").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("
").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})})(jQuery);(function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=h(),n=s._rgba=[];return i=i.toLowerCase(),f(l,function(t,a){var o,r=a.re.exec(i),l=r&&a.parse(r),h=a.space||"rgba";return l?(o=s[h](l),s[c[h].cache]=o[c[h].cache],n=s._rgba=o._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,a.transparent),s):a[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,l=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],h=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=h.support={},p=t("
")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),h.fn=t.extend(h.prototype,{parse:function(n,o,r,l){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(o),o=e);var u=this,d=t.type(n),p=this._rgba=[];return o!==e&&(n=[n,o,r,l],d="array"),"string"===d?this.parse(s(n)||a._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof h?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var a=s.cache;f(s.props,function(t,e){if(!u[a]&&s.to){if("alpha"===t||null==n[t])return;u[a]=s.to(u._rgba)}u[a][e.idx]=i(n[t],e,!0)}),u[a]&&0>t.inArray(null,u[a].slice(0,3))&&(u[a][3]=1,s.from&&(u._rgba=s.from(u[a])))}),this):e},is:function(t){var i=h(t),s=!0,n=this;return f(c,function(t,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=h(t),n=s._space(),a=c[n],o=0===this.alpha()?h("transparent"):this,r=o[a.cache]||a.to(o._rgba),l=r.slice();return s=s[a.cache],f(a.props,function(t,n){var a=n.idx,o=r[a],h=s[a],c=u[n.type]||{};null!==h&&(null===o?l[a]=h:(c.mod&&(h-o>c.mod/2?o+=c.mod:o-h>c.mod/2&&(o-=c.mod)),l[a]=i((h-o)*e+o,n)))}),this[n](l)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=h(e)._rgba;return h(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),h.fn.parse.prototype=h.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,a=t[2]/255,o=t[3],r=Math.max(s,n,a),l=Math.min(s,n,a),h=r-l,c=r+l,u=.5*c;return e=l===r?0:s===r?60*(n-a)/h+360:n===r?60*(a-s)/h+120:60*(s-n)/h+240,i=0===h?0:.5>=u?h/c:h/(2-c),[Math.round(e)%360,i,u,null==o?1:o]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],a=t[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,e+1/3)),Math.round(255*n(r,o,e)),Math.round(255*n(r,o,e-1/3)),a]},f(c,function(s,n){var a=n.props,o=n.cache,l=n.to,c=n.from;h.fn[s]=function(s){if(l&&!this[o]&&(this[o]=l(this._rgba)),s===e)return this[o].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[o].slice();return f(a,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=h(c(d)),n[o]=d,n):h(d)},f(a,function(e,i){h.fn[e]||(h.fn[e]=function(n){var a,o=t.type(n),l="alpha"===e?this._hsla?"hsla":"rgba":s,h=this[l](),c=h[i.idx];return"undefined"===o?c:("function"===o&&(n=n.call(this,c),o=t.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=c+parseFloat(a[2])*("+"===a[1]?1:-1))),h[i.idx]=n,this[l](h)))})})}),h.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var a,o,r="";if("transparent"!==n&&("string"!==t.type(n)||(a=s(n)))){if(n=h(a||n),!d.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&o&&o.style;)try{r=t.css(o,"backgroundColor"),o=o.parentNode}catch(l){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(l){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=h(e.elem,i),e.end=h(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},h.hook(o),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},a=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function s(e,i){var s,n,o={};for(s in i)n=i[s],e[s]!==n&&(a[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(o[s]=n));return o}var n=["add","remove","toggle"],a={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,a,o,r){var l=t.speed(a,o,r);return this.queue(function(){var a,o=t(this),r=o.attr("class")||"",h=l.children?o.find("*").addBack():o;h=h.map(function(){var e=t(this);return{el:e,start:i(this)}}),a=function(){t.each(n,function(t,i){e[i]&&o[i+"Class"](e[i])})},a(),h=h.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),o.attr("class",r),h=h.map(function(){var e=this,i=t.Deferred(),s=t.extend({},l,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,h.get()).done(function(){a(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),l.complete.call(o[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,a){return s?t.effects.animateClass.call(this,{add:i},s,n,a):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,a){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,a):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,a,o,r){return"boolean"==typeof n||n===e?a?t.effects.animateClass.call(this,n?{add:s}:{remove:s},a,o,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,a,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,a){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,a)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.4",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,a;for(a=0;s.length>a;a++)null!==s[a]&&(n=t.data(i+s[a]),n===e&&(n=""),t.css(s[a],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("
").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return e.wrap(s),(e[0]===a||t.contains(e[0],a))&&t(a).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var a=e.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(a)&&a.call(n[0]),t.isFunction(e)&&e()}var n=t(this),a=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):o.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,a=i.queue,o=t.effects.effect[i.effect];return t.fx.off||!o?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):a===!1?this.each(e):this.queue(a||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()})(jQuery);(function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var a,o,r,l=t(this),h=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(l,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",g=i.test(u),m={},v="show"===c;l.parent().is(".ui-effects-wrapper")?t.effects.save(l.parent(),h):t.effects.save(l,h),l.show(),a=t.effects.createWrapper(l).css({overflow:"hidden"}),o=a[p](),r=parseFloat(a.css(f))||0,m[p]=v?o:0,g||(l.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),m[f]=v?r:o+r),v&&(a.css(p,0),g||a.css(f,r+o)),a.animate(m,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&l.hide(),t.effects.restore(l,h),t.effects.removeWrapper(l),n()}})}})(jQuery);(function(t){t.effects.effect.bounce=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],l=t.effects.setMode(o,e.mode||"effect"),h="hide"===l,c="show"===l,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||h?1:0),g=e.duration/f,m=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=o.queue(),y=b.length;for((c||h)&&r.push("opacity"),t.effects.save(o,r),o.show(),t.effects.createWrapper(o),d||(d=o["top"===v?"outerHeight":"outerWidth"]()/3),c&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,_?2*-d:2*d).animate(a,g,m)),h&&(d/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,o.animate(n,g,m).animate(a,g,m),d=h?2*d:d/2;h&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,o.animate(n,g,m)),o.queue(function(){h&&o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),o.dequeue()}})(jQuery);(function(t){t.effects.effect.clip=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],l=t.effects.setMode(o,e.mode||"hide"),h="show"===l,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(o,r),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[d](),h&&(n.css(d,0),n.css(p,a/2)),f[d]=h?a:0,f[p]=h?0:a/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){h||o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}})}})(jQuery);(function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","opacity","height","width"],o=t.effects.setMode(n,e.mode||"hide"),r="show"===o,l=e.direction||"left",h="up"===l||"down"===l?"top":"left",c="up"===l||"left"===l?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,a),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(h,"pos"===c?-s:s),u[h]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery);(function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),g||p.hide(),i()}var a,o,r,l,h,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),g="show"===f,m=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(a=0;u>a;a++)for(l=m.top+a*_,c=a-(u-1)/2,o=0;d>o;o++)r=m.left+o*v,h=o-(d-1)/2,p.clone().appendTo("body").wrap("
").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(g?h*v:0),top:l+(g?c*_:0),opacity:g?0:1}).animate({left:r+(g?0:h*v),top:l+(g?0:c*_),opacity:g?1:0},e.duration||500,e.easing,s)}})(jQuery);(function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}})(jQuery);(function(t){t.effects.effect.fold=function(e,i){var s,n,a=t(this),o=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(a,e.mode||"hide"),l="show"===r,h="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=l!==d,f=p?["width","height"]:["height","width"],g=e.duration/2,m={},v={};t.effects.save(a,o),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[h?0:1]),l&&s.css(d?{height:0,width:c}:{height:c,width:0}),m[f[0]]=l?n[0]:c,v[f[1]]=l?n[1]:0,s.animate(m,g,e.easing).animate(v,g,e.easing,function(){h&&a.hide(),t.effects.restore(a,o),t.effects.removeWrapper(a),i()})}})(jQuery);(function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],a=t.effects.setMode(s,e.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(o,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&s.hide(),t.effects.restore(s,n),i()}})}})(jQuery);(function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),a=t.effects.setMode(n,e.mode||"show"),o="show"===a,r="hide"===a,l=o||"hide"===a,h=2*(e.times||5)+(l?1:0),c=e.duration/h,u=0,d=n.queue(),p=d.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;h>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,h+1))),n.dequeue()}})(jQuery);(function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),a="hide"===n,o=parseInt(e.percent,10)||150,r=o/100,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?l:{height:l.height*r,width:l.width*r,outerHeight:l.outerHeight*r,outerWidth:l.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),a=t.effects.setMode(s,e.mode||"effect"),o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===a?0:100),r=e.direction||"both",l=e.origin,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=l||["middle","center"],n.restore=!0),n.from=e.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:h),n.to={height:h.height*c.y,width:h.width*c.x,outerHeight:h.outerHeight*c.y,outerWidth:h.outerWidth*c.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],l=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(o,e.mode||"effect"),f=e.restore||"effect"!==p,g=e.scale||"both",m=e.origin||["middle","center"],v=o.css("position"),_=f?r:l,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===e.mode&&"show"===p?(o.from=e.to||b,o.to=e.from||s):(o.from=e.from||("show"===p?b:s),o.to=e.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===g||"both"===g)&&(a.from.y!==a.to.y&&(_=_.concat(u),o.from=t.effects.setTransition(o,u,a.from.y,o.from),o.to=t.effects.setTransition(o,u,a.to.y,o.to)),a.from.x!==a.to.x&&(_=_.concat(d),o.from=t.effects.setTransition(o,d,a.from.x,o.from),o.to=t.effects.setTransition(o,d,a.to.x,o.to))),("content"===g||"both"===g)&&a.from.y!==a.to.y&&(_=_.concat(c).concat(h),o.from=t.effects.setTransition(o,c,a.from.y,o.from),o.to=t.effects.setTransition(o,c,a.to.y,o.to)),t.effects.save(o,_),o.show(),t.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),m&&(n=t.effects.getBaseline(m,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===g||"both"===g)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),h=r.concat(u).concat(d),o.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,h),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=t.effects.setTransition(i,u,a.from.y,i.from),i.to=t.effects.setTransition(i,u,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=t.effects.setTransition(i,d,a.from.x,i.from),i.to=t.effects.setTransition(i,d,a.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,h)})})),o.animate(o.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),t.effects.restore(o,_),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):t.each(["top","left"],function(t,e){o.css(e,function(e,i){var s=parseInt(i,10),n=t?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(o),i()}})}})(jQuery);(function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","height","width"],o=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",l=e.distance||20,h=e.times||3,c=2*h+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},g={},m={},v=n.queue(),_=v.length;for(t.effects.save(n,a),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+l,g[d]=(p?"+=":"-=")+2*l,m[d]=(p?"-=":"+=")+2*l,n.animate(f,u,e.easing),s=1;h>s;s++)n.animate(g,u,e.easing).animate(m,u,e.easing);n.animate(g,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}})(jQuery);(function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","width","height"],o=t.effects.setMode(n,e.mode||"show"),r="show"===o,l=e.direction||"left",h="up"===l||"down"===l?"top":"left",c="up"===l||"left"===l,u={};t.effects.save(n,a),n.show(),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(h,c?isNaN(s)?"-"+s:-s:s),u[h]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery);(function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),a="fixed"===n.css("position"),o=t("body"),r=a?o.scrollTop():0,l=a?o.scrollLeft():0,h=n.offset(),c={top:h.top-r,left:h.left-l,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("
").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-l,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}})(jQuery);
\ No newline at end of file
diff --git a/web/migrations.php b/web/migrations.php
new file mode 100644
index 0000000..ac9ef3d
--- /dev/null
+++ b/web/migrations.php
@@ -0,0 +1,18 @@
+runMigrations();
\ No newline at end of file
diff --git a/web/system/.htaccess b/web/system/.htaccess
new file mode 100644
index 0000000..14249c5
--- /dev/null
+++ b/web/system/.htaccess
@@ -0,0 +1 @@
+Deny from all
\ No newline at end of file
diff --git a/web/system/engine/.htaccess b/web/system/engine/.htaccess
new file mode 100644
index 0000000..14249c5
--- /dev/null
+++ b/web/system/engine/.htaccess
@@ -0,0 +1 @@
+Deny from all
\ No newline at end of file
diff --git a/web/system/engine/config-default.php b/web/system/engine/config-default.php
new file mode 100644
index 0000000..d91e51a
--- /dev/null
+++ b/web/system/engine/config-default.php
@@ -0,0 +1,15 @@
+config = $config;
+ $this->tpl = $tpl;
+ $this->core = $core;
+ }
+
+ protected function loadRender($template, $parameters=array())
+ {
+ $this->tpl->loadTemplate($template);
+ return $this->tpl->render($parameters);
+ }
+
+}
\ No newline at end of file
diff --git a/web/system/engine/hf_core.php b/web/system/engine/hf_core.php
new file mode 100644
index 0000000..bb42246
--- /dev/null
+++ b/web/system/engine/hf_core.php
@@ -0,0 +1,365 @@
+config = array_merge($config, $newconfig);
+ \vendor\DB\DB::$type = $config["DATABASE_TYPE"];
+ if ($this->config["USE_H20_TPL"])
+ $this->tpl = new \H2o(null, array(
+ "searchpath" => getcwd() . "/application/views/",
+ "cache_dir" => "application/tmp/",
+ 'cache' => 'file'
+ ));
+ set_error_handler("\\system\\engine\\HF_Core::error_handler");
+ //set_exception_handler("\\system\\engine\\HF_Core::exception_handler");
+ if (!$migrations)
+ $this->findController();
+ }
+
+ public static function exception_handler($e) {
+ echo "Hello";
+ }
+
+ public function siteURL()
+ {
+ if (isvarset($this->config["SITE_URL"]))
+ {
+ return $this->config["SITE_URL"];
+ }
+ $path = explode("/", $_SERVER["REQUEST_URI"]);
+ $path = array_filter($path, 'strlen');
+ if (count($path) == 0)
+ {
+ return $_SERVER["HTTP_HOST"] . "/";
+ } else {
+ if (in_array($this->classname, $path))
+ {
+ $newpath = implode("/", array_splice($path, 0, -2));
+ return $_SERVER["HTTP_HOST"] . "/" . $newpath . "/";
+ } else {
+ $newpath = implode("/", $path);
+ return $_SERVER["HTTP_HOST"] . "/" . $newpath . "/";
+ }
+ }
+ }
+
+ private function findController()
+ {
+ try
+ {
+ if (isvarset($_SERVER["PATH_INFO"]))
+ {
+ $request = $_SERVER["PATH_INFO"];
+ //$request = $_SERVER["PHP_SELF"];
+ $splitreq = explode("/", $request);
+ /*$request = "";
+ for($i = 0; $i < count($splitreq); $i++)
+ {
+ if ($splitreq[$i] == "index.php")
+ {
+ $request = implode("/", array_splice($splitreq, $i+1));
+ }
+ }*/
+ //print $request;
+ //$request = substr($request, 1);
+ //$request = substr($request, 0, -1);
+ } else {
+ $request = "";
+ }
+ if ($request == "" || $request == "/")
+ {
+ require_once("application/controllers/" . $this->config["DEFAULT_ROUTE"] . ".php");
+ $this->loadController(new $this->config["DEFAULT_ROUTE"]($this->config, $this, $this->tpl), $this->config["DEFAULT_ROUTE"], "index");
+ return;
+ }
+ if ($request[strlen($request)-1] == "/")
+ $request = substr($request, 0, -1);
+ $arr = explode("/", $request);
+ $path = "application/controllers/";
+ for($i = 0; $i < count($arr); $i++)
+ {
+ if (is_file($path . $arr[$i] . ".php")) // found the controller
+ {
+ include_once($path . $arr[$i] . ".php");
+ if ($i + 1 < count($arr)) // if there is a define after the controller name - this would be the method name
+ {
+ $this->loadController(new $arr[$i]($this->config, $this, $this->tpl), $arr[$i], $arr[$i+1], array_slice ($arr, 3));
+ } else { // call index
+ $this->loadController(new $arr[$i]($this->config, $this, $this->tpl), $arr[$i], "index");
+ }
+ return;
+ }
+
+ if (is_dir($path . $arr[$i])) // controller is hidden deeper
+ {
+ $path = $path . $arr[$i] . "/";
+ continue;
+ }
+
+ include_once($path . $this->config["DEFAULT_ROUTE"] . ".php");
+ $this->loadController(new $this->config["DEFAULT_ROUTE"]($this->config, $this, $this->tpl), $this->config["DEFAULT_ROUTE"], "index");
+ //$this->load404Controller();
+ break;
+ // throw exception controller not found
+ }
+ } catch (\Exception $e) {
+ if ($this->config["DEBUG"])
+ echo vdump($e, $this);
+ else
+ $this->mail_admins("[Exception - " . $this->config["SITE_NAME"] . "]", vdump($e, $this), true);
+ }
+ }
+
+ private function load404Controller()
+ {
+ if (is_file(getcwd() . "/application/status.php"))
+ {
+ include_once (getcwd() . "/application/status.php");
+ $this->loadController(new HF_Status($this->config, $this, $this->tpl), "\\system\\engine\\HF_Status", "Status404");
+ } else {
+ include_once(getcwd() . "/system/engine/status.php");
+ $this->loadController(new HF_Status($this->config, $this, $this->tpl), "\\system\\engine\\HF_Status", "Status404");
+
+ }
+ }
+
+ private function load500Controller()
+ {
+ if (is_file(getcwd() . "/application/status.php"))
+ {
+ include_once (getcwd() . "/application/status.php");
+ $this->loadController(new HF_Status($this->config, $this, $this->tpl), "\\system\\engine\\HF_Status", "Status500");
+ } else {
+ include_once (getcwd() . "/system/engine/status.php");
+ $this->loadController(new HF_Status($this->config, $this, $this->tpl), "\\system\\engine\\HF_Status", "Status500");
+
+ }
+ }
+
+ private function loadController($class, $classname, $method, $args = array())
+ {
+ $this->class = $class;
+ $this->classname = $classname;
+ $this->method = $method;
+ $this->args = $args;
+ }
+
+ public function run($err=false)
+ {
+ try
+ {
+ $call = new \ReflectionMethod($this->classname, $this->method);
+ if ($err)
+ {
+ $call->invokeArgs($this->class, $this->args);
+ return;
+ }
+
+ $numOfReqPara = $call->getNumberOfRequiredParameters();
+ $numOfOptPara = $call->getNumberOfParameters() - $numOfReqPara;
+ $remainparas = count($this->args) - $numOfReqPara;
+ if ($numOfReqPara == 0 || ($remainparas >= 0 && $remainparas <= $numOfOptPara))
+ {
+ $call->invokeArgs($this->class, $this->args);
+ }
+ else
+ {
+ $this->load404Controller();
+ $this->run(true);
+ }
+
+ }
+ catch (\ReflectionException $e)
+ {
+ if (strstr($e->getMessage(), "does not exist") !== false)
+ {
+ $this->load404Controller();
+ } else {
+ $this->load500Controller();
+ }
+ $this->run(true);
+ if ($this->config["DEBUG"])
+ echo vdump($e, $this);
+ else
+ $this->mail_admins("[Exception - " . $this->config["SITE_NAME"] . "]", vdump($e, $this), true);
+
+
+ } catch (\Exception $e) {
+ $this->load500Controller();
+ $this->run(true);
+ if ($this->config["DEBUG"])
+ echo vdump($e, $this);
+ else
+ $this->mail_admins("[Exception - " . $this->config["SITE_NAME"] . "]", vdump($e, $this), true);
+ }
+ }
+
+ public function mail_admins($subject, $msg, $html = false)
+ {
+ if (array_key_exists("ADMINS", $this->config))
+ {
+ foreach($this->config["ADMINS"] as $email)
+ {
+ $this->mail_user($email, $subject, $msg, $html);
+ }
+ }
+ }
+
+ public function mail_user($to, $subject, $msg, $html = false)
+ {
+ if ($this->config["USE_HF_SMTP"])
+ {
+ $smtp = new HF_SMTP($this->config["SMTP_FROM"], $to, $subject, $msg, $this->config["SMTP_SERVER"], $this->config["SMTP_USER"], $this->config["SMTP_PASS"], $this->config["SMTP_PORT"]);
+ $smtp->send($html);
+ } else {
+ require_once "Mail.php";
+ $smtp = null;
+ if ($this->$this->config["SMTP_USER"] && $this->config["SMTP_PASS"])
+ $smtp = Mail::factory('smtp', array(
+ "host" => $this->config["SMTP_SERVER"],
+ "port" => $this->config["SMTP_PORT"],
+ "auth" => true,
+ 'username' => $this->config["SMTP_USER"],
+ 'password' => $this->config["SMTP_PASS"]
+ ));
+ else
+ $smtp = Mail::factory('smtp', array(
+ "host" => $this->config["SMTP_SERVER"],
+ "port" => $this->config["SMTP_PORT"]
+ ));
+ $headers = array ('From' => $this->config["SMTP_FROM"],
+ 'To' => $to,
+ 'Subject' => $subject);
+ $smtp->send($to, $headers, $msg);
+ }
+ }
+
+ public static function error_handler($err_severity, $err_msg, $err_file, $err_line, array $err_context)
+ {
+ if (0 === error_reporting()) { return false;}
+ switch($err_severity)
+ {
+ case E_ERROR: throw new \ErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_WARNING: throw new WarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_PARSE: throw new ParseException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_NOTICE: throw new NoticeException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_CORE_ERROR: throw new CoreErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_CORE_WARNING: throw new CoreWarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_COMPILE_ERROR: throw new CompileErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_COMPILE_WARNING: throw new CoreWarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_USER_ERROR: throw new UserErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_USER_WARNING: throw new UserWarningException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_USER_NOTICE: throw new UserNoticeException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_STRICT: throw new StrictException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_RECOVERABLE_ERROR: throw new RecoverableErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_DEPRECATED: throw new DeprecatedException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ case E_USER_DEPRECATED: throw new UserDeprecatedException ($err_msg, 0, $err_severity, $err_file, $err_line);
+ }
+ }
+
+ public function setupDatabaseConnection() {
+ switch($this->config["DATABASE_TYPE"]) {
+ case "SQLITE":
+ DB::$c = new \PDO("sqlite:" . $this->config["DATABASE_FILE"]);
+ break;
+ case "MySQL":
+ DB::$c = new \PDO(
+ "mysql:dbname={$this->config['MYSQL_DBNAME']};host={$this->config['MYSQL_HOST']}",
+ $this->config['MYSQL_USER'],
+ $this->config['MYSQL_PASS'],
+ array(
+ \PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
+ \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_OBJ,
+ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
+ )
+ );
+ break;
+ }
+ DB::$c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+ }
+
+ public function runMigrations() {
+ global $argv;
+ $this->setupDatabaseConnection();
+ DB::query("CREATE TABLE IF NOT EXISTS migrations (
+ id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
+ migration INTEGER,
+ ran_at DATETIME
+ )");
+ switch ($argv[1]) {
+ case "show":
+ foreach(DB::fetch("SELECT migration, ran_at FROM migrations") as $migration) {
+ echo $migration["migration"] . " => " . $migration["ran_at"] . PHP_EOL;
+ }
+ break;
+ case "count":
+ echo DB::column("SELECT COUNT(id) FROM migrations");
+ break;
+ case "run":
+ $migrations = DB::fetch("SELECT migration FROM migrations");
+ $migrationArray = [];
+ foreach($migrations as $migration) {
+ $migrationArray[] = $migration["migration"];
+ }
+
+ foreach (glob("application/migrations/*.php") as $filename)
+ {
+ if (!in_array($filename, $migrationArray)) {
+ try {
+ include $filename;
+ DB::insert("migrations", ["migration" => $filename, "ran_at" => (new \DateTime())->format("Y-m-d")]);
+ } catch (\Exception $e) {
+ echo "[HF_Core] - Migration error - $e";
+ exit(1);
+ }
+ }
+
+
+ }
+ break;
+ case "clear":
+ DB::query("DELETE FROM migrations");
+ break;
+ case "reset":
+ switch($this->config["DATABASE_TYPE"]) {
+ case "SQLITE":
+ DB::$c = null;
+ unlink($this->config["DATABASE_FILE"]);
+ break;
+ case "MYSQL":
+ DB::query("DROP DATABASE " . $this->config['MYSQL_DBNAME']);
+ DB::query("CREATE DATABASE " . $this->config['MYSQL_DBNAME']);
+ break;
+ }
+ break;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/web/system/engine/hf_model.php b/web/system/engine/hf_model.php
new file mode 100644
index 0000000..58e7634
--- /dev/null
+++ b/web/system/engine/hf_model.php
@@ -0,0 +1,77 @@
+getShortName());
+
+ foreach(DB::getColumns($table) as $column) {
+ if (isset($data[$column])) {
+ $obj->$column = $data[$column];
+ }
+ }
+ return $obj;
+ }
+
+ public function save() {
+ $fieldMap = [];
+ $function = new \ReflectionClass(get_called_class());
+ $table = strtolower($function->getShortName());
+ foreach(DB::getColumns($table) as $column) {
+ $fieldMap[$column] = $this->$column;
+ }
+ if ($fieldMap["id"] == null) {
+ DB::insert($table, $fieldMap);
+ } else {
+ $updateFields = $fieldMap;
+ unset($updateFields["id"]);
+ DB::update($table, $updateFields, $fieldMap["id"]);
+ }
+ }
+
+ public function update($data) {
+ $function = new \ReflectionClass(get_called_class());
+ $table = strtolower($function->getShortName());
+ foreach(DB::getColumns($table) as $column) {
+ if ($column == "id" || strpos($column, "_id") !== false) {
+ continue; // Don't allow to override id
+ }
+ if (isset($data[$column])) {
+ $this->$column = $data[$column];
+ }
+ }
+ return $this;
+ }
+
+ public function delete() {
+ $function = new \ReflectionClass(get_called_class());
+ $table = strtolower($function->getShortName());
+ if ($this->id) {
+ DB::query("DELETE FROM $table WHERE id = " . $this->id);
+ }
+ }
+
+ public function deleteRelated($tables = []) {
+ $function = new \ReflectionClass(get_called_class());
+ $table = strtolower($function->getShortName());
+ foreach($tables as $relatedTable) {
+ DB::query("DELETE FROM $relatedTable WHERE $table" . "_id = " . $this->id);
+ }
+ }
+
+ public static function getByField($field, $value) {
+ $function = new \ReflectionClass(get_called_class());
+ $table = strtolower($function->getShortName());
+ $fields = implode(", ", DB::getColumns($table));
+ return DB::fetchObject("SELECT $fields FROM $table WHERE $field = ?", get_called_class(), [$value]);
+ }
+
+}
\ No newline at end of file
diff --git a/web/system/engine/hf_smtp.php b/web/system/engine/hf_smtp.php
new file mode 100644
index 0000000..2f554f1
--- /dev/null
+++ b/web/system/engine/hf_smtp.php
@@ -0,0 +1,82 @@
+from = $from;
+ $this->to = $to;
+ $this->subject = $subject;
+ $this->msg = $msg;
+ $this->user = $user;
+ $this->password = $password;
+ $this->port = $port;
+ $this->server = $server;
+ }
+
+ public function send($html=false)
+ {
+ $err = null;
+ $errstr = "";
+ $this->smtpserverconn = fsockopen($this->server, $this->port, $err, $errstr, 100);
+ $response = fgets($this->smtpserverconn, 515);
+ if ($response === false)
+ {
+ throw new Exception("Could not connect to SMTP server!");
+ }
+
+ if ($this->user != null && $this->password != null)
+ {
+ $this->sendCommand("AUTH LOGIN");
+ $this->sendCommand(base64_encode($this->user));
+ $this->sendCommand(base64_encode($this->password));
+ }
+
+ $this->sendCommand("HELO " . $_SERVER["SERVER_NAME"]);
+ $this->sendCommand("MAIL FROM: " . $this->from);
+ $this->sendCommand("RCPT TO: " . $this->to);
+ $this->sendCommand("DATA");
+
+ if ($html)
+ {
+ $this->sendCommand("MIME-Version: 1.0", false);
+ $this->sendCommand("Content-type: text/html; charset=iso-8859-1", false);
+ }
+
+ $this->sendCommand("From: " . $this->from, false);
+ $this->sendCommand("To: " . $this->to, false);
+ $this->sendCommand("Subject: " . $this->subject, false);
+
+
+ $this->sendCommand($this->msg, false);
+
+ $this->sendCommand("", false);
+ $this->sendCommand(".", false);
+ $this->sendCommand("QUIT");
+
+ }
+
+ private function sendCommand($command, $return = true)
+ {
+ fputs($this->smtpserverconn, $command . "\r\n");
+ if ($return)
+ return fgets($this->smtpserverconn, 515);
+ else
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/web/system/engine/status.php b/web/system/engine/status.php
new file mode 100644
index 0000000..85d3ce5
--- /dev/null
+++ b/web/system/engine/status.php
@@ -0,0 +1,17 @@
+isIncrementsOfRanges($value)) {
+ return $this->isInIncrementsOfRanges($dateValue, $value);
+ } elseif ($this->isRange($value)) {
+ return $this->isInRange($dateValue, $value);
+ }
+
+ return $value == '*' || $dateValue == $value;
+ }
+
+ /**
+ * Check if a value is a range
+ *
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isRange($value)
+ {
+ return strpos($value, '-') !== false;
+ }
+
+ /**
+ * Check if a value is an increments of ranges
+ *
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isIncrementsOfRanges($value)
+ {
+ return strpos($value, '/') !== false;
+ }
+
+ /**
+ * Test if a value is within a range
+ *
+ * @param string $dateValue Set date value
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isInRange($dateValue, $value)
+ {
+ $parts = array_map('trim', explode('-', $value, 2));
+
+ return $dateValue >= $parts[0] && $dateValue <= $parts[1];
+ }
+
+ /**
+ * Test if a value is within an increments of ranges (offset[-to]/step size)
+ *
+ * @param string $dateValue Set date value
+ * @param string $value Value to test
+ *
+ * @return bool
+ */
+ public function isInIncrementsOfRanges($dateValue, $value)
+ {
+ $parts = array_map('trim', explode('/', $value, 2));
+ $stepSize = isset($parts[1]) ? $parts[1] : 0;
+ if (($parts[0] == '*' || $parts[0] === '0') && 0 !== $stepSize) {
+ return (int) $dateValue % $stepSize == 0;
+ }
+
+ $range = explode('-', $parts[0], 2);
+ $offset = $range[0];
+ $to = isset($range[1]) ? $range[1] : $dateValue;
+ // Ensure that the date value is within the range
+ if ($dateValue < $offset || $dateValue > $to) {
+ return false;
+ }
+
+ if ($dateValue > $offset && 0 === $stepSize) {
+ return false;
+ }
+
+ for ($i = $offset; $i <= $to; $i+= $stepSize) {
+ if ($i == $dateValue) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/web/system/vendor/Cron/CronExpression.php b/web/system/vendor/Cron/CronExpression.php
new file mode 100644
index 0000000..b59662a
--- /dev/null
+++ b/web/system/vendor/Cron/CronExpression.php
@@ -0,0 +1,355 @@
+ '0 0 1 1 *',
+ '@annually' => '0 0 1 1 *',
+ '@monthly' => '0 0 1 * *',
+ '@weekly' => '0 0 * * 0',
+ '@daily' => '0 0 * * *',
+ '@hourly' => '0 * * * *'
+ );
+
+ if (isset($mappings[$expression])) {
+ $expression = $mappings[$expression];
+ }
+
+ return new static($expression, $fieldFactory ?: new FieldFactory());
+ }
+
+ /**
+ * Validate a CronExpression.
+ *
+ * @param string $expression The CRON expression to validate.
+ *
+ * @return bool True if a valid CRON expression was passed. False if not.
+ * @see Cron\CronExpression::factory
+ */
+ public static function isValidExpression($expression)
+ {
+ try {
+ self::factory($expression);
+ } catch (\InvalidArgumentException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Parse a CRON expression
+ *
+ * @param string $expression CRON expression (e.g. '8 * * * *')
+ * @param FieldFactory $fieldFactory Factory to create cron fields
+ */
+ public function __construct($expression, FieldFactory $fieldFactory)
+ {
+ $this->fieldFactory = $fieldFactory;
+ $this->setExpression($expression);
+ }
+
+ /**
+ * Set or change the CRON expression
+ *
+ * @param string $value CRON expression (e.g. 8 * * * *)
+ *
+ * @return CronExpression
+ * @throws \InvalidArgumentException if not a valid CRON expression
+ */
+ public function setExpression($value)
+ {
+ $this->cronParts = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY);
+ if (count($this->cronParts) < 5) {
+ throw new \InvalidArgumentException(
+ $value . ' is not a valid CRON expression'
+ );
+ }
+
+ foreach ($this->cronParts as $position => $part) {
+ $this->setPart($position, $part);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set part of the CRON expression
+ *
+ * @param int $position The position of the CRON expression to set
+ * @param string $value The value to set
+ *
+ * @return CronExpression
+ * @throws \InvalidArgumentException if the value is not valid for the part
+ */
+ public function setPart($position, $value)
+ {
+ if (!$this->fieldFactory->getField($position)->validate($value)) {
+ throw new \InvalidArgumentException(
+ 'Invalid CRON field value ' . $value . ' at position ' . $position
+ );
+ }
+
+ $this->cronParts[$position] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get a next run date relative to the current date or a specific date
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param int $nth Number of matches to skip before returning a
+ * matching next run date. 0, the default, will return the current
+ * date and time if the next run date falls on the current date and
+ * time. Setting this value to 1 will skip the first match and go to
+ * the second match. Setting this value to 2 will skip the first 2
+ * matches and so on.
+ * @param bool $allowCurrentDate Set to TRUE to return the current date if
+ * it matches the cron expression.
+ *
+ * @return \DateTime
+ * @throws \RuntimeException on too many iterations
+ */
+ public function getNextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
+ {
+ return $this->getRunDate($currentTime, $nth, false, $allowCurrentDate);
+ }
+
+ /**
+ * Get a previous run date relative to the current date or a specific date
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param int $nth Number of matches to skip before returning
+ * @param bool $allowCurrentDate Set to TRUE to return the
+ * current date if it matches the cron expression
+ *
+ * @return \DateTime
+ * @throws \RuntimeException on too many iterations
+ * @see Cron\CronExpression::getNextRunDate
+ */
+ public function getPreviousRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false)
+ {
+ return $this->getRunDate($currentTime, $nth, true, $allowCurrentDate);
+ }
+
+ /**
+ * Get multiple run dates starting at the current date or a specific date
+ *
+ * @param int $total Set the total number of dates to calculate
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param bool $invert Set to TRUE to retrieve previous dates
+ * @param bool $allowCurrentDate Set to TRUE to return the
+ * current date if it matches the cron expression
+ *
+ * @return array Returns an array of run dates
+ */
+ public function getMultipleRunDates($total, $currentTime = 'now', $invert = false, $allowCurrentDate = false)
+ {
+ $matches = array();
+ for ($i = 0; $i < max(0, $total); $i++) {
+ try {
+ $matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate);
+ } catch (\RuntimeException $e) {
+ break;
+ }
+ }
+
+ return $matches;
+ }
+
+ /**
+ * Get all or part of the CRON expression
+ *
+ * @param string $part Specify the part to retrieve or NULL to get the full
+ * cron schedule string.
+ *
+ * @return string|null Returns the CRON expression, a part of the
+ * CRON expression, or NULL if the part was specified but not found
+ */
+ public function getExpression($part = null)
+ {
+ if (null === $part) {
+ return implode(' ', $this->cronParts);
+ } elseif (array_key_exists($part, $this->cronParts)) {
+ return $this->cronParts[$part];
+ }
+
+ return null;
+ }
+
+ /**
+ * Helper method to output the full expression.
+ *
+ * @return string Full CRON expression
+ */
+ public function __toString()
+ {
+ return $this->getExpression();
+ }
+
+ /**
+ * Determine if the cron is due to run based on the current date or a
+ * specific date. This method assumes that the current number of
+ * seconds are irrelevant, and should be called once per minute.
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ *
+ * @return bool Returns TRUE if the cron is due to run or FALSE if not
+ */
+ public function isDue($currentTime = 'now')
+ {
+ if ('now' === $currentTime) {
+ $currentDate = date('Y-m-d H:i');
+ $currentTime = strtotime($currentDate);
+ } elseif ($currentTime instanceof \DateTime) {
+ $currentDate = clone $currentTime;
+ // Ensure time in 'current' timezone is used
+ $currentDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
+ $currentDate = $currentDate->format('Y-m-d H:i');
+ $currentTime = strtotime($currentDate);
+ } else {
+ $currentTime = new \DateTime($currentTime);
+ $currentTime->setTime($currentTime->format('H'), $currentTime->format('i'), 0);
+ $currentDate = $currentTime->format('Y-m-d H:i');
+ $currentTime = $currentTime->getTimeStamp();
+ }
+
+ try {
+ return $this->getNextRunDate($currentDate, 0, true)->getTimestamp() == $currentTime;
+ } catch (\Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Get the next or previous run date of the expression relative to a date
+ *
+ * @param string|\DateTime $currentTime Relative calculation date
+ * @param int $nth Number of matches to skip before returning
+ * @param bool $invert Set to TRUE to go backwards in time
+ * @param bool $allowCurrentDate Set to TRUE to return the
+ * current date if it matches the cron expression
+ *
+ * @return \DateTime
+ * @throws \RuntimeException on too many iterations
+ */
+ protected function getRunDate($currentTime = null, $nth = 0, $invert = false, $allowCurrentDate = false)
+ {
+ if ($currentTime instanceof \DateTime) {
+ $currentDate = clone $currentTime;
+ } else {
+ $currentDate = new \DateTime($currentTime ?: 'now');
+ $currentDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
+ }
+
+ $currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0);
+ $nextRun = clone $currentDate;
+ $nth = (int) $nth;
+
+ // We don't have to satisfy * or null fields
+ $parts = array();
+ $fields = array();
+ foreach (self::$order as $position) {
+ $part = $this->getExpression($position);
+ if (null === $part || '*' === $part) {
+ continue;
+ }
+ $parts[$position] = $part;
+ $fields[$position] = $this->fieldFactory->getField($position);
+ }
+
+ // Set a hard limit to bail on an impossible date
+ for ($i = 0; $i < 1000; $i++) {
+
+ foreach ($parts as $position => $part) {
+ $satisfied = false;
+ // Get the field object used to validate this part
+ $field = $fields[$position];
+ // Check if this is singular or a list
+ if (strpos($part, ',') === false) {
+ $satisfied = $field->isSatisfiedBy($nextRun, $part);
+ } else {
+ foreach (array_map('trim', explode(',', $part)) as $listPart) {
+ if ($field->isSatisfiedBy($nextRun, $listPart)) {
+ $satisfied = true;
+ break;
+ }
+ }
+ }
+
+ // If the field is not satisfied, then start over
+ if (!$satisfied) {
+ $field->increment($nextRun, $invert);
+ continue 2;
+ }
+ }
+
+ // Skip this match if needed
+ if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) {
+ $this->fieldFactory->getField(0)->increment($nextRun, $invert);
+ continue;
+ }
+
+ return $nextRun;
+ }
+
+ // @codeCoverageIgnoreStart
+ throw new \RuntimeException('Impossible CRON expression');
+ // @codeCoverageIgnoreEnd
+ }
+}
diff --git a/web/system/vendor/Cron/DayOfMonthField.php b/web/system/vendor/Cron/DayOfMonthField.php
new file mode 100644
index 0000000..86129c9
--- /dev/null
+++ b/web/system/vendor/Cron/DayOfMonthField.php
@@ -0,0 +1,103 @@
+
+ */
+class DayOfMonthField extends AbstractField
+{
+ /**
+ * Get the nearest day of the week for a given day in a month
+ *
+ * @param int $currentYear Current year
+ * @param int $currentMonth Current month
+ * @param int $targetDay Target day of the month
+ *
+ * @return \DateTime Returns the nearest date
+ */
+ private static function getNearestWeekday($currentYear, $currentMonth, $targetDay)
+ {
+ $tday = str_pad($targetDay, 2, '0', STR_PAD_LEFT);
+ $target = \DateTime::createFromFormat('Y-m-d', "$currentYear-$currentMonth-$tday");
+ $currentWeekday = (int) $target->format('N');
+
+ if ($currentWeekday < 6) {
+ return $target;
+ }
+
+ $lastDayOfMonth = $target->format('t');
+
+ foreach (array(-1, 1, -2, 2) as $i) {
+ $adjusted = $targetDay + $i;
+ if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) {
+ $target->setDate($currentYear, $currentMonth, $adjusted);
+ if ($target->format('N') < 6 && $target->format('m') == $currentMonth) {
+ return $target;
+ }
+ }
+ }
+ }
+
+ public function isSatisfiedBy(\DateTime $date, $value)
+ {
+ // ? states that the field value is to be skipped
+ if ($value == '?') {
+ return true;
+ }
+
+ $fieldValue = $date->format('d');
+
+ // Check to see if this is the last day of the month
+ if ($value == 'L') {
+ return $fieldValue == $date->format('t');
+ }
+
+ // Check to see if this is the nearest weekday to a particular value
+ if (strpos($value, 'W')) {
+ // Parse the target day
+ $targetDay = substr($value, 0, strpos($value, 'W'));
+ // Find out if the current day is the nearest day of the week
+ return $date->format('j') == self::getNearestWeekday(
+ $date->format('Y'),
+ $date->format('m'),
+ $targetDay
+ )->format('j');
+ }
+
+ return $this->isSatisfied($date->format('d'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('previous day');
+ $date->setTime(23, 59);
+ } else {
+ $date->modify('next day');
+ $date->setTime(0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-\?LW0-9A-Za-z]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/DayOfWeekField.php b/web/system/vendor/Cron/DayOfWeekField.php
new file mode 100644
index 0000000..8e33b19
--- /dev/null
+++ b/web/system/vendor/Cron/DayOfWeekField.php
@@ -0,0 +1,134 @@
+convertLiterals($value);
+
+ $currentYear = $date->format('Y');
+ $currentMonth = $date->format('m');
+ $lastDayOfMonth = $date->format('t');
+
+ // Find out if this is the last specific weekday of the month
+ if (strpos($value, 'L')) {
+ $weekday = str_replace('7', '0', substr($value, 0, strpos($value, 'L')));
+ $tdate = clone $date;
+ $tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth);
+ while ($tdate->format('w') != $weekday) {
+ $tdate->setDate($currentYear, $currentMonth, --$lastDayOfMonth);
+ }
+
+ return $date->format('j') == $lastDayOfMonth;
+ }
+
+ // Handle # hash tokens
+ if (strpos($value, '#')) {
+ list($weekday, $nth) = explode('#', $value);
+
+ // 0 and 7 are both Sunday, however 7 matches date('N') format ISO-8601
+ if ($weekday === '0') {
+ $weekday = 7;
+ }
+
+ // Validate the hash fields
+ if ($weekday < 0 || $weekday > 7) {
+ throw new \InvalidArgumentException("Weekday must be a value between 0 and 7. {$weekday} given");
+ }
+ if ($nth > 5) {
+ throw new \InvalidArgumentException('There are never more than 5 of a given weekday in a month');
+ }
+ // The current weekday must match the targeted weekday to proceed
+ if ($date->format('N') != $weekday) {
+ return false;
+ }
+
+ $tdate = clone $date;
+ $tdate->setDate($currentYear, $currentMonth, 1);
+ $dayCount = 0;
+ $currentDay = 1;
+ while ($currentDay < $lastDayOfMonth + 1) {
+ if ($tdate->format('N') == $weekday) {
+ if (++$dayCount >= $nth) {
+ break;
+ }
+ }
+ $tdate->setDate($currentYear, $currentMonth, ++$currentDay);
+ }
+
+ return $date->format('j') == $currentDay;
+ }
+
+ // Handle day of the week values
+ if (strpos($value, '-')) {
+ $parts = explode('-', $value);
+ if ($parts[0] == '7') {
+ $parts[0] = '0';
+ } elseif ($parts[1] == '0') {
+ $parts[1] = '7';
+ }
+ $value = implode('-', $parts);
+ }
+
+ // Test to see which Sunday to use -- 0 == 7 == Sunday
+ $format = in_array(7, str_split($value)) ? 'N' : 'w';
+ $fieldValue = $date->format($format);
+
+ return $this->isSatisfied($fieldValue, $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('-1 day');
+ $date->setTime(23, 59, 0);
+ } else {
+ $date->modify('+1 day');
+ $date->setTime(0, 0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ $value = $this->convertLiterals($value);
+
+ foreach (explode(',', $value) as $expr) {
+ if (!preg_match('/^(\*|[0-7](L?|#[1-5]))([\/\,\-][0-7]+)*$/', $expr)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private function convertLiterals($string)
+ {
+ return str_ireplace(
+ array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'),
+ range(0, 6),
+ $string
+ );
+ }
+}
diff --git a/web/system/vendor/Cron/FieldFactory.php b/web/system/vendor/Cron/FieldFactory.php
new file mode 100644
index 0000000..5aa86f6
--- /dev/null
+++ b/web/system/vendor/Cron/FieldFactory.php
@@ -0,0 +1,55 @@
+fields[$position])) {
+ switch ($position) {
+ case 0:
+ $this->fields[$position] = new MinutesField();
+ break;
+ case 1:
+ $this->fields[$position] = new HoursField();
+ break;
+ case 2:
+ $this->fields[$position] = new DayOfMonthField();
+ break;
+ case 3:
+ $this->fields[$position] = new MonthField();
+ break;
+ case 4:
+ $this->fields[$position] = new DayOfWeekField();
+ break;
+ case 5:
+ $this->fields[$position] = new YearField();
+ break;
+ default:
+ throw new \InvalidArgumentException(
+ $position . ' is not a valid position'
+ );
+ }
+ }
+
+ return $this->fields[$position];
+ }
+}
diff --git a/web/system/vendor/Cron/FieldInterface.php b/web/system/vendor/Cron/FieldInterface.php
new file mode 100644
index 0000000..3823fbf
--- /dev/null
+++ b/web/system/vendor/Cron/FieldInterface.php
@@ -0,0 +1,39 @@
+isSatisfied($date->format('H'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ // Change timezone to UTC temporarily. This will
+ // allow us to go back or forwards and hour even
+ // if DST will be changed between the hours.
+ $timezone = $date->getTimezone();
+ $localMinutes = $date->format('i');
+ $date->setTimezone(new \DateTimeZone('UTC'));
+ // handle timezones with non-hour-offsets
+ $utcMinutes = $date->format('i');
+ $minDiff = $localMinutes - $utcMinutes;
+ if ($invert) {
+ $date->modify('-1 hour');
+ $date->setTime($date->format('H'), 59 - $minDiff);
+ } else {
+ $date->modify('+1 hour');
+ $date->setTime($date->format('H'), 0 - $minDiff);
+ }
+ $date->setTimezone($timezone);
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/LICENSE b/web/system/vendor/Cron/LICENSE
new file mode 100644
index 0000000..c6d88ac
--- /dev/null
+++ b/web/system/vendor/Cron/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011 Michael Dowling
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.
diff --git a/web/system/vendor/Cron/MinutesField.php b/web/system/vendor/Cron/MinutesField.php
new file mode 100644
index 0000000..cfa2b09
--- /dev/null
+++ b/web/system/vendor/Cron/MinutesField.php
@@ -0,0 +1,30 @@
+isSatisfied($date->format('i'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('-1 minute');
+ } else {
+ $date->modify('+1 minute');
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/MonthField.php b/web/system/vendor/Cron/MonthField.php
new file mode 100644
index 0000000..0205c17
--- /dev/null
+++ b/web/system/vendor/Cron/MonthField.php
@@ -0,0 +1,44 @@
+isSatisfied($date->format('m'), $value);
+ }
+
+ public function increment(DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('last day of previous month');
+ $date->setTime(23, 59);
+ } else {
+ $date->modify('first day of next month');
+ $date->setTime(0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9A-Z]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/Cron/YearField.php b/web/system/vendor/Cron/YearField.php
new file mode 100644
index 0000000..b526dde
--- /dev/null
+++ b/web/system/vendor/Cron/YearField.php
@@ -0,0 +1,34 @@
+isSatisfied($date->format('Y'), $value);
+ }
+
+ public function increment(\DateTime $date, $invert = false)
+ {
+ if ($invert) {
+ $date->modify('-1 year');
+ $date->setDate($date->format('Y'), 12, 31);
+ $date->setTime(23, 59, 0);
+ } else {
+ $date->modify('+1 year');
+ $date->setDate($date->format('Y'), 1, 1);
+ $date->setTime(0, 0, 0);
+ }
+
+ return $this;
+ }
+
+ public function validate($value)
+ {
+ return (bool) preg_match('/^[\*,\/\-0-9]+$/', $value);
+ }
+}
diff --git a/web/system/vendor/DB.php b/web/system/vendor/DB.php
new file mode 100644
index 0000000..dfb343a
--- /dev/null
+++ b/web/system/vendor/DB.php
@@ -0,0 +1,165 @@
+
+ ********************************** 80 Columns *********************************
+ */
+
+namespace vendor\DB;
+
+class DB
+{
+ static $q,$c,$p,$i = '`';
+
+ static $type = "";
+
+ /**
+ * Fetch a column offset from the result set (COUNT() queries)
+ *
+ * @param string $query query string
+ * @param array $params query parameters
+ * @param integer $key index of column offset
+ * @return array|null
+ */
+ static function column($query, $params = NULL, $key = 0)
+ {
+ if($statement = DB::query($query, $params))
+ return $statement->fetchColumn($key);
+ }
+
+ /**
+ * Fetch a single query result row
+ *
+ * @param string $query query string
+ * @param array $params query parameters
+ * @return mixed
+ */
+ static function row($query, $params = NULL)
+ {
+ if($statement = DB::query($query, $params))
+ return $statement->fetch();
+ }
+
+ /**
+ * Fetches an associative array of all rows as key-value pairs (first
+ * column is the key, second column is the value).
+ *
+ * @param string $query query string
+ * @param array $params query parameters
+ * @return array
+ */
+ static function pairs($query, $params = NULL)
+ {
+ $data = array();
+
+ if($statement = DB::query($query, $params))
+ while($row = $statement->fetch(\PDO::FETCH_NUM))
+ $data[$row[0]] = $row[1];
+
+ return $data;
+ }
+
+ /**
+ * Fetch all query result rows
+ *
+ * @param string $query query string
+ * @param array $params query parameters
+ * @param int $column the optional column to return
+ * @return array
+ */
+ static function fetch($query, $params = NULL, $column = NULL)
+ {
+ if( ! $statement = DB::query($query, $params)) return;
+
+ // Return an array of records
+ if($column === NULL) return $statement->fetchAll();
+
+ // Fetch a certain column from all rows
+ return $statement->fetchAll(\PDO::FETCH_COLUMN, $column);
+ }
+
+ /**
+ * Fetch all query result rows as object
+ *
+ * @param string $query query string
+ * @param array $params query parameters
+ * @return array
+ */
+ static function fetchObject($query, $className, $params = NULL)
+ {
+ /** @var \PDOStatement $statement */
+ if( ! $statement = DB::query($query, $params)) return null;
+
+ return $statement->fetchAll(\PDO::FETCH_CLASS, $className);
+ }
+
+ /**
+ * Prepare and send a query returning the PDOStatement
+ *
+ * @param string $query query string
+ * @param array $params query parameters
+ * @return object|null
+ */
+ static function query($query, $params = NULL)
+ {
+ $statement = static::$c->prepare(DB::$q[] = strtr($query, '`', DB::$i));
+ $statement->execute($params);
+ return $statement;
+ }
+
+ /**
+ * Insert a row into the database
+ *
+ * @param string $table name
+ * @param array $data
+ * @return integer|null
+ */
+ static function insert($table, array $data)
+ {
+ $query = "INSERT INTO`$table`(`" . implode('`,`', array_keys($data))
+ . '`)VALUES(' . rtrim(str_repeat('?,', count($data = array_values($data))), ',') . ')';
+ return DB::$p
+ ? DB::column($query . 'RETURNING`id`', $data)
+ : (DB::query($query, $data) ? static::$c->lastInsertId() : NULL);
+ }
+
+ /**
+ * Update a database row
+ *
+ * @param string $table name
+ * @param array $data
+ * @param array $w where conditions
+ * @return integer|null
+ */
+ static function update($table, $data, $value, $column = 'id')
+ {
+ $keys = implode('`=?,`', array_keys($data));
+ if($statement = DB::query(
+ "UPDATE`$table`SET`$keys`=? WHERE`$column`=?",
+ array_values($data + array($value))
+ ))
+ return $statement->rowCount();
+ }
+
+ /**
+ * Returns array containing all field names
+ * @param $table
+ * @return array
+ */
+ static function getColumns($table) {
+ switch (self::$type) {
+ case "SQLITE":
+ return self::fetch("PRAGMA table_info($table)", null, 1);
+ break;
+ case "MySQL":
+ return self::fetch("DESC $table", null, 0);
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/web/system/vendor/README.md b/web/system/vendor/README.md
new file mode 100644
index 0000000..74e50fa
--- /dev/null
+++ b/web/system/vendor/README.md
@@ -0,0 +1,453 @@
+H2O template markup
+========================
+Being a martial arts fan, I borrow a quote.
+
+
+
+H2O template
+------------------------
+H2O is markup language for PHP that has taken a lot of inspiration from Django.
+
+
+__Features__
+ * Readable and human-friendly syntax.
+ * Easy to use and maintain
+ * Encourages reuse in templates by allowing template inclusion and inheritance.
+ * Highly extensible through filters, tags, and template extensions.
+ * Includes a rich set of filters and tags for string formatting, HTML helpers and
+ internationalization support.
+
+
+Requirement
+------------------------
+
+ - PHP 5.1 +
+
+
+News
+------------------------
+
+ - version 0.4
+ 1. **Breaking changes** autoescape is now turned on by default
+ 2. Improved searchpath and file loading handling
+ 3. Improved handling on PHP overloaded objects
+ 4. Plenty of bug fixes
+ - version 0.3
+ 1. Support internationalized templates and translation parsing toolkit
+ 2. Performance optimization on context lookup
+ 3. Fixed operator parsing
+
+Getting started
+------------------------
+
+### Getting h2o
+
+Download
+
+[](http://code.google.com/p/h2o-template/downloads)
+
+With Git
+
+`git clone http://github.com/speedmax/h2o-php.git`
+
+With SVN
+
+`svn checkout http://h2o-template.googlecode.com/svn/trunk/ h2o`
+
+### Installation
+ 1. Download and extract h2o into your project path or your php include path
+
+ Sample file structure setup
+
+ myawesome_app/
+ index.php
+ templates/
+ index.html
+ h2o/
+
+
+ 2. Use `require 'h2o/h2o.php'` in your php files to include the h2o library.
+ 3. Below is a basic code sample to get your project going.
+ 3. Check out the *\example* and *\specs* dirs to see some of h2o's more interesting features in action.
+
+*templates/index.html*
+
+
+ Hello world
+
+ Greetings {{ name }}
+
+
+
+*index.php*
+
+ render(array('name'=>'Peter Jackson'));
+ ?>
+
+
+Useful links
+------------------------
+
+ * Please submit patches or bug reports to our [lighthouse bug tracker][issue].
+ * Check out our [Google group][group] for h2o-related discussion.
+
+ [issue]:http://idealian.lighthouseapp.com/projects/11041-h2o-template-language
+ [group]:http://groups.google.com/group/h2o-template-php
+
+
+Syntax explanation
+------------------------
+
+## variable
+`{{ variable }}`
+
+Use dot (.) to access attributes of a variable
+
+#### variable lookup order
+1. key of an associative array
+2. array-index
+3. object attribute
+4. object method call
+
+**Example**
+
+*in your template*
+
+ {{ person.name }}
+
+*in php*
+
+ 'Peter Jackson', 'age' => 25
+ );
+ $h2o->render(compact('person'));
+ ?>
+
+Let's say that you have assigned the value `Peter Jackson` to a 'person' variable in your php script. The following
+variable tag will print out `Peter Jackson`.
+
+## Filters
+
+Filters are variable modifiers that manipulate or format the value of a variable.
+A filter usually looks like this `{{ person.name|capitalize }}`, a pipe ( | )
+character after a variable, plus a filter name, will cause H2O to apply the filter.
+
+__Filter chaining__
+
+![filter chaining](http://wiki.shopify.com/upload/8/8c/Filterchain.jpg)
+Let me borrow the image from liquid template
+
+You can chain multiple filters together and use a pipe ( | ) character to separate
+them. `{{ document.body|escape|nl2br }}`
+
+__Filter arguments__
+Filters can accept arguments. For example:
+`{{ document.description|truncate 20 }}`
+will display the first 20 characters of the document's description.
+
+Moreover, there are cases where you might want to pass in multiple arguments.
+Use commas ( , ) to separate them:
+`{{ person.bio|truncate 20, "..." }}`
+
+__Filter named arguments__
+h2o uses colons ( : ) for named arguments. These allow you to build 'optional argument' arrays.
+
+`{{ '/images/logo.png' | image_tag width:450, height:250, alt:"company logo" }}`
+
+The above code translated to php will be like the below snippet, which resembles what happens internally:
+
+ 450,
+ 'height' => 250,
+ 'alt'=>'company logo'
+ ));
+ ?>
+
+Note: Difference with Django, Smarty
+H2o does not use the colon ( : ) character to separate arguments for readability reasons,
+H2o uses the comma ( , ) which is more logical.
+
+
+## Tag
+
+`{% tag %}`
+
+Tags are very powerful, as they control the logical flow and structure of a template,
+There are inline tags `{% inline_tag %}` or tags that requires a
+close tag. For example: `{% if condition %} ... {% endif %}`
+
+
+### The "if" tag
+
+`if` tags evaluate either a variable or a simple expression. If the result of the `if`
+expression is *true*, then the contents of the `if` block will be allowed to render.
+
+ {% if person.is_adult %}
+ You are old enough.
+ {% else %}
+ sorry, you are too young for that.
+ {% endif %}
+
+### The "for" tag
+
+`for` tags allow iteratation over an array of items.
+
+ {% for task in tasks %}
+ {{ task }}
+ {% endfor %}
+
+The above snippet will print out each "task" in the "tasks" array.
+
+Template inheritance
+------------------------
+H2o supports template inheritance. Inheritance allows you to factor out a lot
+of common code that would otherwise be duplicated across most of your templates.
+
+Template inheritance is implemented using the `block` and `extends` tags, with child templates
+*extending* their parent templates.
+**Word of Caution:**
+ * H2o templates only support single inheritance (just like PHP!), and currently do not support deep inheritance chains.
+
+
+Quote from the Django docs:
+> ... a base skeleton template that contains all the common elements of your
+> site and defines blocks that child templates can override.
+
+
+*Example:*
+
+_base.html_ - defines the base structure of our pages.
+
+
+ {%block title %}This is a page title {% endblock %}
+
+
+ {% block content%}
+
Page title
+
H2O template inheritance is a powerful tool
+ {% endblock %}
+
+
+
+
+
+
+As you can see, the base template is a typical web page using a two column layout.
+We defined two blocks (`content` and `sidebar`) and HTML code common across all of our pages.
+
+
+_page.html_ - defines a page-specific template.
+
+ {% extends 'base.html' %}
+
+ {% block content %}
+ extended page
+ Body of extended page
+ {% endblock %}
+
+ {% block sidebar %}
+ Sidebar contains use links.
+ {% endblock %}
+
+
+The `page.html` extends `base.html`, allowing us to override any block
+previously defined in `base.html`.
+
+Below is an excellent article about template inheritance in Django. If you wish to understand H2o's
+template-inheritance system, this would be a great spot to start, since H2o's template-inheritance system
+is strongly influenced by Django's.
+
+[Power of inheritance][3] is a very good blog post explaining inheritance
+
+ [3]:http://www2.jeffcroft.com/blog/2006/feb/25/django-templates-the-power-of-inheritance/
+
+*Tips*
+
+* If you have found that you have several common elements inside the same template, it may be a
+ good idea to put that portion of the template inside a `block` in a base template.
+* `block` give you a hook, which is useful, since these can help with javascript and css too.
+* When defining a block use a short and distinctive name
+
+
+
+### Configuration
+There are a range of options for configuring the template engine.
+
+ [option_value]
+ ));
+ ?>
+
+#### Loader
+The name of the loader or an instance of H2o_Loader
+
+__Use file loader [default]__
+
+` $template = new H2o('index.html', array('loader'=>'file'); `
+
+
+__Advanced setup__
+ $loader );
+ ?>
+
+__Use dictionary loader__
+
+If you want to load templates from resources other than files, then this will be your
+friend. H2o uses `dict_loader()` for testing.
+
+ 'Hello {{ person }}'
+ ));
+ $template = new H2o('index.html', array('loader' => $loader'));
+ ?>
+
+#### Searchpath
+
+default: this will be the base path of your template
+
+H2o use this path to load additional templates and extensions.
+
+You can either explicity set the search path,
+
+`$template = new H2o('index.html', array('searchpath' => '/sites/common_templates'));`
+
+or h2o will try to find the searchpath for you.
+
+`$template = new H2o('/sites/common_templates/index.html');`
+
+#### Cache
+You can define the type of caching engine h2o should use, if any.
+Set 'cache' to false to disable caching.
+You can read more about performance and caching in following sections
+
+Use file cache [default]
+
+`$template = new H2o('index.html', array('cache'=>'file'));`
+
+Use apc cache:
+
+`$template = new H2o('index.html', array('cache'=>'apc'));`
+
+Use memcache cache
+
+`$template = new H2o('index.html', array('cache'=>'memcache'));`
+
+Disable caching
+
+`$template = new H2o('index.html', array('cache'=>false));`
+
+#### Cache_dir
+When the file cache is used, you can define where you want templates to be cached.
+
+It will put a cached template in same location as the normal template
+
+`$template = new H2o('index.html', array('cache_dir'=>'/tmp/cached_templates'));`
+
+#### Cache_ttl
+"cache_ttl" specifies how long a cached template should be used (defaults: 1 hour) before it is recompiled. The template fragment cache
+that is bundled in the cache extension will use this as default ttl value.
+
+`$template = new H2o('index.html', array('cache_ttl' => 3600));`
+
+
+Performance and Caching
+------------------------
+
+Caching can increase performance since it skips step of inefficient template parsing.
+H2o caches the template objects (the internal data structure of a template) and the bundled
+caching backends include File, APC, and Memcache.
+
+### File cache
+By default h2o uses the file cache to store template objects. Change h2o option `cache_dir` to where you
+want to store template cache (ie: /tmp).
+
+ 'file',
+ 'cache_dir' => '/tmp'
+ ));
+ ?>
+
+### APC cache
+APC is an op-code and object cache extension for php whose performance is
+generally 10-30% better than just plain file caching.
+
+ 'apc'));
+ ?>
+
+### Memcache
+Currently not implemented
+
+
+Extending H2o
+------------------------
+
+
+Known issues
+------------------------
+Yes, h2o has them. However, if you are careful, these shouldn't hinder your template development.
+The deep inheritance issue is a bit problematic for some template architectures, but again, if you
+are careful, and perhaps a bit inventive, it won't hinder you terribly much.
+
+ * `{{ block.super }}` doesn't work with more than 1 level of inheritance yet, so if `{{ block.super }}`
+ invokes another `{{ block.super }}` it won't work just yet.
+ * 'if' conditions don't support multiple expressions or mathematical expressions yet, like:
+ `{% if something > 3 or something < 2 %}` or `{% if something + else > 12 %}`
+ These likely will not be implemented in the future unless some daring soul implements them and
+ contributes the code back to the h2o-php project.
+
+
+Contributors
+---
+ - Taylor Luk - Founder of [Issue publishing](http://issueapp.com)
+ - jlogsdon - Major refactoring (wip) and bug fixes
+ - cyberklin - Added filter support for any context resolve
+ - idlesign - Added if_changed tag support
+ - metropolis - Improved our test coverage
+ - plus many others
+
+
+Credit
+------------------------
+H2o borrows ideas and/or concepts from the following projects:
+
+ - Django template - Django web development framework.
+ - Ptemplates - Armin Ronacher's pet project for a django port in PHP.
+ - Jinja - Django inspired template in Python.
+
+Special Thanks: Armin Ronacher, since early versions of h2o were based off of his Ptemplates project.
+
+The MIT License
+------------------------
+Copyright (c) 2008 Taylor Luk
+
+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.
diff --git a/web/system/vendor/StackTracePrint.php b/web/system/vendor/StackTracePrint.php
new file mode 100644
index 0000000..08d49b5
--- /dev/null
+++ b/web/system/vendor/StackTracePrint.php
@@ -0,0 +1,69 @@
+";
+
+ $ret .= "".htmlspecialchars(trim($code[$backtrace[0]['line']-1]))."\n";
+
+ $ret .= "\n";
+
+ ob_start();
+
+ foreach ($args as $arg)
+ var_dump($arg);
+
+ var_dump($_SERVER);
+ var_dump($_COOKIE);
+
+ $str = ob_get_contents();
+
+ ob_end_clean();
+
+ $str = preg_replace('/=>(\s+)/', ' => ', $str);
+ $str = preg_replace('/ => NULL/', ' → NULL', $str);
+ $str = preg_replace('/}\n(\s+)\[/', "}\n\n".'$1[', $str);
+ $str = preg_replace('/ (float|int)\((\-?[\d\.]+)\)/', " $1 $2", $str);
+
+ $str = preg_replace('/array\((\d+)\) {\s+}\n/', "array•$1 []", $str);
+ $str = preg_replace('/ string\((\d+)\) \"(.*)\"/', " str•$1 '$2'", $str);
+ $str = preg_replace('/\[\"(.+)\"\] => /', "'$1' → ", $str);
+ $str = preg_replace('/object\((\S+)\)#(\d+) \((\d+)\) {/', "obj•$2 $1[$3] {", $str);
+ $str = str_replace("bool(false)", "bool•false", $str);
+ $str = str_replace("bool(true)", "bool•true", $str);
+
+ $ret .= $str;
+
+
+
+ $ret .= "";
+
+ return $ret;
+
+
+
+}
+
+// Original - http://www.php.net/manual/en/function.debug-print-backtrace.php#86932
+function debug_string_backtrace() {
+ ob_start();
+ debug_print_backtrace();
+ $trace = ob_get_contents();
+ ob_end_clean();
+
+ // Remove first item from backtrace as it's this function which
+ // is redundant.
+ $trace = preg_replace ('/^#0\s+' . __FUNCTION__ . "[^\n]*\n/", '', $trace, 1);
+
+ // Renumber backtrace items.
+ $trace = preg_replace ('/^#(\d+)/me', '\'#\' . ($1 - 1)', $trace);
+
+ $trace = wordwrap($trace, 123, "
");
+ return $trace;
+}
\ No newline at end of file
diff --git a/web/system/vendor/aes.php b/web/system/vendor/aes.php
new file mode 100644
index 0000000..f7b6be2
--- /dev/null
+++ b/web/system/vendor/aes.php
@@ -0,0 +1,27 @@
+ 32) {
+ throw new \Exception("Key is too long");
+ } else {
+ $realKey = $key;
+ }
+
+ return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $realKey, $text, MCRYPT_MODE_ECB));
+}
+
+function aes_decrypt($key, $cipherText) {
+ $realKey = "";
+ if (count($key) < 32) { //if it's less than 32 bits - pad it
+ $realKey = str_pad($key, 32 - count($key) + 1);
+ } else if (count($key) > 32) {
+ throw new \Exception("Key is too long");
+ } else {
+ $realKey = $key;
+ }
+ return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $realKey, base64_decode($cipherText), MCRYPT_MODE_ECB);
+}
\ No newline at end of file
diff --git a/web/system/vendor/cron.php b/web/system/vendor/cron.php
new file mode 100644
index 0000000..8cddfb8
--- /dev/null
+++ b/web/system/vendor/cron.php
@@ -0,0 +1,18 @@
+
\ No newline at end of file
diff --git a/web/system/vendor/h2o.php b/web/system/vendor/h2o.php
new file mode 100644
index 0000000..c264b81
--- /dev/null
+++ b/web/system/vendor/h2o.php
@@ -0,0 +1,268 @@
+'file'));
+ *
+ *
+ * $h2o = new H2O('template.html', array("loader"=>'hash'));
+ */
+class H2o {
+ var $searchpath;
+ var $context;
+ var $loader = false;
+
+ static $tags = array();
+ static $filters = array();
+ static $extensions = array();
+
+ static function getOptions($options = array()) {
+ return array_merge(array(
+ 'loader' => 'file',
+ 'cache' => 'file', // file | apc | memcache
+ 'cache_prefix' => 'h2o_',
+ 'cache_ttl' => 3600, // file | apc | memcache
+ 'searchpath' => false,
+ 'autoescape' => true,
+
+ // Enviroment setting
+ 'BLOCK_START' => '{%',
+ 'BLOCK_END' => '%}',
+ 'VARIABLE_START' => '{{',
+ 'VARIABLE_END' => '}}',
+ 'COMMENT_START' => '{*',
+ 'COMMENT_END' => '*}',
+ 'TRIM_TAGS' => true
+ ), $options);
+ }
+
+ function __construct($file = null, $options = array()) {
+ # Init a environment
+ $this->options = $this->getOptions($options);
+ $loader = $this->options['loader'];
+
+ if (!$loader)
+ return true;
+
+ if (is_object($loader)) {
+ $this->loader = $loader;
+ $this->loader->setOptions($this->options);
+ } else {
+ $loader = "H2o_{$loader}_Loader";
+ if (!class_exists($loader, false))
+ throw new Exception('Invalid template loader');
+
+ if (isset($options['searchpath'])){
+ $this->searchpath = $options['searchpath'];
+ } else if ($file) {
+ $this->searchpath = dirname(realpath($file)).DS;
+ } else {
+ $this->searchpath = getcwd().DS;
+ }
+
+ $loader_searchpath = is_array($this->searchpath) ? $this->searchpath : array($this->searchpath);
+ $this->loader = new $loader($loader_searchpath, $this->options);
+ }
+ $this->loader->runtime = $this;
+
+ if (isset($options['i18n'])) {
+ h2o::load('i18n');
+ $this->i18n = new H2o_I18n($this->searchpath, $options['i18n']);
+ }
+
+ if ($file) {
+ $this->nodelist = $this->loadTemplate($file);
+ }
+ }
+
+ function loadTemplate($file) {
+ return $this->nodelist = $this->loader->read_cache($file);
+ }
+
+ function loadSubTemplate($file) {
+ return $this->loader->read($file);
+ }
+
+ # Build a finalized nodelist from template ready to be cached
+ function parse($source, $filename = '', $env = null) {
+ if (!$env)
+ $env = $this->options;
+
+ if (!class_exists('H2o_Parser', false))
+ require H2O_ROOT.'h2o/parser.php';
+
+ $parser = new H2o_Parser($source, $filename, $this, $env);
+ $nodelist = $parser->parse();
+ return $nodelist;
+ }
+
+ function set($context, $value = null) {
+ # replace with new context object
+ if (is_object($context) && $context instanceof H2o_Context) {
+ return $this->context = $context;
+ }
+
+ # Init context
+ if (!$this->context) {
+ $this->context = new H2o_Context($this->defaultContext(), $this->options);
+ }
+
+ # Extend or set value
+ if (is_array($context)) {
+ return $this->context->extend($context);
+ }
+ elseif (is_string($context)) {
+ return $this->context[$context] = $value;
+ }
+ return false;
+ }
+
+ # Render the nodelist
+ function render($context = array()) {
+ $this->set($context);
+
+ $this->stream = new StreamWriter;
+ $this->nodelist->render($this->context, $this->stream);
+ return $this->stream->close();
+ }
+
+ static function parseString($source, $options = array()) {
+ $instance = new H2o(null, array_merge($options, array('loader' => false)));
+ $instance->nodelist = $instance->parse($source);
+ return $instance;
+ }
+
+ static function &createTag($tag, $args = null, $parser, $position = 0) {
+ if (!isset(self::$tags[$tag])) {
+ throw new H2o_Error($tag . " tag doesn't exist");
+ }
+ $tagClass = self::$tags[$tag];
+ $tag = new $tagClass($args, $parser, $position);
+ return $tag;
+ }
+
+ /**
+ * Register a new tag
+ *
+ *
+ * h2o::addTag('tag_name', 'ClassName');
+ *
+ * h2o::addTag(array(
+ * 'tag_name' => 'MagClass',
+ * 'tag_name2' => 'TagClass2'
+ * ));
+ *
+ * h2o::addTag('tag_name'); // Tag_name_Tag
+ *
+ * h2o::addTag(array('tag_name',
+ * @param unknown_type $tag
+ * @param unknown_type $class
+ */
+ static function addTag($tag, $class = null) {
+ $tags = array();
+ if (is_string($tag)) {
+ if (is_null($class))
+ $class = ucwords("{$tag}_Tag");
+ $tags[$tag] = $class;
+ } elseif (is_array($tag)) {
+ $tags = $tag;
+ }
+
+ foreach ($tags as $tag => $tagClass) {
+ if (is_integer($tag)) {
+ unset($tags[$tag]);
+ $tag = $tagClass;
+ $tagClass = ucwords("{$tagClass}_Tag");
+ }
+ if (!class_exists($tagClass, false)) {
+ throw new H2o_Error("{$tagClass} tag is not found");
+ }
+ $tags[$tag] = $tagClass;
+ }
+ self::$tags = array_merge(self::$tags, $tags);
+ }
+
+ /**
+ * Register a new filter to h2o runtime
+ *
+ * @param unknown_type $filter
+ * @param unknown_type $callback
+ * @return unknown
+ */
+ static function addFilter($filter, $callback = null) {
+ if (is_array($filter)) {
+ $filters = $filter;
+ foreach($filters as $key => $filter) {
+ if (is_numeric($key))
+ $key = $filter;
+ self::addFilter($key, $filter);
+ }
+ return true;
+ } elseif (is_string($filter) && class_exists($filter, false) && is_subclass_of($filter, 'FilterCollection')) {
+ foreach (get_class_methods($filter) as $f) {
+ if (is_callable(array($filter, $f)))
+ self::$filters[$f] = array($filter, $f);
+ }
+ return true;
+ }
+ if (is_null($callback))
+ $callback = $filter;
+
+ if (!is_callable($callback)) {
+ return false;
+ }
+ self::$filters[$filter] = $callback;
+ }
+
+ static function addLookup($callback) {
+ if (is_callable($callback)) {
+ H2o_Context::$lookupTable[] = $callback;
+ } else die('damm it');
+ }
+
+ static function load($extension, $file = null) {
+ if (!$file) {
+ $file = H2O_ROOT.'ext'.DS.$extension.'.php';
+ }
+ if (is_file($file)) {
+ include_once ($file);
+ self::$extensions[$extension] = $file;
+ }
+ }
+
+ function defaultContext() {
+ return array('h2o' => new H2o_Info);
+ }
+}
+
+/**
+ * Convenient wrapper for loading template file or string
+ * @param $name
+ * @param $options - H2o options
+ * @return Instance of H2o Template
+ */
+function h2o($name, $options = array()) {
+ $is_file = '/([^\s]*?)(\.[^.\s]*$)/';
+
+ if (!preg_match($is_file, $name)) {
+ return H2o::parseString($name, $options);
+ }
+
+ $instance = new H2o($name, $options);
+ return $instance;
+}
+
+?>
diff --git a/web/system/vendor/h2o/.htaccess b/web/system/vendor/h2o/.htaccess
new file mode 100644
index 0000000..14249c5
--- /dev/null
+++ b/web/system/vendor/h2o/.htaccess
@@ -0,0 +1 @@
+Deny from all
\ No newline at end of file
diff --git a/web/system/vendor/h2o/context.php b/web/system/vendor/h2o/context.php
new file mode 100644
index 0000000..ab09dbc
--- /dev/null
+++ b/web/system/vendor/h2o/context.php
@@ -0,0 +1,266 @@
+ 0, 'last'=> 1, 'length'=> 2, 'size'=> 3);
+ static $lookupTable = array();
+
+ function __construct($context = array(), $options = array()){
+ if (is_object($context))
+ $context = get_object_vars($context);
+ $this->scopes = array($context);
+
+ if (isset($options['safeClass']))
+ $this->safeClass = array_merge($this->safeClass, $options['safeClass']);
+
+ if (isset($options['autoescape']))
+ $this->autoescape = $options['autoescape'];
+
+ $this->options = $options;
+ }
+
+ function push($layer = array()){
+ return array_unshift($this->scopes, $layer);
+ }
+
+ /**
+ * pop the most recent layer
+ */
+ function pop() {
+ if (!isset($this->scopes[1]))
+ throw new Exception('cannnot pop from empty stack');
+ return array_shift($this->scopes);
+ }
+
+ function offsetExists($offset) {
+ foreach ($this->scopes as $layer) {
+ if (isset($layer[$offset])) return true;
+ }
+ return false;
+ }
+
+ function offsetGet($key) {
+ foreach ($this->scopes as $layer) {
+ if (isset($layer[$key]))
+ return $layer[$key];
+ }
+ return;
+ }
+
+ function offsetSet($key, $value) {
+ if (strpos($key, '.') > -1)
+ throw new Exception('cannot set non local variable');
+ return $this->scopes[0][$key] = $value;
+ }
+
+ function offsetUnset($key) {
+ foreach ($this->scopes as $layer) {
+ if (isset($layer[$key])) unset($layer[$key]);
+ }
+ }
+
+ function extend($context) {
+ $this->scopes[0] = array_merge($this->scopes[0], $context);
+ }
+
+ function set($key, $value) {
+ return $this->offsetSet($key, $value);
+ }
+
+ function get($key) {
+ return $this->offsetGet($key);
+ }
+
+ function isDefined($key) {
+ return $this->offsetExists($key);
+ }
+ /**
+ *
+ *
+ *
+ * Variable name
+ *
+ * @param $var variable name or array(0 => variable name, 'filters' => filters array)
+ * @return unknown_type
+ */
+ function resolve($var) {
+
+ # if $var is array - it contains filters to apply
+ $filters = array();
+ if ( is_array($var) ) {
+
+ $name = array_shift($var);
+ $filters = isset($var['filters'])? $var['filters'] : array();
+
+ }
+ else $name = $var;
+
+ $result = null;
+
+ # Lookup basic types, null, boolean, numeric and string
+ # Variable starts with : (:users.name) to short-circuit lookup
+ if ($name[0] === ':') {
+ $object = $this->getVariable(substr($name, 1));
+ if (!is_null($object)) $result = $object;
+ } else {
+ if ($name === 'true') {
+ $result = true;
+ }
+ elseif ($name === 'false') {
+ $result = false;
+ }
+ elseif (preg_match('/^-?\d+(\.\d+)?$/', $name, $matches)) {
+ $result = isset($matches[1])? floatval($name) : intval($name);
+ }
+ elseif (preg_match('/^"([^"\\\\]*(?:\\.[^"\\\\]*)*)"|' .
+ '\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'$/', $name)) {
+ $result = stripcslashes(substr($name, 1, -1));
+ }
+ }
+ if (!empty(self::$lookupTable) && $result == Null) {
+ $result = $this->externalLookup($name);
+ }
+ $result = $this->applyFilters($result,$filters);
+ return $result;
+ }
+
+ function getVariable($name) {
+ # Local variables. this gives as a bit of performance improvement
+ if (!strpos($name, '.'))
+ return $this[$name];
+
+ # Prepare for Big lookup
+ $parts = explode('.', $name);
+ $object = $this[array_shift($parts)];
+
+ # Lookup context
+ foreach ($parts as $part) {
+ if (is_array($object) or $object instanceof ArrayAccess) {
+ if (isset($object[$part])) {
+ $object = $object[$part];
+ } elseif ($part === 'first') {
+ $object = isset($object[0])?$object[0]:null;
+ } elseif ($part === 'last') {
+ $last = count($object)-1;
+ $object = isset($object[$last])?$object[$last]:null;
+ } elseif ($part === 'size' or $part === 'length') {
+ return count($object);
+ } else {
+ return null;
+ }
+ }
+ elseif (is_object($object)) {
+ if (isset($object->$part))
+ $object = $object->$part;
+ elseif (is_callable(array($object, $part))) {
+ $methodAllowed = in_array(get_class($object), $this->safeClass) ||
+ (isset($object->h2o_safe) && (
+ $object->h2o_safe === true || in_array($part, $object->h2o_safe)
+ )
+ );
+ $object = $methodAllowed ? $object->$part() : null;
+ }
+ else return null;
+ }
+ else return null;
+ }
+ return $object;
+ }
+
+ function applyFilters($object, $filters) {
+
+ foreach ($filters as $filter) {
+ $name = substr(array_shift($filter), 1);
+ $args = $filter;
+
+ if (isset(h2o::$filters[$name])) {
+ foreach ($args as $i => $argument) {
+ # name args
+ if (is_array($argument)) {
+ foreach ($argument as $n => $arg) {
+ $args[$i][$n] = $this->resolve($arg);
+ }
+ } else {
+ # resolve argument values
+ $args[$i] = $this->resolve($argument);
+ }
+ }
+ array_unshift($args, $object);
+ $object = call_user_func_array(h2o::$filters[$name], $args);
+ }
+ }
+ return $object;
+ }
+
+ function escape($value, $var) {
+
+ $safe = false;
+ $filters = (is_array($var) && isset($var['filters']))? $var['filters'] : array();
+
+ foreach ( $filters as $filter ) {
+
+ $name = substr(array_shift($filter), 1);
+ $safe = !$safe && ($name === 'safe');
+
+ $escaped = $name === 'escape';
+ }
+
+ $should_escape = $this->autoescape || isset($escaped) && $escaped;
+
+ if ( ($should_escape && !$safe)) {
+ $value = htmlspecialchars($value);
+ }
+
+ return $value;
+ }
+
+ function externalLookup($name) {
+ if (!empty(self::$lookupTable)) {
+ foreach (self::$lookupTable as $lookup) {
+ $tmp = call_user_func_array($lookup, array($name, $this));
+ if ($tmp !== null)
+ return $tmp;
+ }
+ }
+ return null;
+ }
+}
+
+class BlockContext {
+ var $h2o_safe = array('name', 'depth', 'super');
+ var $block, $index;
+ private $context;
+
+ function __construct($block, $context, $index) {
+ $this->block =& $block;
+ $this->context = $context;
+ $this->index = $index;
+ }
+
+ function name() {
+ return $this->block->name;
+ }
+
+ function depth() {
+ return $this->index;
+ }
+
+ function super() {
+ $stream = new StreamWriter;
+ $this->block->parent->render($this->context, $stream, $this->index+1);
+ return $stream->close();
+ }
+
+ function __toString() {
+ return "[BlockContext : {$this->block->name}, {$this->block->filename}]";
+ }
+}
+?>
diff --git a/web/system/vendor/h2o/datatype.php b/web/system/vendor/h2o/datatype.php
new file mode 100644
index 0000000..0495f4a
--- /dev/null
+++ b/web/system/vendor/h2o/datatype.php
@@ -0,0 +1,173 @@
+close = false;
+ }
+
+ function write($data) {
+ if ($this->close)
+ new Exception('tried to write to closed stream');
+ $this->buffer[] = $data;
+ }
+
+ function close() {
+ $this->close = true;
+ return implode('', $this->buffer);
+ }
+}
+
+class Evaluator {
+ static function gt($l, $r) { return $l > $r; }
+ static function ge($l, $r) { return $l >= $r; }
+
+ static function lt($l, $r) { return $l < $r; }
+ static function le($l, $r) { return $l <= $r; }
+
+ static function eq($l, $r) { return $l == $r; }
+ static function ne($l, $r) { return $l != $r; }
+
+ static function not_($bool) { return !$bool; }
+ static function and_($l, $r) { return ($l && $r); }
+ static function or_($l, $r) { return ($l && $r); }
+
+ # Currently only support single expression with no preceddence ,no boolean expression
+ # [expression] = [optional binary] ? operant [ optional compare operant]
+ # [operant] = variable|string|numeric|boolean
+ # [compare] = > | < | == | >= | <=
+ # [binary] = not | !
+ static function exec($args, $context) {
+ $argc = count($args);
+ $first = array_shift($args);
+ $first = $context->resolve($first);
+ switch ($argc) {
+ case 1 :
+ return $first;
+ case 2 :
+ if (is_array($first) && isset($first['operator']) && $first['operator'] == 'not') {
+ $operant = array_shift($args);
+ $operant = $context->resolve($operant);
+ return !($operant);
+ }
+ case 3 :
+ list($op, $right) = $args;
+ $right = $context->resolve($right);
+ return call_user_func(array("Evaluator", $op['operator']), $first, $right);
+ default:
+ return false;
+ }
+ }
+}
+
+/**
+ * $type of token, Block | Variable
+ */
+class H2o_Token {
+ function __construct ($type, $content, $position) {
+ $this->type = $type;
+ $this->content = $content;
+ $this->result='';
+ $this->position = $position;
+ }
+
+ function write($content){
+ $this->result= $content;
+ }
+}
+
+/**
+ * a token stream
+ */
+class TokenStream {
+ var $pushed;
+ var $stream;
+ var $closed;
+ var $c;
+
+ function __construct() {
+ $this->pushed = array();
+ $this->stream = array();
+ $this->closed = false;
+ }
+
+ function pop() {
+ if (count($this->pushed))
+ return array_pop($this->pushed);
+ return array_pop($this->stream);
+ }
+
+ function feed($type, $contents, $position) {
+ if ($this->closed)
+ throw new Exception('cannot feed closed stream');
+ $this->stream[] = new H2o_Token($type, $contents, $position);
+ }
+
+ function push($token) {
+ if (is_null($token))
+ throw new Exception('cannot push NULL');
+ if ($this->closed)
+ $this->pushed[] = $token;
+ else
+ $this->stream[] = $token;
+ }
+
+ function close() {
+ if ($this->closed)
+ new Exception('cannot close already closed stream');
+ $this->closed = true;
+ $this->stream = array_reverse($this->stream);
+ }
+
+ function isClosed() {
+ return $this->closed;
+ }
+
+ function current() {
+ return $this->c ;
+ }
+
+ function next() {
+ return $this->c = $this->pop();
+ }
+}
+
+class H2o_Info {
+ var $h2o_safe = array('filters', 'extensions', 'tags');
+ var $name = 'H2o Template engine';
+ var $description = "Django inspired template system";
+ var $version = H2O_VERSION;
+
+ function filters() {
+ return array_keys(h2o::$filters);
+ }
+
+ function tags() {
+ return array_keys(h2o::$tags);
+ }
+
+ function extensions() {
+ return array_keys(h2o::$extensions);
+ }
+}
+
+/**
+ * Functions
+ */
+function sym_to_str($string) {
+ return substr($string, 1);
+}
+
+function is_sym($string) {
+ return isset($string[0]) && $string[0] === ':';
+}
+
+function symbol($string) {
+ return ':'.$string;
+}
+
+function strip_regex($regex, $delimiter = '/') {
+ return substr($regex, 1, strrpos($regex, $delimiter)-1);
+}
+?>
diff --git a/web/system/vendor/h2o/errors.php b/web/system/vendor/h2o/errors.php
new file mode 100644
index 0000000..4f214e9
--- /dev/null
+++ b/web/system/vendor/h2o/errors.php
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/web/system/vendor/h2o/filters.php b/web/system/vendor/h2o/filters.php
new file mode 100644
index 0000000..2e72e9a
--- /dev/null
+++ b/web/system/vendor/h2o/filters.php
@@ -0,0 +1,369 @@
+ $value) {
+ $result .= $name.'='.urlencode($value).'&'.$querystring;
+ }
+ $querystring = substr($result, 0, strlen($result)-1);
+ return htmlspecialchars($result);
+ } else {
+ return urlencode($data);
+ }
+ }
+
+ static function hyphenize ($string) {
+ $rules = array('/[^\w\s-]+/'=>'','/\s+/'=>'-', '/-{2,}/'=>'-');
+ $string = preg_replace(array_keys($rules), $rules, trim($string));
+ return $string = trim(strtolower($string));
+ }
+
+ static function urlize( $string, $truncate = false ) {
+ $reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
+ preg_match_all($reg_exUrl, $string, $matches);
+ $usedPatterns = array();
+ foreach($matches[0] as $pattern){
+ if(!array_key_exists($pattern, $usedPatterns)){
+ $usedPatterns[$pattern]=true;
+ $string = str_replace($pattern, "{$pattern}", $string);
+ }
+ }
+
+ $reg_exEmail = "/[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/";
+ preg_match_all($reg_exEmail, $string, $matches);
+ $usedPatterns = array();
+ foreach($matches[0] as $pattern){
+ if(!array_key_exists($pattern, $usedPatterns)){
+ $usedPatterns[$pattern]=true;
+ $string = str_replace($pattern, "{$pattern}", $string);
+ }
+ }
+ return $string;
+ }
+
+ static function set_default($object, $default) {
+ return !$object ? $default : $object;
+ }
+}
+
+class StringFilters extends FilterCollection {
+
+ static function humanize($string) {
+ $string = preg_replace('/\s+/', ' ', trim(preg_replace('/[^A-Za-z0-9()!,?$]+/', ' ', $string)));
+ return capfirst($string);
+ }
+
+ static function capitalize($string) {
+ return ucwords(strtolower($string)) ;
+ }
+
+ static function titlize($string) {
+ return self::capitalize($string);
+ }
+
+ static function capfirst($string) {
+ $string = strtolower($string);
+ return strtoupper($string{0}). substr($string, 1, strlen($string));
+ }
+
+ static function tighten_space($value) {
+ return preg_replace("/\s{2,}/", ' ', $value);
+ }
+
+ static function escape($value, $attribute = false) {
+ return htmlspecialchars($value, $attribute ? ENT_QUOTES : ENT_NOQUOTES);
+ }
+
+ static function escapejson($value) {
+ // The standard django escapejs converts all non-ascii characters into hex codes.
+ // This function encodes the entire data structure, and strings get quotes around them.
+ return json_encode($value);
+ }
+
+ static function force_escape($value, $attribute = false) {
+ return self::escape($value, $attribute);
+ }
+
+ static function e($value, $attribute = false) {
+ return self::escape($value, $attribute);
+ }
+
+ static function safe($value) {
+ return $value;
+ }
+
+ static function truncate ($string, $max = 50, $ends = '...') {
+ return (strlen($string) > $max ? substr($string, 0, $max).$ends : $string);
+ }
+
+ static function limitwords($text, $limit = 50, $ends = '...') {
+ if (strlen($text) > $limit) {
+ $words = str_word_count($text, 2);
+ $pos = array_keys($words);
+
+ if (isset($pos[$limit])) {
+ $text = substr($text, 0, $pos[$limit]) . $ends;
+ }
+ }
+ return $text;
+ }
+}
+
+class NumberFilters extends FilterCollection {
+ static function filesize ($bytes, $round = 1) {
+ if ($bytes === 0)
+ return '0 bytes';
+ elseif ($bytes === 1)
+ return '1 byte';
+
+ $units = array(
+ 'bytes' => pow(2, 0), 'kB' => pow(2, 10),
+ 'BM' => pow(2, 20), 'GB' => pow(2, 30),
+ 'TB' => pow(2, 40), 'PB' => pow(2, 50),
+ 'EB' => pow(2, 60), 'ZB' => pow(2, 70)
+ );
+
+ $lastUnit = 'bytes';
+ foreach ($units as $unitName => $unitFactor) {
+ if ($bytes >= $unitFactor) {
+ $lastUnit = $unitName;
+ } else {
+ $number = round( $bytes / $units[$lastUnit], $round );
+ return number_format($number) . ' ' . $lastUnit;
+ }
+ }
+ }
+
+ static function currency($amount, $currency = 'USD', $precision = 2, $negateWithParentheses = false) {
+ $definition = array(
+ 'EUR' => array('�','.',','), 'GBP' => '�', 'JPY' => '�',
+ 'USD'=>'$', 'AU' => '$', 'CAN' => '$'
+ );
+ $negative = false;
+ $separator = ',';
+ $decimals = '.';
+ $currency = strtoupper($currency);
+
+ // Is negative
+ if (strpos('-', $amount) !== false) {
+ $negative = true;
+ $amount = str_replace("-","",$amount);
+ }
+ $amount = (float) $amount;
+
+ if (!$negative) {
+ $negative = $amount < 0;
+ }
+ if ($negateWithParentheses) {
+ $amount = abs($amount);
+ }
+
+ // Get rid of negative zero
+ $zero = round(0, $precision);
+ if (round($amount, $precision) === $zero) {
+ $amount = $zero;
+ }
+
+ if (isset($definition[$currency])) {
+ $symbol = $definition[$currency];
+ if (is_array($symbol))
+ @list($symbol, $separator, $decimals) = $symbol;
+ } else {
+ $symbol = $currency;
+ }
+ $amount = number_format($amount, $precision, $decimals, $separator);
+
+ return $negateWithParentheses ? "({$symbol}{$amount})" : "{$symbol}{$amount}";
+ }
+}
+
+class HtmlFilters extends FilterCollection {
+ static function base_url($url, $options = array()) {
+ return $url;
+ }
+
+ static function asset_url($url, $options = array()) {
+ return self::base_url($url, $options);
+ }
+
+ static function image_tag($url, $options = array()) {
+ $attr = self::htmlAttribute(array('alt','width','height','border'), $options);
+ return sprintf('', $url, $attr);
+ }
+
+ static function css_tag($url, $options = array()) {
+ $attr = self::htmlAttribute(array('media'), $options);
+ return sprintf('', $url, $attr);
+ }
+
+ static function script_tag($url, $options = array()) {
+ return sprintf('', $url);
+ }
+
+ static function links_to($text, $url, $options = array()) {
+ $attrs = self::htmlAttribute(array('ref'), $options);
+ $url = self::base_url($url, $options);
+ return sprintf('%s', $url, $attrs, $text);
+ }
+
+ static function links_with ($url, $text, $options = array()) {
+ return self::links_to($text, $url, $options);
+ }
+
+ static function strip_tags($text) {
+ $text = preg_replace(array('/', '/>/'), array(' <', '> '),$text);
+ return strip_tags($text);
+ }
+
+ static function linebreaks($value, $format = 'p') {
+ if ($format === 'br')
+ return HtmlFilters::nl2br($value);
+ return HtmlFilters::nl2pbr($value);
+ }
+
+ static function nl2br($value) {
+ return str_replace("\n", "
\n", $value);
+ }
+
+ static function nl2pbr($value) {
+ $result = array();
+ $parts = preg_split('/(\r?\n){2,}/m', $value);
+ foreach ($parts as $part) {
+ array_push($result, '' . HtmlFilters::nl2br($part) . '
');
+ }
+ return implode("\n", $result);
+ }
+
+ protected static function htmlAttribute($attrs = array(), $data = array()) {
+ $attrs = self::extract(array_merge(array('id', 'class', 'title', "style"), $attrs), $data);
+
+ $result = array();
+ foreach ($attrs as $name => $value) {
+ $result[] = "{$name}=\"{$value}\"";
+ }
+ return join(' ', $result);
+ }
+
+ protected static function extract($attrs = array(), $data=array()) {
+ $result = array();
+ if (empty($data)) return array();
+ foreach($data as $k => $e) {
+ if (in_array($k, $attrs)) $result[$k] = $e;
+ }
+ return $result;
+ }
+}
+
+class DatetimeFilters extends FilterCollection {
+ static function date($time, $format = 'jS F Y H:i') {
+ if ($time instanceof DateTime)
+ $time = (int) $time->format('U');
+ if (!is_numeric($time))
+ $time = strtotime($time);
+
+ return date($format, $time);
+ }
+
+ static function relative_time($timestamp, $format = 'g:iA') {
+ if ($timestamp instanceof DateTime)
+ $timestamp = (int) $timestamp->format('U');
+
+ $timestamp = is_numeric($timestamp) ? $timestamp: strtotime($timestamp);
+
+ $time = mktime(0, 0, 0);
+ $delta = time() - $timestamp;
+ $string = '';
+
+ if ($timestamp < $time - 86400) {
+ return date("F j, Y, g:i a", $timestamp);
+ }
+ if ($delta > 86400 && $timestamp < $time) {
+ return "Yesterday at " . date("g:i a", $timestamp);
+ }
+
+ if ($delta > 7200)
+ $string .= floor($delta / 3600) . " hours, ";
+ else if ($delta > 3660)
+ $string .= "1 hour, ";
+ else if ($delta >= 3600)
+ $string .= "1 hour ";
+ $delta %= 3600;
+
+ if ($delta > 60)
+ $string .= floor($delta / 60) . " minutes ";
+ else
+ $string .= $delta . " seconds ";
+ return "$string ago";
+ }
+
+ static function relative_date($time) {
+ if ($time instanceof DateTime)
+ $time = (int) $time->format('U');
+
+ $time = is_numeric($time) ? $time: strtotime($time);
+ $today = strtotime(date('M j, Y'));
+ $reldays = ($time - $today)/86400;
+
+ if ($reldays >= 0 && $reldays < 1)
+ return 'today';
+ else if ($reldays >= 1 && $reldays < 2)
+ return 'tomorrow';
+ else if ($reldays >= -1 && $reldays < 0)
+ return 'yesterday';
+
+ if (abs($reldays) < 7) {
+ if ($reldays > 0) {
+ $reldays = floor($reldays);
+ return 'in ' . $reldays . ' day' . ($reldays != 1 ? 's' : '');
+ } else {
+ $reldays = abs(floor($reldays));
+ return $reldays . ' day' . ($reldays != 1 ? 's' : '') . ' ago';
+ }
+ }
+ if (abs($reldays) < 182)
+ return date('l, F j',$time ? $time : time());
+ else
+ return date('l, F j, Y',$time ? $time : time());
+ }
+
+ static function relative_datetime($time) {
+ $date = self::relative_date($time);
+
+ if ($date === 'today')
+ return self::relative_time($time);
+
+ return $date;
+ }
+}
+
+/* Ultizie php funciton as Filters */
+h2o::addFilter(array('md5', 'sha1', 'numberformat'=>'number_format', 'wordwrap', 'trim', 'upper' => 'strtoupper', 'lower' => 'strtolower'));
+
+/* Add filter collections */
+h2o::addFilter(array('CoreFilters', 'StringFilters', 'NumberFilters', 'DatetimeFilters', 'HtmlFilters'));
+
+/* Alias default to set_default */
+h2o::addFilter('default', array('CoreFilters', 'set_default'));
+
+?>
diff --git a/web/system/vendor/h2o/loaders.php b/web/system/vendor/h2o/loaders.php
new file mode 100644
index 0000000..91a392f
--- /dev/null
+++ b/web/system/vendor/h2o/loaders.php
@@ -0,0 +1,290 @@
+searchpath = (array) $searchpath;
+ $this->setOptions($options);
+ }
+
+ function setOptions($options = array()) {
+ if (isset($options['cache']) && $options['cache']) {
+ $this->cache = h2o_cache($options);
+ }
+ }
+
+ function read($filename) {
+
+ if (!is_file($filename))
+ $filename = $this->get_template_path($this->searchpath,$filename);
+
+ if (is_file($filename)) {
+ $source = file_get_contents($filename);
+ return $this->runtime->parse($source);
+ } else {
+ throw new TemplateNotFound($filename);
+ }
+ }
+
+ function get_template_path($search_path, $filename){
+
+
+ for ($i=0 ; $i < count($search_path) ; $i++)
+ {
+
+ if(file_exists($search_path[$i] . $filename)) {
+ $filename = $search_path[$i] . $filename;
+ return $filename;
+ break;
+ } else {
+ continue;
+ }
+
+ }
+
+ throw new Exception('TemplateNotFound - Looked for template: ' . $filename);
+
+
+
+ }
+
+ function read_cache($filename) {
+ if (!$this->cache){
+ $filename = $this->get_template_path($this->searchpath,$filename);
+ return $this->read($filename);
+ }
+
+ if (!is_file($filename)){
+ $filename = $this->get_template_path($this->searchpath,$filename);
+ }
+
+ $filename = realpath($filename);
+
+ $cache = md5($filename);
+ $object = $this->cache->read($cache);
+ $this->cached = $object && !$this->expired($object);
+
+ if (!$this->cached) {
+ $nodelist = $this->read($filename);
+ $object = (object) array(
+ 'filename' => $filename,
+ 'content' => serialize($nodelist),
+ 'created' => time(),
+ 'templates' => $nodelist->parser->storage['templates'],
+ 'included' => $nodelist->parser->storage['included'] + array_values(h2o::$extensions)
+ );
+ $this->cache->write($cache, $object);
+ } else {
+ foreach($object->included as $ext => $file) {
+ include_once (h2o::$extensions[$ext] = $file);
+ }
+ }
+ return unserialize($object->content);
+ }
+
+ function flush_cache() {
+ $this->cache->flush();
+ }
+
+ function expired($object) {
+ if (!$object) return false;
+
+ $files = array_merge(array($object->filename), $object->templates);
+ foreach ($files as $file) {
+ if (!is_file($file))
+ $file = $this->get_template_path($this->searchpath, $file);
+
+ if ($object->created < filemtime($file))
+ return true;
+ }
+ return false;
+ }
+}
+
+function file_loader($file) {
+ return new H2o_File_Loader($file);
+}
+
+class H2o_Hash_Loader {
+
+ function __construct($scope, $options = array()) {
+ $this->scope = $scope;
+ }
+
+ function setOptions() {}
+
+ function read($file) {
+ if (!isset($this->scope[$file]))
+ throw new TemplateNotFound;
+ return $this->runtime->parse($this->scope[$file], $file);
+ }
+
+ function read_cache($file) {
+ return $this->read($file);
+ }
+}
+
+function hash_loader($hash = array()) {
+ return new H2o_Hash_Loader($hash);
+}
+
+/**
+ * Cache subsystem
+ *
+ */
+function h2o_cache($options = array()) {
+ $type = $options['cache'];
+ $className = "H2o_".ucwords($type)."_Cache";
+
+ if (class_exists($className, false)) {
+ return new $className($options);
+ }
+ return false;
+}
+
+class H2o_File_Cache {
+ var $ttl = 3600;
+ var $prefix = 'h2o_';
+
+ function __construct($options = array()) {
+ if (isset($options['cache_dir']) && is_writable($options['cache_dir'])) {
+ $path = $options['cache_dir'];
+ } else {
+ $path = dirname($tmp = tempnam(uniqid(rand(), true), ''));
+
+ if (file_exists($tmp)) unlink($tmp);
+ }
+ if (isset($options['cache_ttl'])) {
+ $this->ttl = $options['cache_ttl'];
+ }
+ if(isset($options['cache_prefix'])) {
+ $this->prefix = $options['cache_prefix'];
+ }
+
+ $this->path = realpath($path). DS;
+ }
+
+ function read($filename) {
+ if (!file_exists($this->path . $this->prefix. $filename))
+ return false;
+
+ $content = file_get_contents($this->path . $this->prefix. $filename);
+ $expires = (int)substr($content, 0, 10);
+
+ if (time() >= $expires)
+ return false;
+ return unserialize(trim(substr($content, 10)));
+ }
+
+ function write($filename, &$object) {
+ $expires = time() + $this->ttl;
+ $content = $expires . serialize($object);
+ return file_put_contents($this->path . $this->prefix. $filename, $content);
+ }
+
+ function flush() {
+ foreach (glob($this->path. $this->prefix. '*') as $file) {
+ @unlink($file);
+ }
+ }
+}
+
+class H2o_Apc_Cache {
+ var $ttl = 3600;
+ var $prefix = 'h2o_';
+
+ function __construct($options = array()) {
+ if (!function_exists('apc_add'))
+ throw new Exception('APC extension needs to be loaded to use APC cache');
+
+ if (isset($options['cache_ttl'])) {
+ $this->ttl = $options['cache_ttl'];
+ }
+ if(isset($options['cache_prefix'])) {
+ $this->prefix = $options['cache_prefix'];
+ }
+ }
+
+ function read($filename) {
+ return apc_fetch($this->prefix.$filename);
+ }
+
+ function write($filename, $object) {
+ return apc_store($this->prefix.$filename, $object, $this->ttl);
+ }
+
+ function flush() {
+ return apc_clear_cache('user');
+ }
+}
+
+
+class H2o_Memcache_Cache {
+ var $ttl = 3600;
+ var $prefix = 'h2o_';
+ /**
+ * @var host default is file socket
+ */
+ var $host = 'unix:///tmp/memcached.sock';
+ var $port = 0;
+ var $object;
+ function __construct( $scope, $options = array() ) {
+ if ( !function_exists( 'memcache_set' ) )
+ throw new Exception( 'Memcache extension needs to be loaded to use memcache' );
+
+ if ( isset( $options['cache_ttl'] ) ) {
+ $this->ttl = $options['cache_ttl'];
+ }
+ if( isset( $options['cache_prefix'] ) ) {
+ $this->prefix = $options['cache_prefix'];
+ }
+
+ if( isset( $options['host'] ) ) {
+ $this->host = $options['host'];
+ }
+
+ if( isset( $options['port'] ) ) {
+ $this->port = $options['port'];
+ }
+
+ $this->object = memcache_connect( $this->host, $this->port );
+ }
+
+ function read( $filename ){
+ return memcache_get( $this->object, $this->prefix.$filename );
+ }
+
+ function write( $filename, $content ) {
+ return memcache_set( $this->object,$this->prefix.$filename,$content , MEMCACHE_COMPRESSED,$this->ttl );
+ }
+
+ function flush(){
+ return memcache_flush( $this->object );
+ }
+}
\ No newline at end of file
diff --git a/web/system/vendor/h2o/nodes.php b/web/system/vendor/h2o/nodes.php
new file mode 100644
index 0000000..11dad3f
--- /dev/null
+++ b/web/system/vendor/h2o/nodes.php
@@ -0,0 +1,84 @@
+parser = $parser;
+ if (is_null($initial))
+ $initial = array();
+ $this->list = $initial;
+ $this->position = $position;
+ }
+
+ function render($context, $stream) {
+ foreach($this->list as $node) {
+ $node->render($context, $stream);
+ }
+ }
+
+ function append($node) {
+ array_push($this->list, $node);
+ }
+
+ function extend($nodes) {
+ array_merge($this->list, $nodes);
+ }
+
+ function getLength() {
+ return count($this->list);
+ }
+
+ function getIterator() {
+ return new ArrayIterator( $this->list );
+ }
+}
+
+class VariableNode extends H2o_Node {
+ private $filters = array();
+ var $variable;
+
+ function __construct($variable, $filters, $position = 0) {
+ if (!empty($filters))
+ $this->filters = $filters;
+ $this->variable = $variable;
+ }
+
+ function render($context, $stream) {
+ $value = $context->resolve($this->variable);
+ $value = $context->escape($value, $this->variable);
+ $stream->write($value);
+ }
+}
+
+class CommentNode extends H2o_Node {}
+
+class TextNode extends H2o_Node {
+ var $content;
+ function __construct($content, $position = 0) {
+ $this->content = $content;
+ $this->position = $position;
+ }
+
+ function render($context, $stream) {
+ $stream->write($this->content);
+ }
+
+ function is_blank() {
+ return strlen(trim($this->content));
+ }
+}
+
+
+?>
\ No newline at end of file
diff --git a/web/system/vendor/h2o/parser.php b/web/system/vendor/h2o/parser.php
new file mode 100644
index 0000000..a805243
--- /dev/null
+++ b/web/system/vendor/h2o/parser.php
@@ -0,0 +1,290 @@
+options = $options;
+
+ $trim = '';
+ if ($this->options['TRIM_TAGS'])
+ $trim = '(?:\r?\n)?';
+
+ $this->pattern = ('/\G(.*?)(?:' .
+ preg_quote($this->options['BLOCK_START']). '(.*?)' .preg_quote($this->options['BLOCK_END']) . $trim . '|' .
+ preg_quote($this->options['VARIABLE_START']). '(.*?)' .preg_quote($this->options['VARIABLE_END']) . '|' .
+ preg_quote($this->options['COMMENT_START']). '(.*?)' .preg_quote($this->options['COMMENT_END']) . $trim . ')/sm'
+ );
+ }
+
+ function tokenize($source) {
+ $result = new TokenStream;
+ $pos = 0;
+ $matches = array();
+ preg_match_all($this->pattern, $source, $matches, PREG_SET_ORDER);
+
+ foreach ($matches as $match) {
+ if ($match[1])
+ $result->feed('text', $match[1], $pos);
+ $tagpos = $pos + strlen($match[1]);
+ if ($match[2])
+ $result->feed('block', trim($match[2]), $tagpos);
+ elseif ($match[3])
+ $result->feed('variable', trim($match[3]), $tagpos);
+ elseif ($match[4])
+ $result->feed('comment', trim($match[4]), $tagpos);
+ $pos += strlen($match[0]);
+ }
+ if ($pos < strlen($source)){
+ $result->feed('text', substr($source, $pos), $pos);
+ }
+ $result->close();
+ return $result;
+ }
+}
+
+class H2o_Parser {
+ var $first;
+ var $storage = array();
+ var $filename;
+ var $runtime;
+
+ function __construct($source, $filename, $runtime, $options) {
+ $this->options = $options;
+ //$this->source = $source;
+ $this->runtime = $runtime;
+ $this->filename = $filename;
+ $this->first = true;
+
+ $this->lexer = new H2o_Lexer($options);
+ $this->tokenstream = $this->lexer->tokenize($source);
+ $this->storage = array(
+ 'blocks' => array(),
+ 'templates' => array(),
+ 'included' => array()
+ );
+ }
+
+ function &parse() {
+ $until = func_get_args();
+ $nodelist = new NodeList($this);
+ while($token = $this->tokenstream->next()) {
+ //$token = $this->tokenstream->current();
+ switch($token->type) {
+ case 'text' :
+ $node = new TextNode($token->content, $token->position);
+ break;
+ case 'variable' :
+ $args = H2o_Parser::parseArguments($token->content, $token->position);
+ $variable = array_shift($args);
+ $filters = $args;
+ $node = new VariableNode($variable, $filters, $token->position);
+ break;
+ case 'comment' :
+ $node = new CommentNode($token->content);
+ break;
+ case 'block' :
+ if (in_array($token->content, $until)) {
+ $this->token = $token;
+ return $nodelist;
+ }
+ $temp = preg_split('/\s+/',$token->content, 2);
+ $name = $temp[0];
+ $args = (count($temp) > 1 ? $temp[1] : null);
+ $node = H2o::createTag($name, $args, $this, $token->position);
+ $this->token = $token;
+ }
+ $this->searching = join(',',$until);
+ $this->first = false;
+ $nodelist->append($node);
+ }
+
+ if ($until) {
+ throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
+ }
+ return $nodelist;
+ }
+
+ function skipTo($until) {
+ $this->parse($until);
+ return null;
+ }
+
+ # Parse arguments
+ static function parseArguments($source = null, $fpos = 0){
+ $parser = new ArgumentLexer($source, $fpos);
+ $result = array();
+ $current_buffer = &$result;
+ $filter_buffer = array();
+ $tokens = $parser->parse();
+ foreach ($tokens as $token) {
+ list($token, $data) = $token;
+ if ($token == 'filter_start') {
+ $filter_buffer = array();
+ $current_buffer = &$filter_buffer;
+ }
+ elseif ($token == 'filter_end') {
+ if (count($filter_buffer)) {
+
+ $i = count($result)-1;
+ if ( is_array($result[$i]) ) $result[$i]['filters'][] = $filter_buffer;
+ else $result[$i] = array(0 => $result[$i], 'filters' => array($filter_buffer));
+ }
+ $current_buffer = &$result;
+ }
+ elseif ($token == 'boolean') {
+ $current_buffer[] = ($data === 'true'? true : false);
+ }
+ elseif ($token == 'name') {
+ $current_buffer[] = symbol($data);
+ }
+ elseif ($token == 'number' || $token == 'string') {
+ $current_buffer[] = $data;
+ }
+ elseif ($token == 'named_argument') {
+ $last = $current_buffer[count($current_buffer) - 1];
+ if (!is_array($last))
+ $current_buffer[] = array();
+
+ $namedArgs =& $current_buffer[count($current_buffer) - 1];
+ list($name,$value) = array_map('trim', explode(':', $data, 2));
+
+ # if argument value is variable mark it
+ $value = self::parseArguments($value);
+ $namedArgs[$name] = $value[0];
+ }
+ elseif( $token == 'operator') {
+ $current_buffer[] = array('operator'=>$data);
+ }
+ }
+ return $result;
+ }
+}
+
+class H2O_RE {
+ static $whitespace, $seperator, $parentheses, $pipe, $filter_end, $operator, $boolean, $number, $string, $i18n_string, $name, $named_args;
+
+ static function init() {
+ $r = 'strip_regex';
+
+ self::$whitespace = '/\s+/m';
+ self::$parentheses = '/\(|\)/m';
+ self::$filter_end = '/;/';
+ self::$boolean = '/true|false/';
+ self::$seperator = '/,/';
+ self::$pipe = '/\|/';
+ self::$operator = '/\s?(>|<|>=|<=|!=|==|!|and |not |or )\s?/i';
+ self::$number = '/\d+(\.\d*)?/';
+ self::$name = '/[a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*/';
+
+ self::$string = '/(?:
+ "([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" | # Double Quote string
+ \'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\' # Single Quote String
+ )/xsm';
+ self::$i18n_string = "/_\({$r(self::$string)}\) | {$r(self::$string)}/xsm";
+
+ self::$named_args = "{
+ ({$r(self::$name)})(?:{$r(self::$whitespace)})?
+ :
+ (?:{$r(self::$whitespace)})?({$r(self::$i18n_string)}|{$r(self::$number)}|{$r(self::$name)})
+ }x";
+ }
+}
+H2O_RE::init();
+
+class ArgumentLexer {
+ private $source;
+ private $match;
+ private $pos = 0, $fpos, $eos;
+ private $operator_map = array(
+ '!' => 'not', '!='=> 'ne', '==' => 'eq', '>' => 'gt', '<' => 'lt', '<=' => 'le', '>=' => 'ge'
+ );
+
+ function __construct($source, $fpos = 0){
+ if (!is_null($source))
+ $this->source = $source;
+ $this->fpos=$fpos;
+ }
+
+ function parse(){
+ $result = array();
+ $filtering = false;
+ while (!$this->eos()) {
+ $this->scan(H2O_RE::$whitespace);
+ if (!$filtering) {
+ if ($this->scan(H2O_RE::$operator)){
+ $operator = trim($this->match);
+ if(isset($this->operator_map[$operator]))
+ $operator = $this->operator_map[$operator];
+ $result[] = array('operator', $operator);
+ }
+ elseif ($this->scan(H2O_RE::$boolean))
+ $result[] = array('boolean', $this->match);
+ elseif ($this->scan(H2O_RE::$named_args))
+ $result[] = array('named_argument', $this->match);
+ elseif ($this->scan(H2O_RE::$name))
+ $result[] = array('name', $this->match);
+ elseif ($this->scan(H2O_RE::$pipe)) {
+ $filtering = true;
+ $result[] = array('filter_start', $this->match);
+ }
+ elseif ($this->scan(H2O_RE::$seperator))
+ $result[] = array('separator', null);
+ elseif ($this->scan(H2O_RE::$i18n_string))
+ $result[] = array('string', $this->match);
+ elseif ($this->scan(H2O_RE::$number))
+ $result[] = array('number', $this->match);
+ else
+ throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
+ }
+ else {
+ // parse filters, with chaining and ";" as filter end character
+ if ($this->scan(H2O_RE::$pipe)) {
+ $result[] = array('filter_end', null);
+ $result[] = array('filter_start', null);
+ }
+ elseif ($this->scan(H2O_RE::$seperator))
+ $result[] = array('separator', null);
+ elseif ($this->scan(H2O_RE::$filter_end)) {
+ $result[] = array('filter_end', null);
+ $filtering = false;
+ }
+ elseif ($this->scan(H2O_RE::$boolean))
+ $result[] = array('boolean', $this->match);
+ elseif ($this->scan(H2O_RE::$named_args))
+ $result[] = array('named_argument', $this->match);
+ elseif ($this->scan(H2O_RE::$name))
+ $result[] = array('name', $this->match);
+ elseif ($this->scan(H2O_RE::$i18n_string))
+ $result[] = array('string', $this->match);
+ elseif ($this->scan(H2O_RE::$number))
+ $result[] = array('number', $this->match);
+ else
+ throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
+ }
+ }
+ // if we are still in the filter state, we add a filter_end token.
+ if ($filtering)
+ $result[] = array('filter_end', null);
+ return $result;
+ }
+
+ # String scanner
+ function scan($regexp) {
+ if (preg_match($regexp . 'A', $this->source, $match, null, $this->pos)) {
+ $this->match = $match[0];
+ $this->pos += strlen($this->match);
+ return true;
+ }
+ return false;
+ }
+
+ function eos() {
+ return $this->pos >= strlen($this->source);
+ }
+
+ /**
+ * return the position in the template
+ */
+ function getPosition() {
+ return $this->fpos + $this->pos;
+ }
+}
+?>
diff --git a/web/system/vendor/h2o/tags.php b/web/system/vendor/h2o/tags.php
new file mode 100644
index 0000000..ea2fdbf
--- /dev/null
+++ b/web/system/vendor/h2o/tags.php
@@ -0,0 +1,483 @@
+nodelist_true = $parser->parse('endifchanged', 'else');
+
+ if ($parser->token->content === 'else')
+ $this->nodelist_false = $parser->parse('endifchanged');
+
+ $this->_varlist = current(H2o_Parser::parseArguments($argstring));
+
+ if (!$this->_varlist)
+ throw new TemplateSyntaxError('H2o doesn\'t support lazy ifchanged yet. Please, supply a variable.');
+
+ }
+
+ function render($context, $stream) {
+
+ if ($this->_varlist) {
+ $compare_to = $context->resolve($this->_varlist);
+ } else {
+ /**
+ * @todo Rendering method $this->nodelist_true->render() should return a result.
+ * Further more $compare_to variable should be set to this result.
+ */
+ $compare_to = '';
+ }
+
+ if ($compare_to != $this->_last_seen) {
+ $this->_last_seen = $compare_to;
+ $this->nodelist_true->render($context, $stream);
+ } elseif ($this->nodelist_false) {
+ $this->nodelist_false->render($context, $stream);
+ }
+
+ }
+}
+
+class If_Tag extends H2o_Node {
+ private $body;
+ private $else;
+ private $negate;
+
+ function __construct($argstring, $parser, $position = 0) {
+ if (preg_match('/\s(and|or)\s/', $argstring))
+ throw new TemplateSyntaxError('H2o doesn\'t support multiple expressions');
+
+ $this->body = $parser->parse('endif', 'else');
+
+ if ($parser->token->content === 'else')
+ $this->else = $parser->parse('endif');
+
+ $this->args = H2o_Parser::parseArguments($argstring);
+
+ $first = current($this->args);
+ if (isset($first['operator']) && $first['operator'] === 'not') {
+ array_shift($this->args);
+ $this->negate = true;
+ }
+ }
+
+ function render($context, $stream) {
+ if ($this->test($context))
+ $this->body->render($context, $stream);
+ elseif ($this->else)
+ $this->else->render($context, $stream);
+ }
+
+ function test($context) {
+ $test = Evaluator::exec($this->args, $context);
+ return $this->negate? !$test : $test;
+ }
+}
+
+class For_Tag extends H2o_Node {
+ public $position;
+ private $iteratable, $key, $item, $body, $else, $limit, $reversed;
+ private $syntax = '{
+ ([a-zA-Z][a-zA-Z0-9-_]*)(?:,\s?([a-zA-Z][a-zA-Z0-9-_]*))?
+ \s+in\s+
+ ([a-zA-Z][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*)\s* # Iteratable name
+ (?:limit\s*:\s*(\d+))?\s*
+ (reversed)? # Reverse keyword
+ }x';
+
+ function __construct($argstring, $parser, $position) {
+ if (!preg_match($this->syntax, $argstring, $match))
+ throw new TemplateSyntaxError("Invalid for loop syntax ");
+
+ $this->body = $parser->parse('endfor', 'else');
+
+ if ($parser->token->content === 'else')
+ $this->else = $parser->parse('endfor');
+
+ $match = array_pad($match, 6, '');
+ list(,$this->key, $this->item, $this->iteratable, $this->limit, $this->reversed) = $match;
+
+ if ($this->limit)
+ $this->limit = (int) $this->limit;
+
+ # Swap value if no key found
+ if (!$this->item) {
+ list($this->key, $this->item) = array($this->item, $this->key);
+ }
+ $this->iteratable = symbol($this->iteratable);
+ $this->reversed = (bool) $this->reversed;
+ }
+
+ function render($context, $stream) {
+ $iteratable = $context->resolve($this->iteratable);
+
+ if ($this->reversed)
+ $iteratable = array_reverse($iteratable);
+
+ if ($this->limit)
+ $iteratable = array_slice($iteratable, 0, $this->limit);
+
+ $length = count($iteratable);
+
+ if ($length) {
+ $parent = $context['loop'];
+ $context->push();
+ $rev_count = $is_even = $idx = 0;
+ foreach($iteratable as $key => $value) {
+ $is_even = $idx % 2;
+ $rev_count = $length - $idx;
+
+ if ($this->key) {
+ $context[$this->key] = $key;
+ }
+ $context[$this->item] = $value;
+ $context['loop'] = array(
+ 'parent' => $parent,
+ 'first' => $idx === 0,
+ 'last' => $rev_count === 1,
+ 'odd' => !$is_even,
+ 'even' => $is_even,
+ 'length' => $length,
+ 'counter' => $idx + 1,
+ 'counter0' => $idx,
+ 'revcounter' => $rev_count,
+ 'revcounter0' => $rev_count - 1
+ );
+ $this->body->render($context, $stream);
+ ++$idx;
+ }
+ $context->pop();
+ } elseif ($this->else)
+ $this->else->render($context, $stream);
+ }
+}
+
+class Block_Tag extends H2o_Node {
+ public $name;
+ public $position;
+ public $stack;
+ private $syntax = '/^[a-zA-Z_][a-zA-Z0-9_-]*$/';
+
+ function __construct($argstring, $parser, $position) {
+ if (!preg_match($this->syntax, $argstring))
+ throw new TemplateSyntaxError('Block tag expects a name, example: block [content]');
+
+ $this->name = $argstring;
+
+ if (isset($parser->storage['blocks'][$this->name]))
+ throw new TemplateSyntaxError('Block name exists, Please select a different block name');
+
+ $this->filename = $parser->filename;
+ $this->stack = array($parser->parse('endblock', "endblock {$this->name}"));
+
+ $parser->storage['blocks'][$this->name] = $this;
+ $this->position = $position;
+ }
+
+ function addLayer(&$nodelist) {
+ $nodelist->parent = $this;
+ array_push($this->stack, $nodelist);
+ }
+
+ function render($context, $stream, $index = 1) {
+ $key = count($this->stack) - $index;
+
+ if (isset($this->stack[$key])) {
+ $context->push();
+ $context['block'] = new BlockContext($this, $context, $index);
+ $this->stack[$key]->render($context, $stream);
+ $context->pop();
+ }
+ }
+}
+
+class Extends_Tag extends H2o_Node {
+ public $filename;
+ public $position;
+ public $nodelist;
+ private $syntax = '/^["\'](.*?)["\']$/';
+
+ function __construct($argstring, $parser, $position = 0) {
+ if (!$parser->first)
+ throw new TemplateSyntaxError('extends must be first in file');
+
+ if (!preg_match($this->syntax, $argstring))
+ throw new TemplatesyntaxError('filename must be quoted');
+
+ $this->filename = stripcslashes(substr($argstring, 1, -1));
+
+ # Parse the current template
+ $parser->parse();
+
+ # Parse parent template
+ $this->nodelist = $parser->runtime->loadSubTemplate($this->filename, $parser->options);
+ $parser->storage['templates'] = array_merge(
+ $parser->storage['templates'], $this->nodelist->parser->storage['templates']
+ );
+ $parser->storage['templates'][] = $this->filename;
+
+ if (!isset($this->nodelist->parser->storage['blocks']) || !isset($parser->storage['blocks']))
+ return ;
+
+ # Blocks of parent template
+ $blocks =& $this->nodelist->parser->storage['blocks'];
+
+ # Push child blocks on top of parent blocks
+ foreach($parser->storage['blocks'] as $name => &$block) {
+ if (isset($blocks[$name])) {
+ $blocks[$name]->addLayer($block);
+ }
+ }
+ }
+
+ function render($context, $stream) {
+ $this->nodelist->render($context, $stream);
+ }
+}
+
+/**
+ * include tag
+ *
+ * Usage:
+ *
+ * Simple inclusion
+ * {% include "./subtemplate.html" %}
+ *
+ *
+ * Inclusion with additional context variables passing:
+ * {% include "./subtemplate.html" with foo=bar spam="eggs" %}
+ *
+ * Note: Double quotes matter. In this example 'foo' template variable of subtemplate.html
+ * would be initialized with 'bar' variable contents (from main template context),
+ * while 'spam' template variable of subtemplate.html would be set to simple string ('eggs').
+ *
+ */
+class Include_Tag extends H2o_Node {
+ private $nodelist;
+ private $syntax = '/^["\'](.*?)["\'](\s+with\s+(.+))?$/';
+ private $_additional_context = array();
+
+ function __construct($argstring, $parser, $position = 0) {
+ if (!preg_match($this->syntax, $argstring, $matches)) {
+ throw new TemplateSyntaxError();
+ }
+
+ $matches_count = count($matches);
+
+ if ($matches_count > 2) {
+ // "with" statement supplied.
+ $with_vars = explode(' ', $matches[3]);
+ foreach ($with_vars as $var_str) {
+ $eq_pos = strpos($var_str, '=');
+ $this->_additional_context[substr($var_str, 0, $eq_pos)] = substr($var_str, $eq_pos+1);
+ }
+ }
+
+ $this->filename = stripcslashes($matches[1]);
+ $this->nodelist = $parser->runtime->loadSubTemplate($this->filename, $parser->options);
+ $parser->storage['templates'] = array_merge(
+ $this->nodelist->parser->storage['templates'], $parser->storage['templates']
+ );
+ $parser->storage['templates'][] = $this->filename;
+ }
+
+ function render($context, $stream) {
+ foreach ($this->_additional_context as $key => $value) {
+ if (strpos($value, '"') === false) {
+ // Context variable supplied as value. Needs to be resolved.
+ $value = $context->getVariable($value);
+ } else {
+ $value = trim($value, '"');
+ }
+ $context[$key] = $value;
+ }
+
+ $this->nodelist->render($context, $stream);
+ }
+}
+
+class With_Tag extends H2o_Node {
+ public $position;
+ private $variable, $shortcut;
+ private $nodelist;
+ private $syntax = '/^([\w]+(:?\.[\w\d]+)*)\s+as\s+([\w]+(:?\.[\w\d]+)?)$/';
+
+ function __construct($argstring, $parser, $position = 0) {
+ if (!preg_match($this->syntax, $argstring, $matches))
+ throw new TemplateSyntaxError('Invalid with tag syntax');
+
+ # extract the long name and shortcut
+ list(,$this->variable, ,$this->shortcut) = $matches;
+ $this->nodelist = $parser->parse('endwith');
+ }
+
+ function render($context, $stream) {
+ $variable = $context->getVariable($this->variable);
+
+ $context->push(array($this->shortcut => $variable));
+ $this->nodelist->render($context, $stream);
+ $context->pop();
+ }
+}
+
+class Cycle_Tag extends H2o_Node {
+ private $uid;
+ private $sequence;
+
+ function __construct($argstring, $parser, $pos) {
+ $args = h2o_parser::parseArguments($argstring);
+
+ if (count($args) < 2) {
+ throw new Exception('Cycle tag require more than two items');
+ }
+ $this->sequence = $args;
+ $this->uid = '__cycle__'.$pos;
+ }
+
+ function render($context, $stream) {
+ if (!is_null($item = $context->getVariable($this->uid))) {
+ $item = ($item + 1) % count($this->sequence);
+ } else {
+ $item = 0;
+ }
+ $stream->write($context->resolve($this->sequence[$item]));
+ $context->set($this->uid, $item);
+ }
+}
+
+class Load_Tag extends H2o_Node {
+ public $position;
+ private $searchpath = array(H2O_ROOT);
+ private $extension;
+
+ function __construct($argstring, $parser, $pos = 0) {
+ $this->extension = stripcslashes(preg_replace("/^[\"'](.*)[\"']$/", "$1", $argstring));
+
+ if ($parser->runtime->searchpath)
+ $this->appendPath($parser->runtime->searchpath);
+
+ $parser->storage['included'][$this->extension] = $file = $this->load();
+ $this->position = $pos;
+ }
+
+ function render($context, $stream) {
+ $this->load();
+ }
+
+ function appendPath($path) {
+ $this->searchpath[] = $path;
+ }
+
+ private function load() {
+ if (isset(h2o::$extensions[$this->extension])) {
+ return true;
+ }
+ foreach($this->searchpath as $path) {
+ $file = $path.'ext'.DS.$this->extension.'.php';
+ if (is_file($file)) {
+ h2o::load($this->extension, $file);
+ return $file;
+ }
+ }
+ throw new H2o_Error(
+ "Extension: {$this->extension} cannot be loaded, please confirm it exist in extension path"
+ );
+ }
+}
+
+class Debug_Tag extends H2o_Node {
+ private $argument;
+ function __construct($argstring, $parser, $pos = 0) {
+ $this->argument = $argstring;
+ }
+
+ function render($context, $stream) {
+ if ($this->argument) {
+ $object = $context->resolve(symbol($this->argument));
+ } else {
+ $object = $context->scopes[0];
+ }
+ $output = "" . htmlspecialchars( print_r($object, true) ) . "
";
+ $stream->write($output);
+ }
+}
+
+class Comment_Tag extends H2o_Node {
+ function __construct($argstring, $parser, $position) {
+ $parser->parse('endcomment');
+ }
+
+ function render($context, $stream, $index = 1) {
+ }
+}
+
+class Now_Tag extends H2o_Node {
+ function __construct($argstring, $parser, $pos=0) {
+ $this->format = $argstring;
+ if (!$this->format) {
+ $this->format = "D M j G:i:s T Y";
+ }
+ }
+
+ function render($contxt, $stream) {
+ $time = date($this->format);
+ $stream->write($time);
+ }
+}
+
+class Autoescape_Tag extends H2o_Node {
+ protected $enable;
+
+ function __construct($argstring, $parser, $pos = 0) {
+ if ($argstring === 'on')
+ $this->enable = true;
+ elseif ($argstring === 'off')
+ $this->enable = false;
+ else throw new H2o_Error(
+ "Invalid syntax : autoescape on|off "
+ );
+ }
+
+ function render($context, $stream) {
+ $context->autoescape = $this->enable;
+ }
+}
+
+class Csrf_token_Tag extends H2o_Node {
+ function render($context, $stream) {
+ $token = "";
+ if (isset($_COOKIE["csrftoken"]))
+ $token = $_COOKIE["csrftoken"];
+ else {
+ global $SECRET_KEY;
+ if (defined('SECRET_KEY'))
+ $token = md5(mt_rand() . SECRET_KEY);
+ else
+ $token = md5(mt_rand());
+ }
+ setcookie("csrftoken", $token, time()+60*60*24*365, "/");
+ $stream->write("");
+ }
+}
+
+H2o::addTag(array('block', 'extends', 'include', 'if', 'ifchanged', 'for', 'with', 'cycle', 'load', 'debug', 'comment', 'now', 'autoescape', 'csrf_token'));
diff --git a/web/system/vendor/is_cli.php b/web/system/vendor/is_cli.php
new file mode 100644
index 0000000..abb9488
--- /dev/null
+++ b/web/system/vendor/is_cli.php
@@ -0,0 +1,17 @@
+ 0)
+ {
+ return true;
+ }
+
+ return false;
+}
\ No newline at end of file
diff --git a/web/system/vendor/isvarset.php b/web/system/vendor/isvarset.php
new file mode 100644
index 0000000..ab68f38
--- /dev/null
+++ b/web/system/vendor/isvarset.php
@@ -0,0 +1,6 @@
+
+
+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/web/system/vendor/phpoauthlib2/ccurl.php b/web/system/vendor/phpoauthlib2/ccurl.php
new file mode 100644
index 0000000..d66ec60
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/ccurl.php
@@ -0,0 +1,149 @@
+authentication = 0;
+ if($use == true) $this->authentication = 1;
+ }
+
+ public function setName($name){
+ $this->auth_name = $name;
+ }
+ public function setPass($pass){
+ $this->auth_pass = $pass;
+ }
+
+ public function addHeader($head)
+ {
+ $this->_header[] = $head;
+ }
+
+ public function __construct($url,$followlocation = true,$timeOut = 30,$maxRedirecs = 4,$binaryTransfer = false,$includeHeader = false,$noBody = false)
+ {
+ $this->_url = $url;
+ $this->_followlocation = $followlocation;
+ $this->_timeout = $timeOut;
+ $this->_maxRedirects = $maxRedirecs;
+ $this->_noBody = $noBody;
+ $this->_includeHeader = $includeHeader;
+ $this->_binaryTransfer = $binaryTransfer;
+
+ $this->_cookieFileLocation = dirname(__FILE__).'/cookie.txt';
+
+ }
+
+ public function setReferer($referer){
+ $this->_referer = $referer;
+ }
+
+ public function setCookiFileLocation($path)
+ {
+ $this->_cookieFileLocation = $path;
+ }
+
+ public function setPost ($postFields)
+ {
+ $this->_post = true;
+ $this->_postFields = $postFields;
+ }
+
+ public function setUserAgent($userAgent)
+ {
+ $this->_useragent = $userAgent;
+ }
+
+ public function createCurl($url = 'nul')
+ {
+ if($url != 'nul'){
+ $this->_url = $url;
+ }
+
+ $s = curl_init();
+
+ curl_setopt($s,CURLOPT_URL,$this->_url);
+
+ // I understand the implications here - but this isn't a client application
+ // if my ISP is performing MITM sniffing I have bigger fish to fry
+ // also the security of a CA signed certificate is questionable at best
+ // https://www.schneier.com/blog/archives/2012/02/verisign_hacked.html
+ // Email me if you want to discus this adamsna@datanethost.net
+ // NA - 12/10/2014
+ curl_setopt($s, CURLOPT_SSL_VERIFYPEER, false);
+
+ curl_setopt($s,CURLOPT_HTTPHEADER,$this->_header);
+ curl_setopt($s,CURLOPT_TIMEOUT,$this->_timeout);
+ curl_setopt($s,CURLOPT_MAXREDIRS,$this->_maxRedirects);
+ curl_setopt($s,CURLOPT_RETURNTRANSFER,true);
+ curl_setopt($s,CURLOPT_FOLLOWLOCATION,$this->_followlocation);
+ curl_setopt($s,CURLOPT_COOKIEJAR,$this->_cookieFileLocation);
+ curl_setopt($s,CURLOPT_COOKIEFILE,$this->_cookieFileLocation);
+
+ if($this->authentication == 1){
+ curl_setopt($s, CURLOPT_USERPWD, $this->auth_name.':'.$this->auth_pass);
+ }
+ if($this->_post)
+ {
+ //curl_setopt($s,CURLOPT_POST,true);
+ curl_setopt($s, CURLOPT_CUSTOMREQUEST, "POST");
+ curl_setopt($s,CURLOPT_POSTFIELDS,$this->_postFields);
+
+ }
+
+ if($this->_includeHeader)
+ {
+ curl_setopt($s,CURLOPT_HEADER,true);
+ }
+
+ if($this->_noBody)
+ {
+ curl_setopt($s,CURLOPT_NOBODY,true);
+ }
+
+ curl_setopt($s,CURLOPT_USERAGENT,$this->_useragent);
+ curl_setopt($s,CURLOPT_REFERER,$this->_referer);
+
+ $this->_webpage = curl_exec($s);
+ $this->_status = curl_getinfo($s,CURLINFO_HTTP_CODE);
+ curl_close($s);
+
+ }
+
+ public function getHttpStatus()
+ {
+ return $this->_status;
+ }
+
+ public function __tostring(){
+ return $this->_webpage;
+ }
+}
\ No newline at end of file
diff --git a/web/system/vendor/phpoauthlib2/cookie.txt b/web/system/vendor/phpoauthlib2/cookie.txt
new file mode 100644
index 0000000..04cd5d3
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/cookie.txt
@@ -0,0 +1,5 @@
+# Netscape HTTP Cookie File
+# http://curl.haxx.se/docs/http-cookies.html
+# This file was generated by libcurl! Edit at your own risk.
+
+#HttpOnly_.google.com TRUE / FALSE 1463331114 NID 73=wOGSMwy8vYCu7qJjpMYLVMQ_gYCNZXru2x8g0p5InvQIpj8X4P2uiXE8QdX50ZcpHvxCXo35XdDS8P5trQSsI0s3UmQ-tmG_01TTIVil6YeJIzFKqoGmKAdWo_0o8MOQ
diff --git a/web/system/vendor/phpoauthlib2/example.php b/web/system/vendor/phpoauthlib2/example.php
new file mode 100644
index 0000000..5a4813f
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/example.php
@@ -0,0 +1,24 @@
+ "apps.googleusercontent.com",
+ "client_secret" => "",
+ "redirect_uri" => "http://example.com/phpoauthlib2/example.php"
+]);
+
+$oauth = new OAuth($authProvider, $_GET);
+
+$check = $oauth->check();
+
+if ($check === true) {
+ echo "Hello - " . $authProvider->getFirstName();
+ echo "
Your email is - " . $authProvider->getEmail();
+} else {
+ header("Location: " . $check);
+}
\ No newline at end of file
diff --git a/web/system/vendor/phpoauthlib2/oauth.php b/web/system/vendor/phpoauthlib2/oauth.php
new file mode 100644
index 0000000..8ffe1db
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/oauth.php
@@ -0,0 +1,26 @@
+oauthProvider = $provider;
+ $this->request = $request;
+ }
+
+ public function check() {
+ if (isset($this->request["code"]) && !empty($this->request["code"])) {
+ $this->oauthProvider->getProfile();
+ return true;
+ } else {
+ return $this->oauthProvider->getLoginUrl();
+ }
+ }
+
+ public function getProfile() {
+ return $this->oauthProvider->getProfile();
+ }
+}
\ No newline at end of file
diff --git a/web/system/vendor/phpoauthlib2/oauthdataprovider.php b/web/system/vendor/phpoauthlib2/oauthdataprovider.php
new file mode 100644
index 0000000..1de88ce
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/oauthdataprovider.php
@@ -0,0 +1,113 @@
+profile = $profile;
+ $this->dialog = $dialog;
+ $this->accessToken = $accessToken;
+ $this->header = $header;
+ $this->request = $request;
+ }
+
+ public function getLoginUrl() {
+ $urlBuilder = [];
+ $urlBuilder[] = "client_id=" . $this->clientId;
+ $urlBuilder[] = "response_type=" . $this->responseType;
+ $urlBuilder[] = "scope=" . $this->scope;
+ $urlBuilder[] = "state=" . $this->state;
+ $urlBuilder[] = "redirect_uri=" . urlencode($this->redirectURL);
+ return $this->dialog . "?" . implode("&", $urlBuilder);
+ }
+
+ protected function getToken() {
+ $tokenBuilder = [];
+ $tokenBuilder["client_id"] = $this->clientId;
+ $tokenBuilder["client_secret"] = $this->client_secret;
+ $tokenBuilder["grant_type"] = "authorization_code";
+ $tokenBuilder["redirect_uri"] = htmlspecialchars($this->redirectURL);
+ $tokenBuilder["code"] = $this->request["code"];
+ $curl = new ccurl($this->accessToken);
+ $curl->setPost($tokenBuilder);
+ $curl->createCurl();
+ return (string)$curl;
+ }
+
+ protected function parseToken() {
+ $token = $this->getToken();
+ $convertedToken = json_decode($token, true);
+ if (!$convertedToken) {
+ $realToken = $token;
+ } else {
+ $realToken = $convertedToken["access_token"];
+ }
+
+ return $realToken;
+ }
+
+ public function getProfile() {
+ $token = $this->parseToken();
+
+ $profileUrl = $this->profile . "=" . $token;
+ $curl = new ccurl($profileUrl);
+ $curl->addHeader($this->header . " " . $token);
+ $curl->createCurl();
+ $this->profileData = json_decode((string)$curl, true);
+ return (string)$curl;
+ }
+
+ public function getEmail() {
+ return null;
+ }
+
+ public function getFirstName() {
+ return null;
+ }
+
+ public function getLastName() {
+ return null;
+ }
+
+ public function getGender() {
+ return null;
+ }
+
+ public function getId() {
+ return null;
+ }
+
+ public function getRawProfile() {
+ return $this->profileData;
+ }
+
+ public function getSource() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/web/system/vendor/phpoauthlib2/providers/facebookauthprovider.php b/web/system/vendor/phpoauthlib2/providers/facebookauthprovider.php
new file mode 100644
index 0000000..3dba4de
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/providers/facebookauthprovider.php
@@ -0,0 +1,70 @@
+client_secret = $conf["client_secret"];
+ $this->redirectURL = $conf["redirect_uri"];
+ $this->clientId = $conf["client_id"];
+ $tempScopes = [];
+ foreach($scopes as $scope) {
+ switch ($scope) {
+ case OAUTH_SCOPES::EMAIL:
+ $tempScopes[] = "email";
+ }
+ }
+ $tempScopes[] = "public_profile";
+ $this->scope = implode(" ", $tempScopes);
+ }
+
+ public function getEmail() {
+ return $this->profileData["email"];
+ }
+
+ public function getFirstName() {
+ return $this->profileData["first_name"];
+ }
+
+ public function getLastName() {
+ return $this->profileData["last_name"];
+ }
+
+ public function getId() {
+ return $this->profileData["id"];
+ }
+
+ public function getSource() {
+ return "FACEBOOK";
+ }
+
+ public function parseToken() {
+ $token = $this->getToken();
+ return explode("=", $token)[1];
+ }
+
+ public function getProfile() {
+ $token = $this->parseToken();
+ $profileUrl = $this->profile . "?fields=first_name,last_name,name,email,age_range&access_token=" . $token;
+ $curl = new ccurl($profileUrl);
+ $curl->createCurl();
+ $ret = (string)$curl;
+ $this->profileData = json_decode($ret, true);
+ return $ret;
+ }
+
+}
\ No newline at end of file
diff --git a/web/system/vendor/phpoauthlib2/providers/googleauthprovider.php b/web/system/vendor/phpoauthlib2/providers/googleauthprovider.php
new file mode 100644
index 0000000..f3302e6
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/providers/googleauthprovider.php
@@ -0,0 +1,56 @@
+client_secret = $conf["client_secret"];
+ $this->redirectURL = $conf["redirect_uri"];
+ $this->clientId = $conf["client_id"];
+
+ $tmpScopes = [];
+ foreach($scopes as $scope) {
+ switch ($scope) {
+ case OAUTH_SCOPES::EMAIL:
+ $tmpScopes[] = "https://www.googleapis.com/auth/userinfo.email";
+ }
+ }
+
+ $this->scope = implode(" ", $tmpScopes);
+ }
+
+ public function getEmail() {
+ return $this->profileData["email"];
+ }
+
+ public function getFirstName() {
+ return $this->profileData["given_name"];
+ }
+
+ public function getLastName() {
+ return $this->profileData["family_name"];
+ }
+
+ public function getGender() {
+ return $this->profileData["gender"];
+ }
+
+ public function getId() {
+ return $this->profileData["id"];
+ }
+
+ public function getSource() {
+ return "GOOGLE";
+ }
+}
\ No newline at end of file
diff --git a/web/system/vendor/phpoauthlib2/readme.md b/web/system/vendor/phpoauthlib2/readme.md
new file mode 100644
index 0000000..2acf8c8
--- /dev/null
+++ b/web/system/vendor/phpoauthlib2/readme.md
@@ -0,0 +1,86 @@
+# phpoauthlib2
+
+phpoauthlib2 is another OAuth 2.0 library for PHP. The goal of the project is to make it as easy as possible to integrate OAuth into your web application.
+
+You can think of phpoauthlib2 as a combination of ideas from the following projects:
+
+- PHPoAuthLib
+- li3_socialauth
+- oauth-4-laravel
+- PHPoAuthUserData
+
+All wrapped in one simple library.
+
+# Why phpoauthlib2?
+
+Or more specifically why "2"?
+
+For me this is version 2.0. Originally I developed this in private for PHP and it worked but after a refactoring to Django/Python (Python version coming soon to a pip repository near you) then I ported it back to PHP.
+
+# How to use
+
+It's very easy to use this library. Examine the following line -
+
+ $authProvider = new GoogleAuthProvider($_GET, [
+ "client_id" => "apps.googleusercontent.com",
+ "client_secret" => "",
+ "redirect_uri" => "http://example.com/phpoauthlib2/example.php"
+ ]);
+
+client_id and client_secret are provided by the OAauth provider (in this case Google) and the redirect_uri is where you want to the user to end up on successful login. It should go without saying that client_id and client_secret should be kept private - you should avoid committing them a public place like github (yes - people have services running and monitoring for people who commit credentials. Don't believe me? Commit your Amazon AWS keys and see how fast people will spin up VMs). The library will handle the verification and present you with some simple base methods to extract data you might be interested in or the ability to work with the entire OAuth data.
+
+ $oauth = new OAuth($authProvider, $_GET);
+
+OAuth is really a wrapper to do the verification check. In both this line and the previous one we are passing $_GET but phpoauthlib2 can accept any request array from your framework (provided your framework can emit the GET request as an array - which I know at least Symfony can do this).
+
+ $check = $oauth->check();
+
+The check method will return true or a string. Not ideal but I couldn't think of any simpler way to do it (obviously not a problem in a lose typed language - but I don't personally like mixing return types). true indicates that the user successfully logged in and you have access to the user's information. A string indicates that you need to redirect them to the OAuth provider to login (the string itself is the redirect URL).
+
+ if ($check === true) {
+ echo "Hello - " . $authProvider->getFirstName();
+ echo "
Your email is - " . $authProvider->getEmail();
+ } else {
+ header("Location: " . $check);
+ }
+
+This library is designed to be very minimal - so you need to decide how to hook into the login subsystem of your web application. In the example file - it's checking to make sure that the login was successful and then can call $authProvider->getXXX (such as getFirstName and getEmail in this example) and the provider class will return those fields from the raw profile data so you don't have to worry about it.
+
+The work flow to integrate to your system is usually:
+
+ if ($check === true) {
+ $mySystem->login($authProvider->getEmail()); // which sets a cookie or session that they logged in with this specific user
+ header("Location: http://example.com/yoursystem/user.php"); // The line above logs them in to your system - then immediately bounce back to your system and potentially send them straight to their user dashboard
+
+The reasoning behind the getXXX methods is to provide some commonality between providers. That way you can present a OAuth login prompt for different services to the user and you can just call $provider->getEmail() to get their email without having to worry about the actual field that the OAuth provider decided to put it in.
+
+If after you have verified the login was successful you may call
+
+ $provider->getRawProfile();
+
+To return the raw return from the OAuth provider (which will be an associative array).
+
+# Google
+
+To get OAuth credentials for Google just go to this URL: https://console.developers.google.com/
+
+And create a project (which is free) and go to APIs & auth -> Credentials.
+If you are creating a new project - it may complain that you need to setup the OAuth consent screen. Do this and return to the credentials section and you should be able to setup the project.
+
+Add credentials -> OAuth 2.0 client ID
+Then select Web application
+
+It is very important that you input a correct authorized redirect URI. This will be where the user will be sent back on successful login.
+
+# License
+
+I am licensing this under the MIT license. Which essentially grants you the right TDWTFYWWI (to do whatever the f you want with it) - assuming that you acknowledge that I don't provide a warranty.
+
+# What this library is/is not
+
+- This library is a simple interface to use PHP OAuth 2.0 in your web application.
+- This library is designed to be as flexible as possible to use in any framework.
+
+- This library is not designed to hold your hand to secure your client_id, client_secret, or other data.
+- This library is not designed to be specific to a certain framework.
+- This library is not designed to be abstract. The only class you should ever have to extend is OAuthDataProvider - and that is to create a "provider" for different OAuth providers (which merely contains the URLs to send for login, where to query for user data and normalizing data).
\ No newline at end of file