").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window);
7 |
--------------------------------------------------------------------------------
/src/main/webapp/resources/theme1/js/main.js:
--------------------------------------------------------------------------------
1 | jQuery(document).ready(function($) {
2 |
3 | $('#msg').html("This is updated by jQuery")
4 |
5 | });
6 |
--------------------------------------------------------------------------------
/src/test/java/com/mkyong/web/controller/ExplorativeTestNoauto.java:
--------------------------------------------------------------------------------
1 | package com.mkyong.web.controller;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.InputStream;
5 | import java.net.MalformedURLException;
6 | import java.net.URL;
7 | import java.util.Arrays;
8 | import org.junit.Test;
9 | import static org.junit.Assert.*;
10 | import org.junit.Before;
11 | import org.springframework.core.io.Resource;
12 | import org.springframework.web.context.support.ServletContextResource;
13 | import static org.springframework.web.servlet.resource.ILoveProtectedAccess.forceCallGetResource;
14 | import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
15 |
16 | public class ExplorativeTestNoauto {
17 |
18 | private final ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
19 | private final Resource resource = new ServletContextResource(new AllResourcesExistAndReadableFakeContext(), "/resources/theme1/");
20 |
21 | @Before
22 | public void setup() {
23 | handler.setLocations(Arrays.asList(resource));
24 | }
25 |
26 | @Test
27 | public void processPath() throws Exception {
28 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest("/foo/bar")));
29 | }
30 |
31 | @Test
32 | public void processPath1() throws Exception {
33 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest("/foo/bar")));
34 | }
35 |
36 | @Test
37 | public void processPath2() throws Exception {
38 | assertEquals("foo/bar", forceCallGetResource(handler, new DummyAttrRequest("foo/bar")));
39 | }
40 |
41 | @Test
42 | public void processPath3() throws Exception {
43 | // leading whitespace control characters (00-1F)
44 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest(" /foo/bar")));
45 | }
46 |
47 | @Test
48 | public void processPath4() throws Exception {
49 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest((char) 1 + "/foo/bar")));
50 | // 400 Illegal character (jetty?)
51 | }
52 |
53 | @Test
54 | public void processPath5() throws Exception {
55 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest((char) 31 + "/foo/bar")));
56 | // 400 Illegal character (jetty?)
57 | }
58 |
59 | @Test
60 | public void processPath6() throws Exception {
61 | assertEquals("foo/bar", forceCallGetResource(handler, new DummyAttrRequest(" foo/bar")));
62 | // 400 unknown version (foo/bar is treated as the version string lol)
63 | }
64 |
65 | @Test
66 | public void processPath7() throws Exception {
67 | assertEquals("foo/bar", forceCallGetResource(handler, new DummyAttrRequest((char) 31 + "foo/bar")));
68 | // 400 Illegal character (jetty?)
69 | }
70 |
71 | @Test
72 | public void processPath8() throws Exception {
73 | // leading control character 0x7F (DEL)
74 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest((char) 127 + "/foo/bar")));
75 | // this goes through but apparently not interpreted when resolving paths?
76 | }
77 |
78 | @Test
79 | public void processPath9() throws Exception {
80 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest((char) 127 + "/foo/bar")));
81 | }
82 |
83 | @Test
84 | public void processPath10() throws Exception {
85 | // leading control and '/' characters
86 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest(" / foo/bar")));
87 | }
88 |
89 | @Test
90 | public void processPath11() throws Exception {
91 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest(" / / foo/bar")));
92 | }
93 |
94 | @Test
95 | public void processPath12() throws Exception {
96 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest(" // /// //// foo/bar")));
97 | }
98 |
99 | @Test
100 | public void processPath13() throws Exception {
101 | assertEquals("/foo/bar", forceCallGetResource(handler, new DummyAttrRequest((char) 1 + " / " + (char) 127 + " // foo/bar")));
102 | }
103 |
104 | @Test
105 | public void processPath14() throws Exception {
106 | // root ot empty path
107 | }
108 |
109 | @Test
110 | public void processPath15() throws Exception {
111 | assertEquals("", forceCallGetResource(handler, new DummyAttrRequest(" ")));
112 | }
113 |
114 | @Test
115 | public void processPath16() throws Exception {
116 | assertEquals("/", forceCallGetResource(handler, new DummyAttrRequest("/")));
117 | }
118 |
119 | @Test
120 | public void processPath17() throws Exception {
121 | assertEquals("/", forceCallGetResource(handler, new DummyAttrRequest("///")));
122 | }
123 |
124 | @Test
125 | public void processPath18() throws Exception {
126 | assertEquals("/", forceCallGetResource(handler, new DummyAttrRequest("/ / / ")));
127 |
128 | }
129 |
130 | public static class DummyAttrRequest extends FailingRequest {
131 |
132 | private final String attr;
133 |
134 | public DummyAttrRequest(String attr) {
135 | this.attr = attr;
136 | }
137 |
138 | @Override
139 | public Object getAttribute(String string) {
140 | return attr;
141 | }
142 |
143 | }
144 |
145 | public static class AllResourcesExistAndReadableFakeContext extends FailingServletContext {
146 |
147 | @Override
148 | public InputStream getResourceAsStream(String string) {
149 | //anything that closes w/o error is fine
150 | return new ByteArrayInputStream(new byte[]{});
151 | }
152 |
153 | @Override
154 | public URL getResource(String string) throws MalformedURLException {
155 | //anything notnull is fine
156 | return new URL("file:///");
157 | }
158 |
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/test/java/com/mkyong/web/controller/FailingRequest.java:
--------------------------------------------------------------------------------
1 | package com.mkyong.web.controller;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.UnsupportedEncodingException;
6 | import java.security.Principal;
7 | import java.util.Collection;
8 | import java.util.Enumeration;
9 | import java.util.Locale;
10 | import java.util.Map;
11 | import javax.servlet.AsyncContext;
12 | import javax.servlet.DispatcherType;
13 | import javax.servlet.RequestDispatcher;
14 | import javax.servlet.ServletContext;
15 | import javax.servlet.ServletException;
16 | import javax.servlet.ServletInputStream;
17 | import javax.servlet.ServletRequest;
18 | import javax.servlet.ServletResponse;
19 | import javax.servlet.http.Cookie;
20 | import javax.servlet.http.HttpServletRequest;
21 | import javax.servlet.http.HttpServletResponse;
22 | import javax.servlet.http.HttpSession;
23 | import javax.servlet.http.HttpUpgradeHandler;
24 | import javax.servlet.http.Part;
25 |
26 | public class FailingRequest implements HttpServletRequest {
27 |
28 | @Override
29 | public String getAuthType() {
30 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
31 | }
32 |
33 | @Override
34 | public Cookie[] getCookies() {
35 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
36 | }
37 |
38 | @Override
39 | public long getDateHeader(String string) {
40 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
41 | }
42 |
43 | @Override
44 | public String getHeader(String string) {
45 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
46 | }
47 |
48 | @Override
49 | public Enumeration getHeaders(String string) {
50 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
51 | }
52 |
53 | @Override
54 | public Enumeration getHeaderNames() {
55 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
56 | }
57 |
58 | @Override
59 | public int getIntHeader(String string) {
60 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
61 | }
62 |
63 | @Override
64 | public String getMethod() {
65 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
66 | }
67 |
68 | @Override
69 | public String getPathInfo() {
70 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
71 | }
72 |
73 | @Override
74 | public String getPathTranslated() {
75 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
76 | }
77 |
78 | @Override
79 | public String getContextPath() {
80 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
81 | }
82 |
83 | @Override
84 | public String getQueryString() {
85 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
86 | }
87 |
88 | @Override
89 | public String getRemoteUser() {
90 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
91 | }
92 |
93 | @Override
94 | public boolean isUserInRole(String string) {
95 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
96 | }
97 |
98 | @Override
99 | public Principal getUserPrincipal() {
100 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
101 | }
102 |
103 | @Override
104 | public String getRequestedSessionId() {
105 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
106 | }
107 |
108 | @Override
109 | public String getRequestURI() {
110 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
111 | }
112 |
113 | @Override
114 | public StringBuffer getRequestURL() {
115 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
116 | }
117 |
118 | @Override
119 | public String getServletPath() {
120 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
121 | }
122 |
123 | @Override
124 | public HttpSession getSession(boolean bln) {
125 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
126 | }
127 |
128 | @Override
129 | public HttpSession getSession() {
130 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
131 | }
132 |
133 | @Override
134 | public boolean isRequestedSessionIdValid() {
135 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
136 | }
137 |
138 | @Override
139 | public boolean isRequestedSessionIdFromCookie() {
140 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
141 | }
142 |
143 | @Override
144 | public boolean isRequestedSessionIdFromURL() {
145 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
146 | }
147 |
148 | @Override
149 | public boolean isRequestedSessionIdFromUrl() {
150 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
151 | }
152 |
153 | @Override
154 | public Object getAttribute(String string) {
155 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
156 | }
157 |
158 | @Override
159 | public Enumeration getAttributeNames() {
160 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
161 | }
162 |
163 | @Override
164 | public String getCharacterEncoding() {
165 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
166 | }
167 |
168 | @Override
169 | public void setCharacterEncoding(String string) throws UnsupportedEncodingException {
170 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
171 | }
172 |
173 | @Override
174 | public int getContentLength() {
175 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
176 | }
177 |
178 | @Override
179 | public String getContentType() {
180 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
181 | }
182 |
183 | @Override
184 | public ServletInputStream getInputStream() throws IOException {
185 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
186 | }
187 |
188 | @Override
189 | public String getParameter(String string) {
190 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
191 | }
192 |
193 | @Override
194 | public Enumeration getParameterNames() {
195 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
196 | }
197 |
198 | @Override
199 | public String[] getParameterValues(String string) {
200 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
201 | }
202 |
203 | @Override
204 | public Map getParameterMap() {
205 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
206 | }
207 |
208 | @Override
209 | public String getProtocol() {
210 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
211 | }
212 |
213 | @Override
214 | public String getScheme() {
215 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
216 | }
217 |
218 | @Override
219 | public String getServerName() {
220 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
221 | }
222 |
223 | @Override
224 | public int getServerPort() {
225 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
226 | }
227 |
228 | @Override
229 | public BufferedReader getReader() throws IOException {
230 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
231 | }
232 |
233 | @Override
234 | public String getRemoteAddr() {
235 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
236 | }
237 |
238 | @Override
239 | public String getRemoteHost() {
240 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
241 | }
242 |
243 | @Override
244 | public void setAttribute(String string, Object o) {
245 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
246 | }
247 |
248 | @Override
249 | public void removeAttribute(String string) {
250 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
251 | }
252 |
253 | @Override
254 | public Locale getLocale() {
255 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
256 | }
257 |
258 | @Override
259 | public Enumeration getLocales() {
260 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
261 | }
262 |
263 | @Override
264 | public boolean isSecure() {
265 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
266 | }
267 |
268 | @Override
269 | public RequestDispatcher getRequestDispatcher(String string) {
270 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
271 | }
272 |
273 | @Override
274 | public String getRealPath(String string) {
275 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
276 | }
277 |
278 | @Override
279 | public int getRemotePort() {
280 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
281 | }
282 |
283 | @Override
284 | public String getLocalName() {
285 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
286 | }
287 |
288 | @Override
289 | public String getLocalAddr() {
290 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
291 | }
292 |
293 | @Override
294 | public int getLocalPort() {
295 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
296 | }
297 |
298 | @Override
299 | public String changeSessionId() {
300 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
301 | }
302 |
303 | @Override
304 | public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
305 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
306 | }
307 |
308 | @Override
309 | public void login(String username, String password) throws ServletException {
310 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
311 | }
312 |
313 | @Override
314 | public void logout() throws ServletException {
315 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
316 | }
317 |
318 | @Override
319 | public Collection
getParts() throws IOException, ServletException {
320 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
321 | }
322 |
323 | @Override
324 | public Part getPart(String name) throws IOException, ServletException {
325 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
326 | }
327 |
328 | @Override
329 | public T upgrade(Class handlerClass) throws IOException, ServletException {
330 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
331 | }
332 |
333 | @Override
334 | public long getContentLengthLong() {
335 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
336 | }
337 |
338 | @Override
339 | public ServletContext getServletContext() {
340 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
341 | }
342 |
343 | @Override
344 | public AsyncContext startAsync() throws IllegalStateException {
345 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
346 | }
347 |
348 | @Override
349 | public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
350 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
351 | }
352 |
353 | @Override
354 | public boolean isAsyncStarted() {
355 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
356 | }
357 |
358 | @Override
359 | public boolean isAsyncSupported() {
360 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
361 | }
362 |
363 | @Override
364 | public AsyncContext getAsyncContext() {
365 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
366 | }
367 |
368 | @Override
369 | public DispatcherType getDispatcherType() {
370 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
371 | }
372 |
373 | }
374 |
--------------------------------------------------------------------------------
/src/test/java/com/mkyong/web/controller/FailingServletContext.java:
--------------------------------------------------------------------------------
1 | package com.mkyong.web.controller;
2 |
3 | import java.io.InputStream;
4 | import java.net.MalformedURLException;
5 | import java.net.URL;
6 | import java.util.Enumeration;
7 | import java.util.EventListener;
8 | import java.util.Map;
9 | import java.util.Set;
10 | import javax.servlet.Filter;
11 | import javax.servlet.FilterRegistration;
12 | import javax.servlet.RequestDispatcher;
13 | import javax.servlet.Servlet;
14 | import javax.servlet.ServletContext;
15 | import javax.servlet.ServletException;
16 | import javax.servlet.ServletRegistration;
17 | import javax.servlet.SessionCookieConfig;
18 | import javax.servlet.SessionTrackingMode;
19 | import javax.servlet.descriptor.JspConfigDescriptor;
20 |
21 | public class FailingServletContext implements ServletContext {
22 |
23 | @Override
24 | public String getContextPath() {
25 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
26 | }
27 |
28 | @Override
29 | public ServletContext getContext(String string) {
30 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
31 | }
32 |
33 | @Override
34 | public int getMajorVersion() {
35 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
36 | }
37 |
38 | @Override
39 | public int getMinorVersion() {
40 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
41 | }
42 |
43 | @Override
44 | public String getMimeType(String string) {
45 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
46 | }
47 |
48 | @Override
49 | public Set getResourcePaths(String string) {
50 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
51 | }
52 |
53 | @Override
54 | public URL getResource(String string) throws MalformedURLException {
55 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
56 | }
57 |
58 | @Override
59 | public InputStream getResourceAsStream(String string) {
60 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
61 | }
62 |
63 | @Override
64 | public RequestDispatcher getRequestDispatcher(String string) {
65 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
66 | }
67 |
68 | @Override
69 | public RequestDispatcher getNamedDispatcher(String string) {
70 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
71 | }
72 |
73 | @Override
74 | public Servlet getServlet(String string) throws ServletException {
75 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
76 | }
77 |
78 | @Override
79 | public Enumeration getServlets() {
80 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
81 | }
82 |
83 | @Override
84 | public Enumeration getServletNames() {
85 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
86 | }
87 |
88 | @Override
89 | public void log(String string) {
90 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
91 | }
92 |
93 | @Override
94 | public void log(Exception excptn, String string) {
95 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
96 | }
97 |
98 | @Override
99 | public void log(String string, Throwable thrwbl) {
100 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
101 | }
102 |
103 | @Override
104 | public String getRealPath(String string) {
105 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
106 | }
107 |
108 | @Override
109 | public String getServerInfo() {
110 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
111 | }
112 |
113 | @Override
114 | public String getInitParameter(String string) {
115 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
116 | }
117 |
118 | @Override
119 | public Enumeration getInitParameterNames() {
120 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
121 | }
122 |
123 | @Override
124 | public Object getAttribute(String string) {
125 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
126 | }
127 |
128 | @Override
129 | public Enumeration getAttributeNames() {
130 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
131 | }
132 |
133 | @Override
134 | public void setAttribute(String string, Object o) {
135 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
136 | }
137 |
138 | @Override
139 | public void removeAttribute(String string) {
140 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
141 | }
142 |
143 | @Override
144 | public String getServletContextName() {
145 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
146 | }
147 |
148 | @Override
149 | public int getEffectiveMajorVersion() {
150 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
151 | }
152 |
153 | @Override
154 | public int getEffectiveMinorVersion() {
155 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
156 | }
157 |
158 | @Override
159 | public boolean setInitParameter(String name, String value) {
160 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
161 | }
162 |
163 | @Override
164 | public ServletRegistration.Dynamic addServlet(String servletName, String className) {
165 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
166 | }
167 |
168 | @Override
169 | public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
170 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
171 | }
172 |
173 | @Override
174 | public ServletRegistration.Dynamic addServlet(String servletName, Class extends Servlet> servletClass) {
175 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
176 | }
177 |
178 | @Override
179 | public T createServlet(Class clazz) throws ServletException {
180 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
181 | }
182 |
183 | @Override
184 | public ServletRegistration getServletRegistration(String servletName) {
185 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
186 | }
187 |
188 | @Override
189 | public Map getServletRegistrations() {
190 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
191 | }
192 |
193 | @Override
194 | public FilterRegistration.Dynamic addFilter(String filterName, String className) {
195 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
196 | }
197 |
198 | @Override
199 | public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
200 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
201 | }
202 |
203 | @Override
204 | public FilterRegistration.Dynamic addFilter(String filterName, Class extends Filter> filterClass) {
205 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
206 | }
207 |
208 | @Override
209 | public T createFilter(Class clazz) throws ServletException {
210 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
211 | }
212 |
213 | @Override
214 | public FilterRegistration getFilterRegistration(String filterName) {
215 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
216 | }
217 |
218 | @Override
219 | public Map getFilterRegistrations() {
220 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
221 | }
222 |
223 | @Override
224 | public SessionCookieConfig getSessionCookieConfig() {
225 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
226 | }
227 |
228 | @Override
229 | public void setSessionTrackingModes(Set sessionTrackingModes) {
230 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
231 | }
232 |
233 | @Override
234 | public Set getDefaultSessionTrackingModes() {
235 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
236 | }
237 |
238 | @Override
239 | public Set getEffectiveSessionTrackingModes() {
240 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
241 | }
242 |
243 | @Override
244 | public void addListener(String className) {
245 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
246 | }
247 |
248 | @Override
249 | public void addListener(T t) {
250 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
251 | }
252 |
253 | @Override
254 | public void addListener(Class extends EventListener> listenerClass) {
255 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
256 | }
257 |
258 | @Override
259 | public T createListener(Class clazz) throws ServletException {
260 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
261 | }
262 |
263 | @Override
264 | public JspConfigDescriptor getJspConfigDescriptor() {
265 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
266 | }
267 |
268 | @Override
269 | public ClassLoader getClassLoader() {
270 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
271 | }
272 |
273 | @Override
274 | public void declareRoles(String... roleNames) {
275 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
276 | }
277 |
278 | @Override
279 | public String getVirtualServerName() {
280 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
281 | }
282 |
283 | }
284 |
--------------------------------------------------------------------------------
/src/test/java/com/mkyong/web/controller/NoautoTestInvalidPath.java:
--------------------------------------------------------------------------------
1 | package com.mkyong.web.controller;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Arrays;
5 | import java.util.List;
6 | import java.util.stream.Collectors;
7 | import java.util.stream.Stream;
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertTrue;
10 | import org.junit.Before;
11 | import org.junit.experimental.theories.DataPoints;
12 | import org.junit.experimental.theories.Theories;
13 | import org.junit.experimental.theories.Theory;
14 | import org.junit.runner.RunWith;
15 | import org.springframework.core.io.ClassPathResource;
16 | import org.springframework.core.io.Resource;
17 | import org.springframework.core.io.UrlResource;
18 | import org.springframework.mock.web.MockHttpServletRequest;
19 | import org.springframework.mock.web.MockHttpServletResponse;
20 | import org.springframework.mock.web.MockServletContext;
21 | import org.springframework.web.servlet.HandlerMapping;
22 | import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
23 | import tech.anima.tinytypes.StringTinyType;
24 |
25 | @RunWith(Theories.class)
26 | public class NoautoTestInvalidPath {
27 |
28 | private ResourceHttpRequestHandler handler;
29 |
30 | @Before
31 | public void setUp() {
32 | List resourcePaths = new ArrayList<>();
33 | resourcePaths.add(new ClassPathResource("test/", getClass()));
34 | resourcePaths.add(new ClassPathResource("testalternatepath/", getClass()));
35 | handler = new ResourceHttpRequestHandler();
36 | handler.setLocations(resourcePaths);
37 | handler.setCacheSeconds(3600);
38 | handler.setServletContext(new TestServletContext());
39 | }
40 |
41 | @DataPoints
42 | public static Th1[] urls = Stream.of(new String[]{
43 | "../testsecret/secret.txt",
44 | "test/../../testsecret/secret.txt",
45 | ":/../../testsecret/secret.txt"
46 | }).map(Th1::new).collect(Collectors.toList()).toArray(new Th1[]{});
47 |
48 | @Theory
49 | public void invalidPath1(Th1 path) throws Exception {
50 | MockHttpServletRequest request = new MockHttpServletRequest();
51 | request.setMethod("GET");
52 | MockHttpServletResponse response = new MockHttpServletResponse();
53 |
54 | Resource location = new ClassPathResource("test/", getClass());
55 | this.handler.setLocations(Arrays.asList(location));
56 |
57 | testInvalidPath(location, path.value, request, response);
58 | }
59 | @DataPoints
60 | public static Th2[] urls2 = Stream.of(new String[]{
61 | "file:" ,
62 | "/file:",
63 | "url:",
64 | "/url:",
65 | "/",
66 | "////../.." ,
67 | " " ,
68 | "/ ",
69 | "url:"
70 | }).map(Th2::new).collect(Collectors.toList()).toArray(new Th2[]{});
71 |
72 | @Theory
73 | public void invalidPath2(Th2 url) throws Exception {
74 | MockHttpServletRequest request = new MockHttpServletRequest();
75 | request.setMethod("GET");
76 | MockHttpServletResponse response = new MockHttpServletResponse();
77 |
78 | Resource location = new UrlResource(getClass().getResource("./test/"));
79 | this.handler.setLocations(Arrays.asList(location));
80 | Resource secretResource = new UrlResource(getClass().getResource("testsecret/secret.txt"));
81 | String secretPath = secretResource.getURL().getPath();
82 |
83 | testInvalidPath(location, url.value + secretPath, request, response);
84 |
85 | }
86 | @DataPoints
87 | public static Th3[] urls3 = Stream.of(new String[]{
88 | "/%2E%2E/testsecret/secret.txt",
89 | "/%2e%2e/testsecret/secret.txt"
90 | }).map(Th3::new).collect(Collectors.toList()).toArray(new Th3[]{});
91 |
92 | @Theory
93 | public void invalidPath3(Th3 url) throws Exception {
94 | MockHttpServletRequest request = new MockHttpServletRequest();
95 | request.setMethod("GET");
96 | MockHttpServletResponse response = new MockHttpServletResponse();
97 |
98 | Resource location = new UrlResource(getClass().getResource("./test/"));
99 | this.handler.setLocations(Arrays.asList(location));
100 | Resource secretResource = new UrlResource(getClass().getResource("testsecret/secret.txt"));
101 |
102 | testInvalidPath(location, url.value, request, response);
103 |
104 | }
105 |
106 | private void testInvalidPath(Resource location, String requestPath,
107 | MockHttpServletRequest request, MockHttpServletResponse response) throws Exception {
108 |
109 | request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, requestPath);
110 | response = new MockHttpServletResponse();
111 | this.handler.handleRequest(request, response);
112 | assertTrue(location.createRelative(requestPath).exists());
113 | assertEquals(404, response.getStatus());
114 | }
115 |
116 | private static class TestServletContext extends MockServletContext {
117 |
118 | @Override
119 | public String getMimeType(String filePath) {
120 | if (filePath.endsWith(".css")) {
121 | return "text/css";
122 | } else if (filePath.endsWith(".js")) {
123 | return "text/javascript";
124 | } else {
125 | return super.getMimeType(filePath);
126 | }
127 | }
128 | }
129 |
130 | public static class Th1 extends StringTinyType {
131 |
132 | public Th1(String value) {
133 | super(value);
134 | }
135 | }
136 |
137 | public static class Th2 extends StringTinyType {
138 |
139 | public Th2(String value) {
140 | super(value);
141 | }
142 | }
143 | public static class Th3 extends StringTinyType {
144 |
145 | public Th3(String value) {
146 | super(value);
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/web/servlet/resource/ILoveProtectedAccess.java:
--------------------------------------------------------------------------------
1 | package org.springframework.web.servlet.resource;
2 |
3 | import javax.servlet.http.HttpServletRequest;
4 | import org.springframework.core.io.Resource;
5 |
6 | public class ILoveProtectedAccess {
7 |
8 | public static Resource forceCallGetResource(ResourceHttpRequestHandler handler, HttpServletRequest req) {
9 | return handler.getResource(req);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/resources/com/mkyong/web/controller/test/bar.css:
--------------------------------------------------------------------------------
1 | h2 { color:white; }
--------------------------------------------------------------------------------
/src/test/resources/com/mkyong/web/controller/test/foo.css:
--------------------------------------------------------------------------------
1 | h1 { color:red; }
--------------------------------------------------------------------------------
/stealfile.sh:
--------------------------------------------------------------------------------
1 | curl http://localhost:8080/spring-css/resources/file:/etc/passwd -vvv
2 |
--------------------------------------------------------------------------------