uberdoc.html
1 <!DOCTYPE html> 2 <html><head><meta charset="utf-8" content="text/html" http-equiv="Content-Type" /><meta content="Django style templates for Clojure" name="description" /><style type="text/css">/** 3 * SyntaxHighlighter 4 * http://alexgorbatchev.com/SyntaxHighlighter 5 * 6 * SyntaxHighlighter is donationware. If you are using it, please donate. 7 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html 8 * 9 * @version 10 * 3.0.83 (July 02 2010) 11 * 12 * @copyright 13 * Copyright (C) 2004-2010 Alex Gorbatchev. 14 * 15 * @license 16 * Dual licensed under the MIT and GPL licenses. 17 */ 18 .syntaxhighlighter a, 19 .syntaxhighlighter div, 20 .syntaxhighlighter code, 21 .syntaxhighlighter table, 22 .syntaxhighlighter table td, 23 .syntaxhighlighter table tr, 24 .syntaxhighlighter table tbody, 25 .syntaxhighlighter table thead, 26 .syntaxhighlighter table caption, 27 .syntaxhighlighter textarea { 28 -moz-border-radius: 0 0 0 0 !important; 29 -webkit-border-radius: 0 0 0 0 !important; 30 background: none !important; 31 border: 0 !important; 32 bottom: auto !important; 33 float: none !important; 34 height: auto !important; 35 left: auto !important; 36 line-height: 1.1em !important; 37 /* margin: 0 !important; */ 38 outline: 0 !important; 39 overflow: visible !important; 40 padding: 0 !important; 41 position: static !important; 42 right: auto !important; 43 text-align: left !important; 44 top: auto !important; 45 vertical-align: baseline !important; 46 width: auto !important; 47 box-sizing: content-box !important; 48 font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; 49 font-weight: normal !important; 50 font-style: normal !important; 51 min-height: inherit !important; 52 min-height: auto !important; 53 } 54 55 .syntaxhighlighter { 56 /* width: 100% !important; */ 57 margin: 1em 0 1em 0 !important; 58 position: relative !important; 59 overflow: auto !important; 60 } 61 .syntaxhighlighter.source { 62 overflow: hidden !important; 63 } 64 .syntaxhighlighter .bold { 65 font-weight: bold !important; 66 } 67 .syntaxhighlighter .italic { 68 font-style: italic !important; 69 } 70 .syntaxhighlighter .line { 71 white-space: pre !important; 72 } 73 .syntaxhighlighter table { 74 /* width: 100% !important;*/ 75 } 76 .syntaxhighlighter table caption { 77 text-align: left !important; 78 padding: .5em 0 0.5em 1em !important; 79 } 80 .syntaxhighlighter table td.code { 81 width: 100% !important; 82 } 83 .syntaxhighlighter table td.code .container { 84 position: relative !important; 85 } 86 .syntaxhighlighter table td.code .container textarea { 87 box-sizing: border-box !important; 88 position: absolute !important; 89 left: 0 !important; 90 top: 0 !important; 91 width: 100% !important; 92 height: 100% !important; 93 border: none !important; 94 background: white !important; 95 padding-left: 1em !important; 96 overflow: hidden !important; 97 white-space: pre !important; 98 } 99 .syntaxhighlighter table td.gutter .line { 100 text-align: right !important; 101 padding: 0 0.5em 0 1em !important; 102 } 103 .syntaxhighlighter table td.code .line { 104 padding: 0 1em !important; 105 } 106 .syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { 107 padding-left: 0em !important; 108 } 109 .syntaxhighlighter.show { 110 display: block !important; 111 } 112 .syntaxhighlighter.collapsed table { 113 display: none !important; 114 } 115 .syntaxhighlighter.collapsed .toolbar { 116 display: none; 117 /* padding: 0.1em 0.8em 0em 0.8em !important; 118 font-size: 1em !important; 119 position: static !important; 120 width: auto !important; 121 height: auto !important;*/ 122 } 123 .syntaxhighlighter.collapsed .toolbar span { 124 display: inline !important; 125 margin-right: 1em !important; 126 } 127 .syntaxhighlighter.collapsed .toolbar span a { 128 padding: 0 !important; 129 display: none !important; 130 } 131 .syntaxhighlighter.collapsed .toolbar span a.expandSource { 132 display: inline !important; 133 } 134 .syntaxhighlighter .toolbar { 135 display: none; 136 /* position: absolute !important; 137 right: 1px !important; 138 top: 1px !important; 139 width: 11px !important; 140 height: 11px !important; 141 font-size: 10px !important; 142 z-index: 10 !important;*/ 143 } 144 .syntaxhighlighter .toolbar span.title { 145 display: inline !important; 146 } 147 .syntaxhighlighter .toolbar a { 148 display: block !important; 149 text-align: center !important; 150 text-decoration: none !important; 151 padding-top: 1px !important; 152 } 153 .syntaxhighlighter .toolbar a.expandSource { 154 display: none !important; 155 } 156 .syntaxhighlighter.ie { 157 font-size: .9em !important; 158 padding: 1px 0 1px 0 !important; 159 } 160 .syntaxhighlighter.ie .toolbar { 161 line-height: 8px !important; 162 } 163 .syntaxhighlighter.ie .toolbar a { 164 padding-top: 0px !important; 165 } 166 .syntaxhighlighter.printing .line.alt1 .content, 167 .syntaxhighlighter.printing .line.alt2 .content, 168 .syntaxhighlighter.printing .line.highlighted .number, 169 .syntaxhighlighter.printing .line.highlighted.alt1 .content, 170 .syntaxhighlighter.printing .line.highlighted.alt2 .content { 171 background: none !important; 172 } 173 .syntaxhighlighter.printing .line .number { 174 color: #bbbbbb !important; 175 } 176 .syntaxhighlighter.printing .line .content { 177 color: black !important; 178 } 179 .syntaxhighlighter.printing .toolbar { 180 display: none !important; 181 } 182 .syntaxhighlighter.printing a { 183 text-decoration: none !important; 184 } 185 .syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { 186 color: black !important; 187 } 188 .syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { 189 color: #008200 !important; 190 } 191 .syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { 192 color: blue !important; 193 } 194 .syntaxhighlighter.printing .keyword { 195 color: #006699 !important; 196 font-weight: bold !important; 197 } 198 .syntaxhighlighter.printing .preprocessor { 199 color: gray !important; 200 } 201 .syntaxhighlighter.printing .variable { 202 color: #aa7700 !important; 203 } 204 .syntaxhighlighter.printing .value { 205 color: #009900 !important; 206 } 207 .syntaxhighlighter.printing .functions { 208 color: #ff1493 !important; 209 } 210 .syntaxhighlighter.printing .constants { 211 color: #0066cc !important; 212 } 213 .syntaxhighlighter.printing .script { 214 font-weight: bold !important; 215 } 216 .syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { 217 color: gray !important; 218 } 219 .syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { 220 color: #ff1493 !important; 221 } 222 .syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { 223 color: red !important; 224 } 225 .syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { 226 color: black !important; 227 } 228 </style><style type="text/css">.syntaxhighlighter{overflow:hidden !important;}</style><style type="text/css">/** 229 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html 230 * 231 * @version 232 * 3.0.83 (July 02 2010) 233 * 234 * @copyright 235 * Copyright (C) 2004-2010 Alex Gorbatchev. 236 * 237 * @license 238 * Dual licensed under the MIT and GPL licenses. 239 */ 240 .syntaxhighlighter { 241 background-color: transparent !important; 242 } 243 .syntaxhighlighter .line.alt1 { 244 background-color: transparent !important; 245 } 246 .syntaxhighlighter .line.alt2 { 247 background-color: transparent !important; 248 } 249 .syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { 250 background-color: #c3defe !important; 251 } 252 .syntaxhighlighter .line.highlighted.number { 253 color: white !important; 254 } 255 .syntaxhighlighter table caption { 256 color: black !important; 257 } 258 .syntaxhighlighter .gutter { 259 color: #787878 !important; 260 } 261 .syntaxhighlighter .gutter .line { 262 border-right: 3px solid #d4d0c8 !important; 263 } 264 .syntaxhighlighter .gutter .line.highlighted { 265 background-color: #d4d0c8 !important; 266 color: white !important; 267 } 268 .syntaxhighlighter.printing .line .content { 269 border: none !important; 270 } 271 .syntaxhighlighter.collapsed { 272 overflow: visible !important; 273 } 274 .syntaxhighlighter.collapsed .toolbar { 275 color: #3f5fbf !important; 276 background: white !important; 277 border: 1px solid #d4d0c8 !important; 278 } 279 .syntaxhighlighter.collapsed .toolbar a { 280 color: #3f5fbf !important; 281 } 282 .syntaxhighlighter.collapsed .toolbar a:hover { 283 color: #aa7700 !important; 284 } 285 .syntaxhighlighter .toolbar { 286 color: #a0a0a0 !important; 287 background: #d4d0c8 !important; 288 border: none !important; 289 } 290 .syntaxhighlighter .toolbar a { 291 color: #a0a0a0 !important; 292 } 293 .syntaxhighlighter .toolbar a:hover { 294 color: red !important; 295 } 296 .syntaxhighlighter .plain, .syntaxhighlighter .plain a { 297 color: black !important; 298 } 299 .syntaxhighlighter .comments, .syntaxhighlighter .comments a { 300 color: #3f5fbf !important; 301 } 302 .syntaxhighlighter .string, .syntaxhighlighter .string a { 303 color: #2a00ff !important; 304 } 305 .syntaxhighlighter .keyword { 306 color: #7f0055 !important; 307 } 308 .syntaxhighlighter .preprocessor { 309 color: #646464 !important; 310 } 311 .syntaxhighlighter .variable { 312 color: #aa7700 !important; 313 } 314 .syntaxhighlighter .value { 315 color: #009900 !important; 316 } 317 .syntaxhighlighter .functions { 318 color: #ff1493 !important; 319 } 320 .syntaxhighlighter .constants { 321 color: #0066cc !important; 322 } 323 .syntaxhighlighter .script { 324 font-weight: bold !important; 325 color: #7f0055 !important; 326 background-color: none !important; 327 } 328 .syntaxhighlighter .color1, .syntaxhighlighter .color1 a { 329 color: gray !important; 330 } 331 .syntaxhighlighter .color2, .syntaxhighlighter .color2 a { 332 color: #ff1493 !important; 333 } 334 .syntaxhighlighter .color3, .syntaxhighlighter .color3 a { 335 color: red !important; 336 } 337 338 .syntaxhighlighter .xml .keyword { 339 color: #3f7f7f !important; 340 font-weight: normal !important; 341 } 342 .syntaxhighlighter .xml .color1, .syntaxhighlighter .xml .color1 a { 343 color: #7f007f !important; 344 } 345 .syntaxhighlighter .xml .string { 346 font-style: italic !important; 347 color: #2a00ff !important; 348 } 349 350 .clojure.syntaxhighlighter .invalid { 351 background-color: #FAA !important; 352 } 353 354 .clojure.syntaxhighlighter .quoted { 355 font-style: italic !important; 356 } 357 358 .syntaxhighlighter .clojure.variable, 359 .syntaxhighlighter .clojure.symbol, 360 .syntaxhighlighter .clojure.value 361 { 362 color: #006060 !important; 363 } 364 365 .syntaxhighlighter .clojure.string { 366 color: #55B !important; 367 } 368 369 .syntaxhighlighter .clojure.functions { 370 color: black !important; 371 } 372 373 .syntaxhighlighter .clojure.color1 { 374 color: #666 !important; 375 } 376 377 .syntaxhighlighter .clojure.color3 { 378 color: #900 !important; 379 } 380 381 .syntaxhighlighter .clojure.constants { 382 color: #1A734D !important; 383 } 384 385 </style><style type="text/css">html{margin:0;padding:0;}h1{margin:0;padding:0;}h2{margin:0;padding:0;}h3{margin:0;padding:0;}h4{margin:0;padding:0;}a{color:#261A3B;}a:visited{color:#261A3B;}</style><style type="text/css">.header{margin-top:30px;}h1.project-name{font-size:34px;display:inline;}h2.project-version{font-size:18px;margin-top:0;display:inline;margin-left:10px;}.toc-link{font-size:12px;margin-left:10px;color:#252519;text-decoration:none;}.toc-link:hover{color:#5050A6;}.toc h1{font-size:34px;margin:0;}.docs-header{border-bottom:dotted #aaa 1px;padding-bottom:10px;margin-bottom:25px;}.toc h1{font-size:24px;}.toc{border-bottom:solid #bbb 1px;margin-bottom:40px;}.toc ul{margin-left:20px;padding-left:0px;padding-top:0;margin-top:0;}.toc li{list-style-type:none;padding-left:0;}.dependencies{}.dependencies table{font-size:16px;width:99.99%;border:none;margin-left:20px;}.dependencies td{padding-right:20px;;white-space:nowrap;}.dependencies .dotted{width:99%;}.dependencies .dotted hr{border-right:none;color:transparent;background-color:transparent;noshade:noshade;border-left:none;border-top:none;margin-bottom:-6px;height:0;border-bottom:dotted #bbb 1px;}.dependencies .dep-version{text-align:right;}.plugins ul{margin-left:20px;padding-left:0px;padding-top:0;margin-top:0;}.plugins li{list-style-type:none;padding-left:0;}.header p{margin-left:20px;}</style><style type="text/css">#floating-toc{position:fixed;top:10px;right:20px;height:20px;overflow:hidden;text-align:right;}#floating-toc li{list-style-type:none;margin:0;padding:0;}</style><style type="text/css">body{margin:0;padding:0;font-family:'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;;font-size:16px;color:#252519;background-color:#F5F5FF;}h1{font-size:20px;margin-top:0;}h2{font-size:18px;}h3{font-size:16px;}a.anchor{text-decoration:none;color:#252519;}a.anchor:hover{color:#5050A6;}table{border-spacing:0;border-bottom:solid #ddd 1px;;margin-bottom:10px;}code{display:inline;}p{margin-top:8px;}tr{margin:0px;padding:0px;}td.docs{width:410px;max-width:410px;vertical-align:top;margin:0px;padding-left:55px;padding-right:20px;border:none;background-color:#FFF;}td.docs pre{font-size:12px;overflow:hidden;}td.codes{vertical-align:top;font-size:10pt;overflow:hidden;background-color:#F5F5FF;width:55%;border-left:solid #E5E5EE 1px;padding-left:20px;border:none;margin:0px;}td.spacer{padding-bottom:40px;}pre code{display:block;padding:4px;}code{background-color:ghostWhite;border:solid #DEDEDE 1px;padding-left:3px;padding-right:3px;font-size:14px;}.syntaxhighlighter code{font-size:13px;}.footer{text-align:center;}</style><script type="text/javascript">/*! jQuery v1.7.1 jquery.com | jquery.org/license */ 386 (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; 387 f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() 388 {for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); 389 </script><script type="text/javascript">//XRegExp 1.5.0 <xregexp.com> MIT License 390 var XRegExp;if(XRegExp){throw Error("can't load XRegExp twice in the same frame")}(function(){XRegExp=function(w,r){var q=[],u=XRegExp.OUTSIDE_CLASS,x=0,p,s,v,t,y;if(XRegExp.isRegExp(w)){if(r!==undefined){throw TypeError("can't supply flags when constructing one RegExp from another")}return j(w)}if(g){throw Error("can't call the XRegExp constructor within token definition functions")}r=r||"";p={hasNamedCapture:false,captureNames:[],hasFlag:function(z){return r.indexOf(z)>-1},setFlag:function(z){r+=z}};while(x<w.length){s=o(w,x,u,p);if(s){q.push(s.output);x+=(s.match[0].length||1)}else{if(v=m.exec.call(i[u],w.slice(x))){q.push(v[0]);x+=v[0].length}else{t=w.charAt(x);if(t==="["){u=XRegExp.INSIDE_CLASS}else{if(t==="]"){u=XRegExp.OUTSIDE_CLASS}}q.push(t);x++}}}y=RegExp(q.join(""),m.replace.call(r,h,""));y._xregexp={source:w,captureNames:p.hasNamedCapture?p.captureNames:null};return y};XRegExp.version="1.5.0";XRegExp.INSIDE_CLASS=1;XRegExp.OUTSIDE_CLASS=2;var c=/\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,h=/[^gimy]+|([\s\S])(?=[\s\S]*\1)/g,n=/^(?:[?*+]|{\d+(?:,\d*)?})\??/,g=false,k=[],m={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},a=m.exec.call(/()??/,"")[1]===undefined,e=function(){var p=/^/g;m.test.call(p,"");return !p.lastIndex}(),f=function(){var p=/x/g;m.replace.call("x",p,"");return !p.lastIndex}(),b=RegExp.prototype.sticky!==undefined,i={};i[XRegExp.INSIDE_CLASS]=/^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;i[XRegExp.OUTSIDE_CLASS]=/^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;XRegExp.addToken=function(s,r,q,p){k.push({pattern:j(s,"g"+(b?"y":"")),handler:r,scope:q||XRegExp.OUTSIDE_CLASS,trigger:p||null})};XRegExp.cache=function(r,p){var q=r+"/"+(p||"");return XRegExp.cache[q]||(XRegExp.cache[q]=XRegExp(r,p))};XRegExp.copyAsGlobal=function(p){return j(p,"g")};XRegExp.escape=function(p){return p.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")};XRegExp.execAt=function(s,r,t,q){r=j(r,"g"+((q&&b)?"y":""));r.lastIndex=t=t||0;var p=r.exec(s);if(q){return(p&&p.index===t)?p:null}else{return p}};XRegExp.freezeTokens=function(){XRegExp.addToken=function(){throw Error("can't run addToken after freezeTokens")}};XRegExp.isRegExp=function(p){return Object.prototype.toString.call(p)==="[object RegExp]"};XRegExp.iterate=function(u,p,v,s){var t=j(p,"g"),r=-1,q;while(q=t.exec(u)){v.call(s,q,++r,u,t);if(t.lastIndex===q.index){t.lastIndex++}}if(p.global){p.lastIndex=0}};XRegExp.matchChain=function(q,p){return function r(s,x){var v=p[x].regex?p[x]:{regex:p[x]},u=j(v.regex,"g"),w=[],t;for(t=0;t<s.length;t++){XRegExp.iterate(s[t],u,function(y){w.push(v.backref?(y[v.backref]||""):y[0])})}return((x===p.length-1)||!w.length)?w:r(w,x+1)}([q],0)};RegExp.prototype.apply=function(q,p){return this.exec(p[0])};RegExp.prototype.call=function(p,q){return this.exec(q)};RegExp.prototype.exec=function(t){var r=m.exec.apply(this,arguments),q,p;if(r){if(!a&&r.length>1&&l(r,"")>-1){p=RegExp(this.source,m.replace.call(d(this),"g",""));m.replace.call(t.slice(r.index),p,function(){for(var u=1;u<arguments.length-2;u++){if(arguments[u]===undefined){r[u]=undefined}}})}if(this._xregexp&&this._xregexp.captureNames){for(var s=1;s<r.length;s++){q=this._xregexp.captureNames[s-1];if(q){r[q]=r[s]}}}if(!e&&this.global&&!r[0].length&&(this.lastIndex>r.index)){this.lastIndex--}}return r};if(!e){RegExp.prototype.test=function(q){var p=m.exec.call(this,q);if(p&&this.global&&!p[0].length&&(this.lastIndex>p.index)){this.lastIndex--}return !!p}}String.prototype.match=function(q){if(!XRegExp.isRegExp(q)){q=RegExp(q)}if(q.global){var p=m.match.apply(this,arguments);q.lastIndex=0;return p}return q.exec(this)};String.prototype.replace=function(r,s){var t=XRegExp.isRegExp(r),q,p,u;if(t&&typeof s.valueOf()==="string"&&s.indexOf("${")===-1&&f){return m.replace.apply(this,arguments)}if(!t){r=r+""}else{if(r._xregexp){q=r._xregexp.captureNames}}if(typeof s==="function"){p=m.replace.call(this,r,function(){if(q){arguments[0]=new String(arguments[0]);for(var v=0;v<q.length;v++){if(q[v]){arguments[0][q[v]]=arguments[v+1]}}}if(t&&r.global){r.lastIndex=arguments[arguments.length-2]+arguments[0].length}return s.apply(null,arguments)})}else{u=this+"";p=m.replace.call(u,r,function(){var v=arguments;return m.replace.call(s,c,function(x,w,A){if(w){switch(w){case"$":return"$";case"&":return v[0];case"`":return v[v.length-1].slice(0,v[v.length-2]);case"'":return v[v.length-1].slice(v[v.length-2]+v[0].length);default:var y="";w=+w;if(!w){return x}while(w>v.length-3){y=String.prototype.slice.call(w,-1)+y;w=Math.floor(w/10)}return(w?v[w]||"":"$")+y}}else{var z=+A;if(z<=v.length-3){return v[z]}z=q?l(q,A):-1;return z>-1?v[z+1]:x}})})}if(t&&r.global){r.lastIndex=0}return p};String.prototype.split=function(u,p){if(!XRegExp.isRegExp(u)){return m.split.apply(this,arguments)}var w=this+"",r=[],v=0,t,q;if(p===undefined||+p<0){p=Infinity}else{p=Math.floor(+p);if(!p){return[]}}u=XRegExp.copyAsGlobal(u);while(t=u.exec(w)){if(u.lastIndex>v){r.push(w.slice(v,t.index));if(t.length>1&&t.index<w.length){Array.prototype.push.apply(r,t.slice(1))}q=t[0].length;v=u.lastIndex;if(r.length>=p){break}}if(u.lastIndex===t.index){u.lastIndex++}}if(v===w.length){if(!m.test.call(u,"")||q){r.push("")}}else{r.push(w.slice(v))}return r.length>p?r.slice(0,p):r};function j(r,q){if(!XRegExp.isRegExp(r)){throw TypeError("type RegExp expected")}var p=r._xregexp;r=XRegExp(r.source,d(r)+(q||""));if(p){r._xregexp={source:p.source,captureNames:p.captureNames?p.captureNames.slice(0):null}}return r}function d(p){return(p.global?"g":"")+(p.ignoreCase?"i":"")+(p.multiline?"m":"")+(p.extended?"x":"")+(p.sticky?"y":"")}function o(v,u,w,p){var r=k.length,y,s,x;g=true;try{while(r--){x=k[r];if((w&x.scope)&&(!x.trigger||x.trigger.call(p))){x.pattern.lastIndex=u;s=x.pattern.exec(v);if(s&&s.index===u){y={output:x.handler.call(p,s,w),match:s};break}}}}catch(q){throw q}finally{g=false}return y}function l(s,q,r){if(Array.prototype.indexOf){return s.indexOf(q,r)}for(var p=r||0;p<s.length;p++){if(s[p]===q){return p}}return -1}XRegExp.addToken(/\(\?#[^)]*\)/,function(p){return m.test.call(n,p.input.slice(p.index+p[0].length))?"":"(?:)"});XRegExp.addToken(/\((?!\?)/,function(){this.captureNames.push(null);return"("});XRegExp.addToken(/\(\?<([$\w]+)>/,function(p){this.captureNames.push(p[1]);this.hasNamedCapture=true;return"("});XRegExp.addToken(/\\k<([\w$]+)>/,function(q){var p=l(this.captureNames,q[1]);return p>-1?"\\"+(p+1)+(isNaN(q.input.charAt(q.index+q[0].length))?"":"(?:)"):q[0]});XRegExp.addToken(/\[\^?]/,function(p){return p[0]==="[]"?"\\b\\B":"[\\s\\S]"});XRegExp.addToken(/^\(\?([imsx]+)\)/,function(p){this.setFlag(p[1]);return""});XRegExp.addToken(/(?:\s+|#.*)+/,function(p){return m.test.call(n,p.input.slice(p.index+p[0].length))?"":"(?:)"},XRegExp.OUTSIDE_CLASS,function(){return this.hasFlag("x")});XRegExp.addToken(/\./,function(){return"[\\s\\S]"},XRegExp.OUTSIDE_CLASS,function(){return this.hasFlag("s")})})(); 391 </script><script type="text/javascript">/** 392 * SyntaxHighlighter 393 * http://alexgorbatchev.com/SyntaxHighlighter 394 * 395 * SyntaxHighlighter is donationware. If you are using it, please donate. 396 * http://alexgorbatchev.com/SyntaxHighlighter/donate.html 397 * 398 * @version 399 * 3.0.83 (July 02 2010) 400 * 401 * @copyright 402 * Copyright (C) 2004-2010 Alex Gorbatchev. 403 * 404 * @license 405 * Dual licensed under the MIT and GPL licenses. 406 */ 407 // 408 // Begin anonymous function. This is used to contain local scope variables without polutting global scope. 409 // 410 var SyntaxHighlighter = function() { 411 412 // CommonJS 413 if (typeof(require) != 'undefined' && typeof(XRegExp) == 'undefined') 414 { 415 XRegExp = require('XRegExp').XRegExp; 416 } 417 418 // Shortcut object which will be assigned to the SyntaxHighlighter variable. 419 // This is a shorthand for local reference in order to avoid long namespace 420 // references to SyntaxHighlighter.whatever... 421 var sh = { 422 defaults : { 423 /** Additional CSS class names to be added to highlighter elements. */ 424 'class-name' : '', 425 426 /** First line number. */ 427 'first-line' : 1, 428 429 /** 430 * Pads line numbers. Possible values are: 431 * 432 * false - don't pad line numbers. 433 * true - automaticaly pad numbers with minimum required number of leading zeroes. 434 * [int] - length up to which pad line numbers. 435 */ 436 'pad-line-numbers' : false, 437 438 /** Lines to highlight. */ 439 'highlight' : null, 440 441 /** Title to be displayed above the code block. */ 442 'title' : null, 443 444 /** Enables or disables smart tabs. */ 445 'smart-tabs' : true, 446 447 /** Gets or sets tab size. */ 448 'tab-size' : 4, 449 450 /** Enables or disables gutter. */ 451 'gutter' : true, 452 453 /** Enables or disables toolbar. */ 454 'toolbar' : true, 455 456 /** Enables quick code copy and paste from double click. */ 457 'quick-code' : true, 458 459 /** Forces code view to be collapsed. */ 460 'collapse' : false, 461 462 /** Enables or disables automatic links. */ 463 'auto-links' : true, 464 465 /** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */ 466 'light' : false, 467 468 'html-script' : false 469 }, 470 471 config : { 472 space : ' ', 473 474 /** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */ 475 useScriptTags : true, 476 477 /** Blogger mode flag. */ 478 bloggerMode : false, 479 480 stripBrs : false, 481 482 /** Name of the tag that SyntaxHighlighter will automatically look for. */ 483 tagName : 'pre', 484 485 strings : { 486 expandSource : 'expand source', 487 help : '?', 488 alert: 'SyntaxHighlighter\n\n', 489 noBrush : 'Can\'t find brush for: ', 490 brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ', 491 492 // this is populated by the build script 493 aboutDialog : '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>About SyntaxHighlighter</title></head><body style="font-family:Geneva,Arial,Helvetica,sans-serif;background-color:#fff;color:#000;font-size:1em;text-align:center;"><div style="text-align:center;margin-top:1.5em;"><div style="font-size:xx-large;">SyntaxHighlighter</div><div style="font-size:.75em;margin-bottom:3em;"><div>version 3.0.83 (July 02 2010)</div><div><a href="http://alexgorbatchev.com/SyntaxHighlighter" target="_blank" style="color:#005896">http://alexgorbatchev.com/SyntaxHighlighter</a></div><div>JavaScript code syntax highlighter.</div><div>Copyright 2004-2010 Alex Gorbatchev.</div></div><div>If you like this script, please <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2930402" style="color:#005896">donate</a> to <br/>keep development active!</div></div></body></html>' 494 } 495 }, 496 497 /** Internal 'global' variables. */ 498 vars : { 499 discoveredBrushes : null, 500 highlighters : {} 501 }, 502 503 /** This object is populated by user included external brush files. */ 504 brushes : {}, 505 506 /** Common regular expressions. */ 507 regexLib : { 508 multiLineCComments : /\/\*[\s\S]*?\*\//gm, 509 singleLineCComments : /\/\/.*$/gm, 510 singleLinePerlComments : /#.*$/gm, 511 doubleQuotedString : /"([^\\"\n]|\\.)*"/g, 512 singleQuotedString : /'([^\\'\n]|\\.)*'/g, 513 multiLineDoubleQuotedString : new XRegExp('"([^\\\\"]|\\\\.)*"', 'gs'), 514 multiLineSingleQuotedString : new XRegExp("'([^\\\\']|\\\\.)*'", 'gs'), 515 xmlComments : /(<|<)!--[\s\S]*?--(>|>)/gm, 516 url : /\w+:\/\/[\w-.\/?%&=:@;]*/g, 517 518 /** <?= ?> tags. */ 519 phpScriptTags : { left: /(<|<)\?=?/g, right: /\?(>|>)/g }, 520 521 /** <%= %> tags. */ 522 aspScriptTags : { left: /(<|<)%=?/g, right: /%(>|>)/g }, 523 524 scriptScriptTags : { left: /(<|<)\s*script.*?(>|>)/gi, right: /(<|<)\/\s*script\s*(>|>)/gi } 525 }, 526 527 toolbar: { 528 /** 529 * Generates HTML markup for the toolbar. 530 * @param {Highlighter} highlighter Highlighter instance. 531 * @return {String} Returns HTML markup. 532 */ 533 getHtml: function(highlighter) 534 { 535 var html = '<div class="toolbar">', 536 items = sh.toolbar.items, 537 list = items.list 538 ; 539 540 function defaultGetHtml(highlighter, name) 541 { 542 return sh.toolbar.getButtonHtml(highlighter, name, sh.config.strings[name]); 543 }; 544 545 for (var i = 0; i < list.length; i++) 546 html += (items[list[i]].getHtml || defaultGetHtml)(highlighter, list[i]); 547 548 html += '</div>'; 549 550 return html; 551 }, 552 553 /** 554 * Generates HTML markup for a regular button in the toolbar. 555 * @param {Highlighter} highlighter Highlighter instance. 556 * @param {String} commandName Command name that would be executed. 557 * @param {String} label Label text to display. 558 * @return {String} Returns HTML markup. 559 */ 560 getButtonHtml: function(highlighter, commandName, label) 561 { 562 return '<span><a href="#" class="toolbar_item' 563 + ' command_' + commandName 564 + ' ' + commandName 565 + '">' + label + '</a></span>' 566 ; 567 }, 568 569 /** 570 * Event handler for a toolbar anchor. 571 */ 572 handler: function(e) 573 { 574 var target = e.target, 575 className = target.className || '' 576 ; 577 578 function getValue(name) 579 { 580 var r = new RegExp(name + '_(\\w+)'), 581 match = r.exec(className) 582 ; 583 584 return match ? match[1] : null; 585 }; 586 587 var highlighter = getHighlighterById(findParentElement(target, '.syntaxhighlighter').id), 588 commandName = getValue('command') 589 ; 590 591 // execute the toolbar command 592 if (highlighter && commandName) 593 sh.toolbar.items[commandName].execute(highlighter); 594 595 // disable default A click behaviour 596 e.preventDefault(); 597 }, 598 599 /** Collection of toolbar items. */ 600 items : { 601 // Ordered lis of items in the toolbar. Can't expect `for (var n in items)` to be consistent. 602 list: ['expandSource', 'help'], 603 604 expandSource: { 605 getHtml: function(highlighter) 606 { 607 if (highlighter.getParam('collapse') != true) 608 return ''; 609 610 var title = highlighter.getParam('title'); 611 return sh.toolbar.getButtonHtml(highlighter, 'expandSource', title ? title : sh.config.strings.expandSource); 612 }, 613 614 execute: function(highlighter) 615 { 616 var div = getHighlighterDivById(highlighter.id); 617 removeClass(div, 'collapsed'); 618 } 619 }, 620 621 /** Command to display the about dialog window. */ 622 help: { 623 execute: function(highlighter) 624 { 625 var wnd = popup('', '_blank', 500, 250, 'scrollbars=0'), 626 doc = wnd.document 627 ; 628 629 doc.write(sh.config.strings.aboutDialog); 630 doc.close(); 631 wnd.focus(); 632 } 633 } 634 } 635 }, 636 637 /** 638 * Finds all elements on the page which should be processes by SyntaxHighlighter. 639 * 640 * @param {Object} globalParams Optional parameters which override element's 641 * parameters. Only used if element is specified. 642 * 643 * @param {Object} element Optional element to highlight. If none is 644 * provided, all elements in the current document 645 * are returned which qualify. 646 * 647 * @return {Array} Returns list of <code>{ target: DOMElement, params: Object }</code> objects. 648 */ 649 findElements: function(globalParams, element) 650 { 651 var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)), 652 conf = sh.config, 653 result = [] 654 ; 655 656 // support for <SCRIPT TYPE="syntaxhighlighter" /> feature 657 if (conf.useScriptTags) 658 elements = elements.concat(getSyntaxHighlighterScriptTags()); 659 660 if (elements.length === 0) 661 return result; 662 663 for (var i = 0; i < elements.length; i++) 664 { 665 var item = { 666 target: elements[i], 667 // local params take precedence over globals 668 params: merge(globalParams, parseParams(elements[i].className)) 669 }; 670 671 if (item.params['brush'] == null) 672 continue; 673 674 result.push(item); 675 } 676 677 return result; 678 }, 679 680 /** 681 * Shorthand to highlight all elements on the page that are marked as 682 * SyntaxHighlighter source code. 683 * 684 * @param {Object} globalParams Optional parameters which override element's 685 * parameters. Only used if element is specified. 686 * 687 * @param {Object} element Optional element to highlight. If none is 688 * provided, all elements in the current document 689 * are highlighted. 690 */ 691 highlight: function(globalParams, element) 692 { 693 var elements = this.findElements(globalParams, element), 694 propertyName = 'innerHTML', 695 highlighter = null, 696 conf = sh.config 697 ; 698 699 if (elements.length === 0) 700 return; 701 702 for (var i = 0; i < elements.length; i++) 703 { 704 var element = elements[i], 705 target = element.target, 706 params = element.params, 707 brushName = params.brush, 708 code 709 ; 710 711 if (brushName == null) 712 continue; 713 714 // Instantiate a brush 715 if (params['html-script'] == 'true' || sh.defaults['html-script'] == true) 716 { 717 highlighter = new sh.HtmlScript(brushName); 718 brushName = 'htmlscript'; 719 } 720 else 721 { 722 var brush = findBrush(brushName); 723 724 if (brush) 725 highlighter = new brush(); 726 else 727 continue; 728 } 729 730 code = target[propertyName]; 731 732 // remove CDATA from <SCRIPT/> tags if it's present 733 if (conf.useScriptTags) 734 code = stripCData(code); 735 736 // Inject title if the attribute is present 737 if ((target.title || '') != '') 738 params.title = target.title; 739 740 params['brush'] = brushName; 741 highlighter.init(params); 742 element = highlighter.getDiv(code); 743 744 // carry over ID 745 if ((target.id || '') != '') 746 element.id = target.id; 747 748 target.parentNode.replaceChild(element, target); 749 } 750 }, 751 752 /** 753 * Main entry point for the SyntaxHighlighter. 754 * @param {Object} params Optional params to apply to all highlighted elements. 755 */ 756 all: function(params) 757 { 758 attachEvent( 759 window, 760 'load', 761 function() { sh.highlight(params); } 762 ); 763 } 764 }; // end of sh 765 766 sh['all'] = sh.all; 767 sh['highlight'] = sh.highlight; 768 769 /** 770 * Checks if target DOM elements has specified CSS class. 771 * @param {DOMElement} target Target DOM element to check. 772 * @param {String} className Name of the CSS class to check for. 773 * @return {Boolean} Returns true if class name is present, false otherwise. 774 */ 775 function hasClass(target, className) 776 { 777 return target.className.indexOf(className) != -1; 778 }; 779 780 /** 781 * Adds CSS class name to the target DOM element. 782 * @param {DOMElement} target Target DOM element. 783 * @param {String} className New CSS class to add. 784 */ 785 function addClass(target, className) 786 { 787 if (!hasClass(target, className)) 788 target.className += ' ' + className; 789 }; 790 791 /** 792 * Removes CSS class name from the target DOM element. 793 * @param {DOMElement} target Target DOM element. 794 * @param {String} className CSS class to remove. 795 */ 796 function removeClass(target, className) 797 { 798 target.className = target.className.replace(className, ''); 799 }; 800 801 /** 802 * Converts the source to array object. Mostly used for function arguments and 803 * lists returned by getElementsByTagName() which aren't Array objects. 804 * @param {List} source Source list. 805 * @return {Array} Returns array. 806 */ 807 function toArray(source) 808 { 809 var result = []; 810 811 for (var i = 0; i < source.length; i++) 812 result.push(source[i]); 813 814 return result; 815 }; 816 817 /** 818 * Splits block of text into lines. 819 * @param {String} block Block of text. 820 * @return {Array} Returns array of lines. 821 */ 822 function splitLines(block) 823 { 824 return block.split('\n'); 825 } 826 827 /** 828 * Generates HTML ID for the highlighter. 829 * @param {String} highlighterId Highlighter ID. 830 * @return {String} Returns HTML ID. 831 */ 832 function getHighlighterId(id) 833 { 834 var prefix = 'highlighter_'; 835 return id.indexOf(prefix) == 0 ? id : prefix + id; 836 }; 837 838 /** 839 * Finds Highlighter instance by ID. 840 * @param {String} highlighterId Highlighter ID. 841 * @return {Highlighter} Returns instance of the highlighter. 842 */ 843 function getHighlighterById(id) 844 { 845 return sh.vars.highlighters[getHighlighterId(id)]; 846 }; 847 848 /** 849 * Finds highlighter's DIV container. 850 * @param {String} highlighterId Highlighter ID. 851 * @return {Element} Returns highlighter's DIV element. 852 */ 853 function getHighlighterDivById(id) 854 { 855 return document.getElementById(getHighlighterId(id)); 856 }; 857 858 /** 859 * Stores highlighter so that getHighlighterById() can do its thing. Each 860 * highlighter must call this method to preserve itself. 861 * @param {Highilghter} highlighter Highlighter instance. 862 */ 863 function storeHighlighter(highlighter) 864 { 865 sh.vars.highlighters[getHighlighterId(highlighter.id)] = highlighter; 866 }; 867 868 /** 869 * Looks for a child or parent node which has specified classname. 870 * Equivalent to jQuery's $(container).find(".className") 871 * @param {Element} target Target element. 872 * @param {String} search Class name or node name to look for. 873 * @param {Boolean} reverse If set to true, will go up the node tree instead of down. 874 * @return {Element} Returns found child or parent element on null. 875 */ 876 function findElement(target, search, reverse /* optional */) 877 { 878 if (target == null) 879 return null; 880 881 var nodes = reverse != true ? target.childNodes : [ target.parentNode ], 882 propertyToFind = { '#' : 'id', '.' : 'className' }[search.substr(0, 1)] || 'nodeName', 883 expectedValue, 884 found 885 ; 886 887 expectedValue = propertyToFind != 'nodeName' 888 ? search.substr(1) 889 : search.toUpperCase() 890 ; 891 892 // main return of the found node 893 if ((target[propertyToFind] || '').indexOf(expectedValue) != -1) 894 return target; 895 896 for (var i = 0; nodes && i < nodes.length && found == null; i++) 897 found = findElement(nodes[i], search, reverse); 898 899 return found; 900 }; 901 902 /** 903 * Looks for a parent node which has specified classname. 904 * This is an alias to <code>findElement(container, className, true)</code>. 905 * @param {Element} target Target element. 906 * @param {String} className Class name to look for. 907 * @return {Element} Returns found parent element on null. 908 */ 909 function findParentElement(target, className) 910 { 911 return findElement(target, className, true); 912 }; 913 914 /** 915 * Finds an index of element in the array. 916 * @ignore 917 * @param {Object} searchElement 918 * @param {Number} fromIndex 919 * @return {Number} Returns index of element if found; -1 otherwise. 920 */ 921 function indexOf(array, searchElement, fromIndex) 922 { 923 fromIndex = Math.max(fromIndex || 0, 0); 924 925 for (var i = fromIndex; i < array.length; i++) 926 if(array[i] == searchElement) 927 return i; 928 929 return -1; 930 }; 931 932 /** 933 * Generates a unique element ID. 934 */ 935 function guid(prefix) 936 { 937 return (prefix || '') + Math.round(Math.random() * 1000000).toString(); 938 }; 939 940 /** 941 * Merges two objects. Values from obj2 override values in obj1. 942 * Function is NOT recursive and works only for one dimensional objects. 943 * @param {Object} obj1 First object. 944 * @param {Object} obj2 Second object. 945 * @return {Object} Returns combination of both objects. 946 */ 947 function merge(obj1, obj2) 948 { 949 var result = {}, name; 950 951 for (name in obj1) 952 result[name] = obj1[name]; 953 954 for (name in obj2) 955 result[name] = obj2[name]; 956 957 return result; 958 }; 959 960 /** 961 * Attempts to convert string to boolean. 962 * @param {String} value Input string. 963 * @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise. 964 */ 965 function toBoolean(value) 966 { 967 var result = { "true" : true, "false" : false }[value]; 968 return result == null ? value : result; 969 }; 970 971 /** 972 * Opens up a centered popup window. 973 * @param {String} url URL to open in the window. 974 * @param {String} name Popup name. 975 * @param {int} width Popup width. 976 * @param {int} height Popup height. 977 * @param {String} options window.open() options. 978 * @return {Window} Returns window instance. 979 */ 980 function popup(url, name, width, height, options) 981 { 982 var x = (screen.width - width) / 2, 983 y = (screen.height - height) / 2 984 ; 985 986 options += ', left=' + x + 987 ', top=' + y + 988 ', width=' + width + 989 ', height=' + height 990 ; 991 options = options.replace(/^,/, ''); 992 993 var win = window.open(url, name, options); 994 win.focus(); 995 return win; 996 }; 997 998 /** 999 * Adds event handler to the target object. 1000 * @param {Object} obj Target object. 1001 * @param {String} type Name of the event. 1002 * @param {Function} func Handling function. 1003 */ 1004 function attachEvent(obj, type, func, scope) 1005 { 1006 function handler(e) 1007 { 1008 e = e || window.event; 1009 1010 if (!e.target) 1011 { 1012 e.target = e.srcElement; 1013 e.preventDefault = function() 1014 { 1015 this.returnValue = false; 1016 }; 1017 } 1018 1019 func.call(scope || window, e); 1020 }; 1021 1022 if (obj.attachEvent) 1023 { 1024 obj.attachEvent('on' + type, handler); 1025 } 1026 else 1027 { 1028 obj.addEventListener(type, handler, false); 1029 } 1030 }; 1031 1032 /** 1033 * Displays an alert. 1034 * @param {String} str String to display. 1035 */ 1036 function alert(str) 1037 { 1038 window.alert(sh.config.strings.alert + str); 1039 }; 1040 1041 /** 1042 * Finds a brush by its alias. 1043 * 1044 * @param {String} alias Brush alias. 1045 * @param {Boolean} showAlert Suppresses the alert if false. 1046 * @return {Brush} Returns bursh constructor if found, null otherwise. 1047 */ 1048 function findBrush(alias, showAlert) 1049 { 1050 var brushes = sh.vars.discoveredBrushes, 1051 result = null 1052 ; 1053 1054 if (brushes == null) 1055 { 1056 brushes = {}; 1057 1058 // Find all brushes 1059 for (var brush in sh.brushes) 1060 { 1061 var info = sh.brushes[brush], 1062 aliases = info.aliases 1063 ; 1064 1065 if (aliases == null) 1066 continue; 1067 1068 // keep the brush name 1069 info.brushName = brush.toLowerCase(); 1070 1071 for (var i = 0; i < aliases.length; i++) 1072 brushes[aliases[i]] = brush; 1073 } 1074 1075 sh.vars.discoveredBrushes = brushes; 1076 } 1077 1078 result = sh.brushes[brushes[alias]]; 1079 1080 if (result == null && showAlert != false) 1081 alert(sh.config.strings.noBrush + alias); 1082 1083 return result; 1084 }; 1085 1086 /** 1087 * Executes a callback on each line and replaces each line with result from the callback. 1088 * @param {Object} str Input string. 1089 * @param {Object} callback Callback function taking one string argument and returning a string. 1090 */ 1091 function eachLine(str, callback) 1092 { 1093 var lines = splitLines(str); 1094 1095 for (var i = 0; i < lines.length; i++) 1096 lines[i] = callback(lines[i], i); 1097 1098 return lines.join('\n'); 1099 }; 1100 1101 /** 1102 * This is a special trim which only removes first and last empty lines 1103 * and doesn't affect valid leading space on the first line. 1104 * 1105 * @param {String} str Input string 1106 * @return {String} Returns string without empty first and last lines. 1107 */ 1108 function trimFirstAndLastLines(str) 1109 { 1110 return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, ''); 1111 }; 1112 1113 /** 1114 * Parses key/value pairs into hash object. 1115 * 1116 * Understands the following formats: 1117 * - name: word; 1118 * - name: [word, word]; 1119 * - name: "string"; 1120 * - name: 'string'; 1121 * 1122 * For example: 1123 * name1: value; name2: [value, value]; name3: 'value' 1124 * 1125 * @param {String} str Input string. 1126 * @return {Object} Returns deserialized object. 1127 */ 1128 function parseParams(str) 1129 { 1130 var match, 1131 result = {}, 1132 arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"), 1133 regex = new XRegExp( 1134 "(?<name>[\\w-]+)" + 1135 "\\s*:\\s*" + 1136 "(?<value>" + 1137 "[\\w-%#]+|" + // word 1138 "\\[.*?\\]|" + // [] array 1139 '".*?"|' + // "" string 1140 "'.*?'" + // '' string 1141 ")\\s*;?", 1142 "g" 1143 ) 1144 ; 1145 1146 while ((match = regex.exec(str)) != null) 1147 { 1148 var value = match.value 1149 .replace(/^['"]|['"]$/g, '') // strip quotes from end of strings 1150 ; 1151 1152 // try to parse array value 1153 if (value != null && arrayRegex.test(value)) 1154 { 1155 var m = arrayRegex.exec(value); 1156 value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : []; 1157 } 1158 1159 result[match.name] = value; 1160 } 1161 1162 return result; 1163 }; 1164 1165 /** 1166 * Wraps each line of the string into <code/> tag with given style applied to it. 1167 * 1168 * @param {String} str Input string. 1169 * @param {String} css Style name to apply to the string. 1170 * @return {String} Returns input string with each line surrounded by <span/> tag. 1171 */ 1172 function wrapLinesWithCode(str, css) 1173 { 1174 if (str == null || str.length == 0 || str == '\n') 1175 return str; 1176 1177 str = str.replace(/</g, '<'); 1178 1179 // Replace two or more sequential spaces with leaving last space untouched. 1180 str = str.replace(/ {2,}/g, function(m) 1181 { 1182 var spaces = ''; 1183 1184 for (var i = 0; i < m.length - 1; i++) 1185 spaces += sh.config.space; 1186 1187 return spaces + ' '; 1188 }); 1189 1190 // Split each line and apply <span class="...">...</span> to them so that 1191 // leading spaces aren't included. 1192 if (css != null) 1193 str = eachLine(str, function(line) 1194 { 1195 if (line.length == 0) 1196 return ''; 1197 1198 var spaces = ''; 1199 1200 line = line.replace(/^( | )+/, function(s) 1201 { 1202 spaces = s; 1203 return ''; 1204 }); 1205 1206 if (line.length == 0) 1207 return spaces; 1208 1209 return spaces + '<code class="' + css + '">' + line + '</code>'; 1210 }); 1211 1212 return str; 1213 }; 1214 1215 /** 1216 * Pads number with zeros until it's length is the same as given length. 1217 * 1218 * @param {Number} number Number to pad. 1219 * @param {Number} length Max string length with. 1220 * @return {String} Returns a string padded with proper amount of '0'. 1221 */ 1222 function padNumber(number, length) 1223 { 1224 var result = number.toString(); 1225 1226 while (result.length < length) 1227 result = '0' + result; 1228 1229 return result; 1230 }; 1231 1232 /** 1233 * Replaces tabs with spaces. 1234 * 1235 * @param {String} code Source code. 1236 * @param {Number} tabSize Size of the tab. 1237 * @return {String} Returns code with all tabs replaces by spaces. 1238 */ 1239 function processTabs(code, tabSize) 1240 { 1241 var tab = ''; 1242 1243 for (var i = 0; i < tabSize; i++) 1244 tab += ' '; 1245 1246 return code.replace(/\t/g, tab); 1247 }; 1248 1249 /** 1250 * Replaces tabs with smart spaces. 1251 * 1252 * @param {String} code Code to fix the tabs in. 1253 * @param {Number} tabSize Number of spaces in a column. 1254 * @return {String} Returns code with all tabs replaces with roper amount of spaces. 1255 */ 1256 function processSmartTabs(code, tabSize) 1257 { 1258 var lines = splitLines(code), 1259 tab = '\t', 1260 spaces = '' 1261 ; 1262 1263 // Create a string with 1000 spaces to copy spaces from... 1264 // It's assumed that there would be no indentation longer than that. 1265 for (var i = 0; i < 50; i++) 1266 spaces += ' '; // 20 spaces * 50 1267 1268 // This function inserts specified amount of spaces in the string 1269 // where a tab is while removing that given tab. 1270 function insertSpaces(line, pos, count) 1271 { 1272 return line.substr(0, pos) 1273 + spaces.substr(0, count) 1274 + line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab 1275 ; 1276 }; 1277 1278 // Go through all the lines and do the 'smart tabs' magic. 1279 code = eachLine(code, function(line) 1280 { 1281 if (line.indexOf(tab) == -1) 1282 return line; 1283 1284 var pos = 0; 1285 1286 while ((pos = line.indexOf(tab)) != -1) 1287 { 1288 // This is pretty much all there is to the 'smart tabs' logic. 1289 // Based on the position within the line and size of a tab, 1290 // calculate the amount of spaces we need to insert. 1291 var spaces = tabSize - pos % tabSize; 1292 line = insertSpaces(line, pos, spaces); 1293 } 1294 1295 return line; 1296 }); 1297 1298 return code; 1299 }; 1300 1301 /** 1302 * Performs various string fixes based on configuration. 1303 */ 1304 function fixInputString(str) 1305 { 1306 var br = /<br\s*\/?>|<br\s*\/?>/gi; 1307 1308 if (sh.config.bloggerMode == true) 1309 str = str.replace(br, '\n'); 1310 1311 if (sh.config.stripBrs == true) 1312 str = str.replace(br, ''); 1313 1314 return str; 1315 }; 1316 1317 /** 1318 * Removes all white space at the begining and end of a string. 1319 * 1320 * @param {String} str String to trim. 1321 * @return {String} Returns string without leading and following white space characters. 1322 */ 1323 function trim(str) 1324 { 1325 return str.replace(/^\s+|\s+$/g, ''); 1326 }; 1327 1328 /** 1329 * Unindents a block of text by the lowest common indent amount. 1330 * @param {String} str Text to unindent. 1331 * @return {String} Returns unindented text block. 1332 */ 1333 function unindent(str) 1334 { 1335 var lines = splitLines(fixInputString(str)), 1336 indents = new Array(), 1337 regex = /^\s*/, 1338 min = 1000 1339 ; 1340 1341 // go through every line and check for common number of indents 1342 for (var i = 0; i < lines.length && min > 0; i++) 1343 { 1344 var line = lines[i]; 1345 1346 if (trim(line).length == 0) 1347 continue; 1348 1349 var matches = regex.exec(line); 1350 1351 // In the event that just one line doesn't have leading white space 1352 // we can't unindent anything, so bail completely. 1353 if (matches == null) 1354 return str; 1355 1356 min = Math.min(matches[0].length, min); 1357 } 1358 1359 // trim minimum common number of white space from the begining of every line 1360 if (min > 0) 1361 for (var i = 0; i < lines.length; i++) 1362 lines[i] = lines[i].substr(min); 1363 1364 return lines.join('\n'); 1365 }; 1366 1367 /** 1368 * Callback method for Array.sort() which sorts matches by 1369 * index position and then by length. 1370 * 1371 * @param {Match} m1 Left object. 1372 * @param {Match} m2 Right object. 1373 * @return {Number} Returns -1, 0 or -1 as a comparison result. 1374 */ 1375 function matchesSortCallback(m1, m2) 1376 { 1377 // sort matches by index first 1378 if(m1.index < m2.index) 1379 return -1; 1380 else if(m1.index > m2.index) 1381 return 1; 1382 else 1383 { 1384 // if index is the same, sort by length 1385 if(m1.length < m2.length) 1386 return -1; 1387 else if(m1.length > m2.length) 1388 return 1; 1389 } 1390 1391 return 0; 1392 }; 1393 1394 /** 1395 * Executes given regular expression on provided code and returns all 1396 * matches that are found. 1397 * 1398 * @param {String} code Code to execute regular expression on. 1399 * @param {Object} regex Regular expression item info from <code>regexList</code> collection. 1400 * @return {Array} Returns a list of Match objects. 1401 */ 1402 function getMatches(code, regexInfo) 1403 { 1404 function defaultAdd(match, regexInfo) 1405 { 1406 return match[0]; 1407 }; 1408 1409 var index = 0, 1410 match = null, 1411 matches = [], 1412 func = regexInfo.func ? regexInfo.func : defaultAdd 1413 ; 1414 1415 while((match = regexInfo.regex.exec(code)) != null) 1416 { 1417 var resultMatch = func(match, regexInfo); 1418 1419 if (typeof(resultMatch) == 'string') 1420 resultMatch = [new sh.Match(resultMatch, match.index, regexInfo.css)]; 1421 1422 matches = matches.concat(resultMatch); 1423 } 1424 1425 return matches; 1426 }; 1427 1428 /** 1429 * Turns all URLs in the code into <a/> tags. 1430 * @param {String} code Input code. 1431 * @return {String} Returns code with </a> tags. 1432 */ 1433 function processUrls(code) 1434 { 1435 var gt = /(.*)((>|<).*)/; 1436 1437 return code.replace(sh.regexLib.url, function(m) 1438 { 1439 var suffix = '', 1440 match = null 1441 ; 1442 1443 // We include < and > in the URL for the common cases like <http://google.com> 1444 // The problem is that they get transformed into <http://google.com> 1445 // Where as > easily looks like part of the URL string. 1446 1447 if (match = gt.exec(m)) 1448 { 1449 m = match[1]; 1450 suffix = match[2]; 1451 } 1452 1453 return '<a href="' + m + '">' + m + '</a>' + suffix; 1454 }); 1455 }; 1456 1457 /** 1458 * Finds all <SCRIPT TYPE="syntaxhighlighter" /> elementss. 1459 * @return {Array} Returns array of all found SyntaxHighlighter tags. 1460 */ 1461 function getSyntaxHighlighterScriptTags() 1462 { 1463 var tags = document.getElementsByTagName('script'), 1464 result = [] 1465 ; 1466 1467 for (var i = 0; i < tags.length; i++) 1468 if (tags[i].type == 'syntaxhighlighter') 1469 result.push(tags[i]); 1470 1471 return result; 1472 }; 1473 1474 /** 1475 * Strips <![CDATA[]]> from <SCRIPT /> content because it should be used 1476 * there in most cases for XHTML compliance. 1477 * @param {String} original Input code. 1478 * @return {String} Returns code without leading <![CDATA[]]> tags. 1479 */ 1480 function stripCData(original) 1481 { 1482 var left = '<![CDATA[', 1483 right = ']]>', 1484 // for some reason IE inserts some leading blanks here 1485 copy = trim(original), 1486 changed = false, 1487 leftLength = left.length, 1488 rightLength = right.length 1489 ; 1490 1491 if (copy.indexOf(left) == 0) 1492 { 1493 copy = copy.substring(leftLength); 1494 changed = true; 1495 } 1496 1497 var copyLength = copy.length; 1498 1499 if (copy.indexOf(right) == copyLength - rightLength) 1500 { 1501 copy = copy.substring(0, copyLength - rightLength); 1502 changed = true; 1503 } 1504 1505 return changed ? copy : original; 1506 }; 1507 1508 1509 /** 1510 * Quick code mouse double click handler. 1511 */ 1512 function quickCodeHandler(e) 1513 { 1514 var target = e.target, 1515 highlighterDiv = findParentElement(target, '.syntaxhighlighter'), 1516 container = findParentElement(target, '.container'), 1517 textarea = document.createElement('textarea'), 1518 highlighter 1519 ; 1520 1521 if (!container || !highlighterDiv || findElement(container, 'textarea')) 1522 return; 1523 1524 highlighter = getHighlighterById(highlighterDiv.id); 1525 1526 // add source class name 1527 addClass(highlighterDiv, 'source'); 1528 1529 // Have to go over each line and grab it's text, can't just do it on the 1530 // container because Firefox loses all \n where as Webkit doesn't. 1531 var lines = container.childNodes, 1532 code = [] 1533 ; 1534 1535 for (var i = 0; i < lines.length; i++) 1536 code.push(lines[i].innerText || lines[i].textContent); 1537 1538 // using \r instead of \r or \r\n makes this work equally well on IE, FF and Webkit 1539 code = code.join('\r'); 1540 1541 // inject <textarea/> tag 1542 textarea.appendChild(document.createTextNode(code)); 1543 container.appendChild(textarea); 1544 1545 // preselect all text 1546 textarea.focus(); 1547 textarea.select(); 1548 1549 // set up handler for lost focus 1550 attachEvent(textarea, 'blur', function(e) 1551 { 1552 textarea.parentNode.removeChild(textarea); 1553 removeClass(highlighterDiv, 'source'); 1554 }); 1555 }; 1556 1557 /** 1558 * Match object. 1559 */ 1560 sh.Match = function(value, index, css) 1561 { 1562 this.value = value; 1563 this.index = index; 1564 this.length = value.length; 1565 this.css = css; 1566 this.brushName = null; 1567 }; 1568 1569 sh.Match.prototype.toString = function() 1570 { 1571 return this.value; 1572 }; 1573 1574 /** 1575 * Simulates HTML code with a scripting language embedded. 1576 * 1577 * @param {String} scriptBrushName Brush name of the scripting language. 1578 */ 1579 sh.HtmlScript = function(scriptBrushName) 1580 { 1581 var brushClass = findBrush(scriptBrushName), 1582 scriptBrush, 1583 xmlBrush = new sh.brushes.Xml(), 1584 bracketsRegex = null, 1585 ref = this, 1586 methodsToExpose = 'getDiv getHtml init'.split(' ') 1587 ; 1588 1589 if (brushClass == null) 1590 return; 1591 1592 scriptBrush = new brushClass(); 1593 1594 for(var i = 0; i < methodsToExpose.length; i++) 1595 // make a closure so we don't lose the name after i changes 1596 (function() { 1597 var name = methodsToExpose[i]; 1598 1599 ref[name] = function() 1600 { 1601 return xmlBrush[name].apply(xmlBrush, arguments); 1602 }; 1603 })(); 1604 1605 if (scriptBrush.htmlScript == null) 1606 { 1607 alert(sh.config.strings.brushNotHtmlScript + scriptBrushName); 1608 return; 1609 } 1610 1611 xmlBrush.regexList.push( 1612 { regex: scriptBrush.htmlScript.code, func: process } 1613 ); 1614 1615 function offsetMatches(matches, offset) 1616 { 1617 for (var j = 0; j < matches.length; j++) 1618 matches[j].index += offset; 1619 } 1620 1621 function process(match, info) 1622 { 1623 var code = match.code, 1624 matches = [], 1625 regexList = scriptBrush.regexList, 1626 offset = match.index + match.left.length, 1627 htmlScript = scriptBrush.htmlScript, 1628 result 1629 ; 1630 1631 // add all matches from the code 1632 for (var i = 0; i < regexList.length; i++) 1633 { 1634 result = getMatches(code, regexList[i]); 1635 offsetMatches(result, offset); 1636 matches = matches.concat(result); 1637 } 1638 1639 // add left script bracket 1640 if (htmlScript.left != null && match.left != null) 1641 { 1642 result = getMatches(match.left, htmlScript.left); 1643 offsetMatches(result, match.index); 1644 matches = matches.concat(result); 1645 } 1646 1647 // add right script bracket 1648 if (htmlScript.right != null && match.right != null) 1649 { 1650 result = getMatches(match.right, htmlScript.right); 1651 offsetMatches(result, match.index + match[0].lastIndexOf(match.right)); 1652 matches = matches.concat(result); 1653 } 1654 1655 for (var j = 0; j < matches.length; j++) 1656 matches[j].brushName = brushClass.brushName; 1657 1658 return matches; 1659 } 1660 }; 1661 1662 /** 1663 * Main Highlither class. 1664 * @constructor 1665 */ 1666 sh.Highlighter = function() 1667 { 1668 // not putting any code in here because of the prototype inheritance 1669 }; 1670 1671 sh.Highlighter.prototype = { 1672 /** 1673 * Returns value of the parameter passed to the highlighter. 1674 * @param {String} name Name of the parameter. 1675 * @param {Object} defaultValue Default value. 1676 * @return {Object} Returns found value or default value otherwise. 1677 */ 1678 getParam: function(name, defaultValue) 1679 { 1680 var result = this.params[name]; 1681 return toBoolean(result == null ? defaultValue : result); 1682 }, 1683 1684 /** 1685 * Shortcut to document.createElement(). 1686 * @param {String} name Name of the element to create (DIV, A, etc). 1687 * @return {HTMLElement} Returns new HTML element. 1688 */ 1689 create: function(name) 1690 { 1691 return document.createElement(name); 1692 }, 1693 1694 /** 1695 * Applies all regular expression to the code and stores all found 1696 * matches in the `this.matches` array. 1697 * @param {Array} regexList List of regular expressions. 1698 * @param {String} code Source code. 1699 * @return {Array} Returns list of matches. 1700 */ 1701 findMatches: function(regexList, code) 1702 { 1703 var result = []; 1704 1705 if (regexList != null) 1706 for (var i = 0; i < regexList.length; i++) 1707 // BUG: length returns len+1 for array if methods added to prototype chain (oising@gmail.com) 1708 if (typeof (regexList[i]) == "object") 1709 result = result.concat(getMatches(code, regexList[i])); 1710 1711 // sort and remove nested the matches 1712 return this.removeNestedMatches(result.sort(matchesSortCallback)); 1713 }, 1714 1715 /** 1716 * Checks to see if any of the matches are inside of other matches. 1717 * This process would get rid of highligted strings inside comments, 1718 * keywords inside strings and so on. 1719 */ 1720 removeNestedMatches: function(matches) 1721 { 1722 // Optimized by Jose Prado (http://joseprado.com) 1723 for (var i = 0; i < matches.length; i++) 1724 { 1725 if (matches[i] === null) 1726 continue; 1727 1728 var itemI = matches[i], 1729 itemIEndPos = itemI.index + itemI.length 1730 ; 1731 1732 for (var j = i + 1; j < matches.length && matches[i] !== null; j++) 1733 { 1734 var itemJ = matches[j]; 1735 1736 if (itemJ === null) 1737 continue; 1738 else if (itemJ.index > itemIEndPos) 1739 break; 1740 else if (itemJ.index == itemI.index && itemJ.length > itemI.length) 1741 matches[i] = null; 1742 else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos) 1743 matches[j] = null; 1744 } 1745 } 1746 1747 return matches; 1748 }, 1749 1750 /** 1751 * Creates an array containing integer line numbers starting from the 'first-line' param. 1752 * @return {Array} Returns array of integers. 1753 */ 1754 figureOutLineNumbers: function(code) 1755 { 1756 var lines = [], 1757 firstLine = parseInt(this.getParam('first-line')) 1758 ; 1759 1760 eachLine(code, function(line, index) 1761 { 1762 lines.push(index + firstLine); 1763 }); 1764 1765 return lines; 1766 }, 1767 1768 /** 1769 * Determines if specified line number is in the highlighted list. 1770 */ 1771 isLineHighlighted: function(lineNumber) 1772 { 1773 var list = this.getParam('highlight', []); 1774 1775 if (typeof(list) != 'object' && list.push == null) 1776 list = [ list ]; 1777 1778 return indexOf(list, lineNumber.toString()) != -1; 1779 }, 1780 1781 /** 1782 * Generates HTML markup for a single line of code while determining alternating line style. 1783 * @param {Integer} lineNumber Line number. 1784 * @param {String} code Line HTML markup. 1785 * @return {String} Returns HTML markup. 1786 */ 1787 getLineHtml: function(lineIndex, lineNumber, code) 1788 { 1789 var classes = [ 1790 'line', 1791 'number' + lineNumber, 1792 'index' + lineIndex, 1793 'alt' + (lineNumber % 2 == 0 ? 1 : 2).toString() 1794 ]; 1795 1796 if (this.isLineHighlighted(lineNumber)) 1797 classes.push('highlighted'); 1798 1799 if (lineNumber == 0) 1800 classes.push('break'); 1801 1802 return '<div class="' + classes.join(' ') + '">' + code + '</div>'; 1803 }, 1804 1805 /** 1806 * Generates HTML markup for line number column. 1807 * @param {String} code Complete code HTML markup. 1808 * @param {Array} lineNumbers Calculated line numbers. 1809 * @return {String} Returns HTML markup. 1810 */ 1811 getLineNumbersHtml: function(code, lineNumbers) 1812 { 1813 var html = '', 1814 count = splitLines(code).length, 1815 firstLine = parseInt(this.getParam('first-line')), 1816 pad = this.getParam('pad-line-numbers') 1817 ; 1818 1819 if (pad == true) 1820 pad = (firstLine + count - 1).toString().length; 1821 else if (isNaN(pad) == true) 1822 pad = 0; 1823 1824 for (var i = 0; i < count; i++) 1825 { 1826 var lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i, 1827 code = lineNumber == 0 ? sh.config.space : padNumber(lineNumber, pad) 1828 ; 1829 1830 html += this.getLineHtml(i, lineNumber, code); 1831 } 1832 1833 return html; 1834 }, 1835 1836 /** 1837 * Splits block of text into individual DIV lines. 1838 * @param {String} code Code to highlight. 1839 * @param {Array} lineNumbers Calculated line numbers. 1840 * @return {String} Returns highlighted code in HTML form. 1841 */ 1842 getCodeLinesHtml: function(html, lineNumbers) 1843 { 1844 html = trim(html); 1845 1846 var lines = splitLines(html), 1847 padLength = this.getParam('pad-line-numbers'), 1848 firstLine = parseInt(this.getParam('first-line')), 1849 html = '', 1850 brushName = this.getParam('brush') 1851 ; 1852 1853 for (var i = 0; i < lines.length; i++) 1854 { 1855 var line = lines[i], 1856 indent = /^( |\s)+/.exec(line), 1857 spaces = null, 1858 lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i; 1859 ; 1860 1861 if (indent != null) 1862 { 1863 spaces = indent[0].toString(); 1864 line = line.substr(spaces.length); 1865 spaces = spaces.replace(' ', sh.config.space); 1866 } 1867 1868 line = trim(line); 1869 1870 if (line.length == 0) 1871 line = sh.config.space; 1872 1873 html += this.getLineHtml( 1874 i, 1875 lineNumber, 1876 (spaces != null ? '<code class="' + brushName + ' spaces">' + spaces + '</code>' : '') + line 1877 ); 1878 } 1879 1880 return html; 1881 }, 1882 1883 /** 1884 * Returns HTML for the table title or empty string if title is null. 1885 */ 1886 getTitleHtml: function(title) 1887 { 1888 return title ? '<caption>' + title + '</caption>' : ''; 1889 }, 1890 1891 /** 1892 * Finds all matches in the source code. 1893 * @param {String} code Source code to process matches in. 1894 * @param {Array} matches Discovered regex matches. 1895 * @return {String} Returns formatted HTML with processed mathes. 1896 */ 1897 getMatchesHtml: function(code, matches) 1898 { 1899 var pos = 0, 1900 result = '', 1901 brushName = this.getParam('brush', '') 1902 ; 1903 1904 function getBrushNameCss(match) 1905 { 1906 var result = match ? (match.brushName || brushName) : brushName; 1907 return result ? result + ' ' : ''; 1908 }; 1909 1910 // Finally, go through the final list of matches and pull the all 1911 // together adding everything in between that isn't a match. 1912 for (var i = 0; i < matches.length; i++) 1913 { 1914 var match = matches[i], 1915 matchBrushName 1916 ; 1917 1918 if (match === null || match.length === 0) 1919 continue; 1920 1921 matchBrushName = getBrushNameCss(match); 1922 1923 result += wrapLinesWithCode(code.substr(pos, match.index - pos), matchBrushName + 'plain') 1924 + wrapLinesWithCode(match.value, matchBrushName + match.css) 1925 ; 1926 1927 pos = match.index + match.length + (match.offset || 0); 1928 } 1929 1930 // don't forget to add whatever's remaining in the string 1931 result += wrapLinesWithCode(code.substr(pos), getBrushNameCss() + 'plain'); 1932 1933 return result; 1934 }, 1935 1936 /** 1937 * Generates HTML markup for the whole syntax highlighter. 1938 * @param {String} code Source code. 1939 * @return {String} Returns HTML markup. 1940 */ 1941 getHtml: function(code) 1942 { 1943 var html = '', 1944 classes = [ 'syntaxhighlighter' ], 1945 tabSize, 1946 matches, 1947 lineNumbers 1948 ; 1949 1950 // process light mode 1951 if (this.getParam('light') == true) 1952 this.params.toolbar = this.params.gutter = false; 1953 1954 className = 'syntaxhighlighter'; 1955 1956 if (this.getParam('collapse') == true) 1957 classes.push('collapsed'); 1958 1959 if ((gutter = this.getParam('gutter')) == false) 1960 classes.push('nogutter'); 1961 1962 // add custom user style name 1963 classes.push(this.getParam('class-name')); 1964 1965 // add brush alias to the class name for custom CSS 1966 classes.push(this.getParam('brush')); 1967 1968 code = trimFirstAndLastLines(code) 1969 .replace(/\r/g, ' ') // IE lets these buggers through 1970 ; 1971 1972 tabSize = this.getParam('tab-size'); 1973 1974 // replace tabs with spaces 1975 code = this.getParam('smart-tabs') == true 1976 ? processSmartTabs(code, tabSize) 1977 : processTabs(code, tabSize) 1978 ; 1979 1980 // unindent code by the common indentation 1981 code = unindent(code); 1982 1983 if (gutter) 1984 lineNumbers = this.figureOutLineNumbers(code); 1985 1986 // find matches in the code using brushes regex list 1987 matches = this.findMatches(this.regexList, code); 1988 // processes found matches into the html 1989 html = this.getMatchesHtml(code, matches); 1990 // finally, split all lines so that they wrap well 1991 html = this.getCodeLinesHtml(html, lineNumbers); 1992 1993 // finally, process the links 1994 if (this.getParam('auto-links')) 1995 html = processUrls(html); 1996 1997 if (typeof(navigator) != 'undefined' && navigator.userAgent && navigator.userAgent.match(/MSIE/)) 1998 classes.push('ie'); 1999 2000 html = 2001 '<div id="' + getHighlighterId(this.id) + '" class="' + classes.join(' ') + '">' 2002 + (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '') 2003 + '<table border="0" cellpadding="0" cellspacing="0">' 2004 + this.getTitleHtml(this.getParam('title')) 2005 + '<tbody>' 2006 + '<tr>' 2007 + (gutter ? '<td class="gutter">' + this.getLineNumbersHtml(code) + '</td>' : '') 2008 + '<td class="code">' 2009 + '<div class="container">' 2010 + html 2011 + '</div>' 2012 + '</td>' 2013 + '</tr>' 2014 + '</tbody>' 2015 + '</table>' 2016 + '</div>' 2017 ; 2018 2019 return html; 2020 }, 2021 2022 /** 2023 * Highlights the code and returns complete HTML. 2024 * @param {String} code Code to highlight. 2025 * @return {Element} Returns container DIV element with all markup. 2026 */ 2027 getDiv: function(code) 2028 { 2029 if (code === null) 2030 code = ''; 2031 2032 this.code = code; 2033 2034 var div = this.create('div'); 2035 2036 // create main HTML 2037 div.innerHTML = this.getHtml(code); 2038 2039 // set up click handlers 2040 if (this.getParam('toolbar')) 2041 attachEvent(findElement(div, '.toolbar'), 'click', sh.toolbar.handler); 2042 2043 if (this.getParam('quick-code')) 2044 attachEvent(findElement(div, '.code'), 'dblclick', quickCodeHandler); 2045 2046 return div; 2047 }, 2048 2049 /** 2050 * Initializes the highlighter/brush. 2051 * 2052 * Constructor isn't used for initialization so that nothing executes during necessary 2053 * `new SyntaxHighlighter.Highlighter()` call when setting up brush inheritence. 2054 * 2055 * @param {Hash} params Highlighter parameters. 2056 */ 2057 init: function(params) 2058 { 2059 this.id = guid(); 2060 2061 // register this instance in the highlighters list 2062 storeHighlighter(this); 2063 2064 // local params take precedence over defaults 2065 this.params = merge(sh.defaults, params || {}) 2066 2067 // process light mode 2068 if (this.getParam('light') == true) 2069 this.params.toolbar = this.params.gutter = false; 2070 }, 2071 2072 /** 2073 * Converts space separated list of keywords into a regular expression string. 2074 * @param {String} str Space separated keywords. 2075 * @return {String} Returns regular expression string. 2076 */ 2077 getKeywords: function(str) 2078 { 2079 str = str 2080 .replace(/^\s+|\s+$/g, '') 2081 .replace(/\s+/g, '|') 2082 ; 2083 2084 return '\\b(?:' + str + ')\\b'; 2085 }, 2086 2087 /** 2088 * Makes a brush compatible with the `html-script` functionality. 2089 * @param {Object} regexGroup Object containing `left` and `right` regular expressions. 2090 */ 2091 forHtmlScript: function(regexGroup) 2092 { 2093 this.htmlScript = { 2094 left : { regex: regexGroup.left, css: 'script' }, 2095 right : { regex: regexGroup.right, css: 'script' }, 2096 code : new XRegExp( 2097 "(?<left>" + regexGroup.left.source + ")" + 2098 "(?<code>.*?)" + 2099 "(?<right>" + regexGroup.right.source + ")", 2100 "sgi" 2101 ) 2102 }; 2103 } 2104 }; // end of Highlighter 2105 2106 return sh; 2107 }(); // end of anonymous function 2108 2109 // CommonJS 2110 typeof(exports) != 'undefined' ? exports['SyntaxHighlighter'] = SyntaxHighlighter : null; 2111 </script><script type="text/javascript">// (inc clojure-brush) ;; an improved SyntaxHighlighter brush for clojure 2112 // 2113 // Copyright (C) 2011 Andrew Brehaut 2114 // 2115 // Distributed under the Eclipse Public License, the same as Clojure. 2116 // 2117 // https://github.com/brehaut/inc-clojure-brush 2118 // 2119 // Written by Andrew Brehaut 2120 // V0.9.1, November 2011 2121 2122 if (typeof net == "undefined") net = {}; 2123 if (!(net.brehaut)) net.brehaut = {}; 2124 2125 net.brehaut.ClojureTools = (function (SH) { 2126 "use strict"; 2127 // utiliies 2128 if (!Object.create) Object.create = function object(o) { 2129 function F() {}; 2130 F.prototype = o; 2131 return new F(); 2132 }; 2133 2134 // data 2135 2136 function Token(value, index, tag, length) { 2137 this.value = value; 2138 this.index = index; 2139 this.length = length || value.length; 2140 this.tag = tag; 2141 this.secondary_tags = {}; 2142 } 2143 2144 // null_token exists so that LispNodes that have not had a closing tag attached 2145 // can have a dummy token to simplify annotation 2146 var null_token = new Token("", -1, "null", -1); 2147 2148 /* LispNodes are aggregate nodes for sexpressions. 2149 * 2150 */ 2151 function LispNode(tag, children, opening) { 2152 this.tag = tag; // current metadata for syntax inference 2153 this.parent = null; // the parent expression 2154 this.list = children; // all the child forms in order 2155 this.opening = opening; // the token that opens this form. 2156 this.closing = null_token; // the token that closes this form. 2157 this.meta = null; // metadata nodes will be attached here if they are found 2158 } 2159 2160 var null_lispnode = new LispNode("null", [], null_token); 2161 2162 2163 function PrefixNode(tag, token, attached_node) { 2164 this.tag = tag; 2165 this.token = token; 2166 this.attached_node = attached_node; 2167 this.parent = null; 2168 } 2169 2170 2171 2172 // tokenize 2173 2174 function tokenize(code) { 2175 var tokens = []; 2176 var tn = 0; 2177 2178 var zero = "0".charCodeAt(0); 2179 var nine = "9".charCodeAt(0); 2180 var lower_a = "a".charCodeAt(0); 2181 var lower_f = "f".charCodeAt(0); 2182 var upper_a = "A".charCodeAt(0); 2183 var upper_f = "F".charCodeAt(0); 2184 2185 var dispatch = false; // have we just seen a # character? 2186 2187 // i tracks the start of the current window 2188 // extent is the window for slicing 2189 2190 for (var i = 0, 2191 extent = i, 2192 j = code.length; 2193 i < j && extent <= j;) { 2194 2195 var c = code[i]; 2196 2197 // we care about capturing the whole token when dispatch is used, so back up the 2198 // starting index by 1 2199 if (dispatch) i--; 2200 2201 switch (c) { 2202 // dispatch alters the value of the next thing read 2203 case "#": 2204 dispatch = true; 2205 i++; 2206 extent++; 2207 continue; 2208 2209 case " ": // ignore whitespace 2210 case "\t": 2211 case "\n": 2212 case "\r": 2213 case ",": 2214 extent++ 2215 break; 2216 2217 // simple terms 2218 case "^": 2219 case "`": 2220 case ")": 2221 case "[": 2222 case "]": 2223 case "}": 2224 case "@": 2225 tokens[tn++] = new Token(c, i, c, ++extent - i); 2226 break; 2227 2228 case "'": 2229 tokens[tn++] = new Token(code.slice(i, ++extent), i, dispatch ? "#'" : "'", extent - i); 2230 break 2231 2232 case "(": 2233 tokens[tn++] = new Token(code.slice(i, ++extent), i, "(", extent - i); 2234 break; 2235 2236 case "{": 2237 tokens[tn++] = new Token(code.slice(i, ++extent), i, dispatch ? "#{" : "{", extent - i); 2238 break; 2239 2240 case "\\": 2241 if (code.slice(i + 1, i + 8) === "newline") { 2242 tokens[tn++] = new Token("\\newline", i, "value", 8); 2243 extent = i + 9; 2244 } 2245 else if (code.slice(i + 1, i + 6) === "space") { 2246 tokens[tn++] = new Token("\\space", i, "value", 6); 2247 extent = i + 6; 2248 } 2249 else if (code.slice(i + 1, i + 4) === "tab") { 2250 tokens[tn++] = new Token("\\tab", i, "value", 4); 2251 extent = i + 5; 2252 } // work around fun bug with &,>,< in character literals 2253 else if (code.slice(i + 1, i + 6) === "&") { 2254 tokens[tn++] = new Token("\\&", i, "value", 6); 2255 extent = i + 6; 2256 } 2257 else if (code.slice(i + 1, i + 5) === "<") { 2258 tokens[tn++] = new Token("\\<", i, "value", 5); 2259 extent = i + 5; 2260 } 2261 else if (code.slice(i + 1, i + 5) === ">") { 2262 tokens[tn++] = new Token("\\>", i, "value", 5); 2263 extent = i + 5; 2264 } 2265 2266 else { 2267 extent += 2; 2268 tokens[tn++] = new Token(code.slice(i, extent), i, "value", 2); 2269 } 2270 break; 2271 2272 case "~": // slice 2273 if (code[i + 1] === "@") { 2274 extent += 2; 2275 tokens[tn++] = new Token(code.slice(i, extent), i, "splice", 2); 2276 } 2277 else { 2278 tokens[tn++] = new Token(code.slice(i, ++extent), i, "unquote", 2); 2279 } 2280 break; 2281 2282 // complicated terms 2283 case "\"": // strings and regexps 2284 for (extent++; extent <= j; extent++) { 2285 if (code[extent] === "\\") extent++; 2286 else if (code[extent] === "\"") break; 2287 } 2288 tokens[tn++] = new Token(code.slice(i, ++extent), i, dispatch ? "regexp" : "string", extent - i); 2289 break; 2290 2291 case ";": 2292 for (; extent <= j && code[extent] !== "\n" && code[extent] !== "\r"; extent++); 2293 tokens[tn++] = new Token(code.slice(i, ++extent), i, "comments", extent - i); 2294 break; 2295 2296 case "+": // numbers; fall through to symbol for + and - not prefixing a number 2297 case "-": 2298 case "0": 2299 case "1": 2300 case "2": 2301 case "3": 2302 case "4": 2303 case "5": 2304 case "6": 2305 case "7": 2306 case "8": 2307 case "9": 2308 // todo: exponents, hex 2309 // http://my.safaribooksonline.com/9781449310387/14?reader=pf&readerfullscreen=&readerleftmenu=1 2310 var c2 = code.charCodeAt(i + 1); 2311 if (((c === "+" || c === "-") && (c2 >= zero && c2 <= nine)) // prefixes 2312 || (c !== "+" && c !== "-")) { 2313 if (c === "+" || c === "-") extent++; 2314 for (; extent <= j; extent++) { 2315 var charCode = code.charCodeAt(extent); 2316 if (charCode < zero || charCode > nine) break; 2317 } 2318 2319 c = code[extent]; 2320 c2 = code.charCodeAt(extent + 1); 2321 if ((c === "r" || c === "R" || c === "/" || c === ".") // interstitial characters 2322 && (c2 >= zero && c2 <= nine)) { 2323 for (extent++; extent <= j; extent++) { 2324 var charCode = code.charCodeAt(extent); 2325 if (charCode < zero || charCode > nine) break; 2326 } 2327 } 2328 2329 c = code[extent]; 2330 c2 = code.charCodeAt(extent + 1); 2331 if ((c === "x" || c === "X") && 2332 ((c2 >= zero && c2 <= nine) 2333 || (c2 >= lower_a && c2 <= lower_f) 2334 || (c2 >= upper_a && c2 <= upper_f))) { 2335 for (extent++; extent <= j; extent++) { 2336 var charCode = code.charCodeAt(extent); 2337 if (((charCode >= zero && charCode <= nine) 2338 || (charCode >= lower_a && charCode <= lower_f) 2339 || (charCode >= upper_a && charCode <= upper_f))) continue; 2340 break; 2341 } 2342 } 2343 2344 c = code[extent]; 2345 c2 = code.charCodeAt(extent + 1); 2346 if ((c === "e" || c === "E") 2347 && (c2 >= zero && c2 <= nine)) { 2348 for (extent++; extent <= j; extent++) { 2349 var charCode = code.charCodeAt(extent); 2350 if (charCode < zero || charCode > nine) break; 2351 } 2352 } 2353 2354 c = code[extent]; 2355 if (c === "N" || c === "M") extent++; 2356 2357 tokens[tn++] = new Token(code.slice(i, extent), i, "value", extent - i); 2358 break; 2359 } 2360 2361 case "_": 2362 if (dispatch && c === "_") { 2363 tokens[tn++] = new Token(code.slice(i, ++extent), i, "skip", extent - i); 2364 break; 2365 } // if not a skip, fall through to symbols 2366 2367 // Allow just about any other symbol as a symbol. This is far more permissive than 2368 // clojure actually allows, but should catch any weirdo crap that accidentally gets 2369 // into the code. 2370 default: 2371 for (extent++; extent <= j; extent++) { 2372 switch (code[extent]) { 2373 case " ": 2374 case "\t": 2375 case "\n": 2376 case "\r": 2377 case "\\": 2378 case ",": 2379 case "{": 2380 case "}": 2381 case "(": 2382 case ")": 2383 case "[": 2384 case "]": 2385 case "^": 2386 case "`": 2387 case "@": 2388 break; 2389 case ";": 2390 // theres a weird bug via syntax highligher that gives us escaped entities. 2391 // need to watch out for these 2392 if (code.slice(extent-3, extent+1) === "<" 2393 ||code.slice(extent-3, extent+1) === ">" 2394 ||code.slice(extent-4, extent+1) === "&") { 2395 continue; 2396 } 2397 break; 2398 default: 2399 continue; 2400 } 2401 break; 2402 } 2403 2404 var value = code.slice(i, extent); 2405 var tag = "symbol"; 2406 if (value[0] == ":") { 2407 tag = "keyword"; 2408 } 2409 else if (value === "true" || value === "false" || value === "nil") { 2410 tag = "value"; 2411 } 2412 tokens[tn++] = new Token(value, i, tag, extent - i); 2413 } 2414 2415 dispatch = false; 2416 i = extent; 2417 } 2418 2419 return tokens; 2420 } 2421 2422 2423 function build_tree(tokens) { 2424 var toplevel = { 2425 list: [], 2426 tag: "toplevel", 2427 parent: null, 2428 opening: null, 2429 closing: null, 2430 depth: -1 2431 }; 2432 2433 // loop variables hoisted out as semi globals to track position in token stream 2434 var i = -1; 2435 var j = tokens.length; 2436 2437 function parse_one(t) { 2438 // ignore special tokens and forms that dont belong in the tree 2439 for (; t && (t.tag === "comments" || t.tag === "invalid" || t.tag == "skip") && i < j; ) { 2440 if (t.tag === "skip") { 2441 t.tag = "preprocessor"; 2442 annotate_comment(parse_one(tokens[++i])); 2443 } 2444 t = tokens[++i]; 2445 } 2446 2447 if (!t) return {}; // hackity hack 2448 2449 switch (t.tag) { 2450 case "{": 2451 return build_aggregate(new LispNode("map", [], t), "}"); 2452 case "(": 2453 return build_aggregate(new LispNode("list", [], t), ")"); 2454 case "#{": 2455 return build_aggregate(new LispNode("set", [], t), "}"); 2456 case "[": 2457 return build_aggregate(new LispNode("vector", [], t), "]"); 2458 case "'": 2459 return new PrefixNode("quote", t, parse_one(tokens[++i])); 2460 case "#'": 2461 return new PrefixNode("varquote", t, parse_one(tokens[++i])); 2462 case "@": 2463 return new PrefixNode("deref", t, parse_one(tokens[++i])); 2464 case "`": 2465 return new PrefixNode("quasiquote", t, parse_one(tokens[++i])); 2466 case "unquote": 2467 return new PrefixNode("unquote", t, parse_one(tokens[++i])); 2468 case "splice": 2469 return new PrefixNode("splice", t, parse_one(tokens[++i])); 2470 case "^": 2471 t.tag = "meta"; 2472 var meta = parse_one(tokens[++i]); 2473 var next = parse_one(tokens[++i]); 2474 next.meta = meta; 2475 return next; 2476 } 2477 2478 return t; 2479 } 2480 2481 // build_aggregate collects to ether sub forms for one aggregate for. 2482 function build_aggregate(current, expected_closing) { 2483 for (i++; i < j; i++) { 2484 var t = tokens[i]; 2485 2486 if (t.tag === "}" || t.tag === ")" || t.tag === "]") { 2487 if (t.tag !== expected_closing) t.tag = "invalid"; 2488 current.closing = t; 2489 if (expected_closing) return current; 2490 } 2491 var node = parse_one(t); 2492 2493 node.parent = current; 2494 current.list[current.list.length] = node; 2495 } 2496 2497 return current; 2498 } 2499 2500 build_aggregate(toplevel, null); 2501 2502 return toplevel; 2503 } 2504 2505 // annotation rules to apply to a form based on its head 2506 2507 var show_locals = true; // HACK. would rather not use a (semi)-global. 2508 2509 /* annotate_comment is a special case annotation. 2510 * in addition to its role in styling specific forms, it is called by parse_one to 2511 * ignore any forms skipped with #_ 2512 */ 2513 function annotate_comment(exp) { 2514 exp.tag = "comments"; 2515 2516 if (exp.list) { 2517 exp.opening.tag = "comments"; 2518 exp.closing.tag = "comments"; 2519 2520 for (var i = 0; i < exp.list.length; i++) { 2521 var child = exp.list[i]; 2522 if (child.list) { 2523 annotate_comment(child); 2524 } 2525 if (child.attached_node) { 2526 annotate_comment(child.attached_node); 2527 } 2528 else { 2529 child.tag = "comments"; 2530 } 2531 } 2532 } 2533 } 2534 2535 /* custom annotation rules are stored here */ 2536 var annotation_rules = {}; 2537 2538 // this function is exposed to allow ad hoc extension of the customisation rules 2539 function register_annotation_rule(names, rule) { 2540 for (var i = 0; i < names.length; i++) { 2541 annotation_rules[names[i]] = rule; 2542 } 2543 } 2544 2545 2546 function annotate_destructuring (exp, scope) { 2547 if (exp.list) { 2548 if (exp.tag === "vector") { 2549 for (var i = 0; i < exp.list.length; i++) { 2550 annotate_destructuring(exp.list[i], scope); 2551 } 2552 } 2553 else if (exp.tag === "map") { 2554 for (var i = 0; i < exp.list.length; i += 2) { 2555 var key = exp.list[i]; 2556 var val = exp.list[i + 1]; 2557 2558 if (key.tag === "keyword" && val.tag === "vector") { 2559 for (var ii = 0, jj = val.list.length; ii < jj; ii++) { 2560 if (val.list[ii].tag !== "symbol") continue; 2561 val.list[ii].tag = "variable"; 2562 scope[val.list[ii].value] = true; 2563 } 2564 } 2565 else { 2566 annotate_destructuring(key, scope); 2567 annotate_expressions(val, scope); 2568 } 2569 } 2570 } 2571 } 2572 else if (exp.tag === "symbol" && (exp.value !== "&" && exp.value !== "&")){ 2573 exp.tag = "variable"; 2574 scope[exp.value] = true; 2575 } 2576 } 2577 2578 function _annotate_binding_vector (exp, scope) { 2579 if (exp.tag !== "vector") return; 2580 2581 var bindings = exp.list; 2582 2583 if (bindings.length % 2 === 1) return; 2584 2585 for (var i = 0; i < bindings.length; i += 2) { 2586 annotate_destructuring(bindings[i], scope); 2587 annotate_expressions(bindings[i + 1], scope); 2588 } 2589 } 2590 2591 function annotate_binding (exp, scope) { 2592 var bindings = exp.list[1]; 2593 if (!show_locals) return; // HACK 2594 2595 if (bindings) { 2596 scope = Object.create(scope); 2597 _annotate_binding_vector(bindings, scope); 2598 } 2599 for (var i = 2; i < exp.list.length; i++) { 2600 annotate_expressions(exp.list[i], scope); 2601 } 2602 } 2603 2604 function _annotate_function_body (exp, scope, start_idx) { 2605 var argvec = exp.list[start_idx]; 2606 if (argvec.tag !== "vector") return; 2607 2608 scope = Object.create(scope); 2609 2610 for (var i = 0, j = argvec.list.length; i < j; i++) { 2611 annotate_destructuring(argvec.list[i], scope); 2612 } 2613 2614 for (var i = start_idx, j = exp.list.length; i < j; i++) { 2615 annotate_expressions(exp.list[i], scope); 2616 } 2617 } 2618 2619 function annotate_function (exp, scope) { 2620 for (var i = 1, j = exp.list.length; i < j; i++) { 2621 var child = exp.list[i]; 2622 2623 if (child.tag === "vector") { 2624 _annotate_function_body (exp, scope, i); 2625 return; 2626 } 2627 else if (child.tag === "list") { 2628 _annotate_function_body(child, scope, 0) 2629 } 2630 } 2631 } 2632 2633 function annotate_letfn (exp, scope) { 2634 scope = Object.create(scope); 2635 var bindings = exp.list[1]; 2636 2637 var fn; 2638 for (var i = 0, j = bindings.list.length; i < j; i++) { 2639 fn = bindings.list[i]; 2640 if (!fn.list[0]) continue; 2641 fn.list[0].tag = "variable"; 2642 scope[fn.list[0].value] = true; 2643 } 2644 2645 for (i = 0, j = bindings.list.length; i < j; i++) { 2646 var fn = bindings.list[i]; 2647 annotate_function(fn, scope); 2648 } 2649 2650 for (i = 2, j = exp.list.length; i < j; i++) { 2651 annotate_expressions(exp.list[i], scope); 2652 } 2653 } 2654 2655 register_annotation_rule( 2656 ["comment"], 2657 annotate_comment 2658 ); 2659 2660 register_annotation_rule( 2661 ["let", "when-let", "if-let", "binding", "doseq", "for", "dotimes", "let*"], 2662 annotate_binding 2663 ); 2664 2665 register_annotation_rule( 2666 ["defn", "defn-", "fn", "bound-fn", "defmacro", "fn*", "defmethod"], 2667 annotate_function 2668 ); 2669 2670 register_annotation_rule( 2671 ["letfn"], 2672 annotate_letfn 2673 ); 2674 2675 // standard annotations 2676 2677 function _annotate_metadata_recursive(meta, scope) { 2678 if (!meta) return; 2679 2680 if (meta.list !== undefined && meta.list !== null) { 2681 for (var i = 0, j = meta.list.length; i < j; i++) { 2682 meta.opening.secondary_tags.meta = true 2683 meta.closing.secondary_tags.meta = true 2684 _annotate_metadata_recursive(meta.list[i], scope); 2685 } 2686 } 2687 else if (meta.attached_node) { 2688 meta.token.secondary_tags.meta = true; 2689 _annotate_metadata_recursive(meta.attached_node, scope); 2690 } 2691 else { 2692 meta.secondary_tags.meta = true; 2693 } 2694 } 2695 2696 function annotate_metadata(exp) { 2697 if (!(exp && exp.meta)) return; 2698 var meta = exp.meta; 2699 2700 annotate_expressions(meta, {}); 2701 _annotate_metadata_recursive(meta, {}); 2702 } 2703 2704 2705 function annotate_quoted(exp, scope) { 2706 if (!exp) return; 2707 2708 if (exp.list !== undefined && exp.list !== null) { 2709 for (var i = 0, j = exp.list.length; i < j; i++) { 2710 exp.opening.secondary_tags.quoted = true 2711 exp.closing.secondary_tags.quoted = true 2712 annotate_quoted(exp.list[i], scope); 2713 } 2714 } 2715 else if (exp.attached_node) { 2716 if (exp.tag === "unquote" || exp.tag === "splice") return; 2717 exp.token.secondary_tags.quoted = true; 2718 annotate_quoted(exp.attached_node, scope); 2719 } 2720 else { 2721 exp.secondary_tags.quoted = true; 2722 } 2723 } 2724 2725 2726 function annotate_expressions(exp, scope) { 2727 annotate_metadata(exp); 2728 2729 switch (exp.tag) { 2730 case "toplevel": 2731 for (var i = 0; i < exp.list.length; i++) { 2732 annotate_expressions(exp.list[i], scope); 2733 } 2734 break; 2735 2736 case "list": // functions, macros, special forms, comments 2737 var head = exp.list[0]; 2738 2739 if (head) { 2740 if (head.tag === "list" || head.tag === "vector" 2741 || head.tag === "map" || head.tag === "set") { 2742 annotate_expressions(head, scope); 2743 } 2744 else if (head.attached_node) { 2745 annotate_expressions(head.attached_node, scope); 2746 } 2747 else { 2748 head.tag = (head.value.match(/(^\.)|(\.$)|[A-Z].*\//) 2749 ? "method" 2750 : "function"); 2751 } 2752 2753 // apply specific rules 2754 if (annotation_rules.hasOwnProperty(head.value)) { 2755 annotation_rules[head.value](exp, scope); 2756 } 2757 else { 2758 for (var i = 1; i < exp.list.length; i++) { 2759 annotate_expressions(exp.list[i], scope); 2760 } 2761 } 2762 } 2763 else { // empty list 2764 exp.opening.tag = "value"; 2765 exp.closing.tag = "value"; 2766 } 2767 2768 break; 2769 2770 case "vector": // data 2771 case "map": 2772 case "set": 2773 for (var i = 0; i < exp.list.length; i++) { 2774 annotate_expressions(exp.list[i], scope); 2775 } 2776 break; 2777 2778 case "symbol": 2779 if (exp.value.match(/[A-Z].*\/[A-Z_]+/)) { 2780 exp.tag = "constant"; 2781 } 2782 else if (show_locals && scope[exp.value]) { 2783 exp.tag = "variable"; 2784 } 2785 else if (exp.tag === "symbol" && exp.value.match(/([A-Z].*\/)?[A-Z_]+/)) { 2786 exp.tag = "type"; 2787 } 2788 break; 2789 2790 case "quote": 2791 case "quasiquote": 2792 annotate_quoted(exp.attached_node, scope); 2793 2794 default: 2795 if (exp.attached_node) annotate_expressions(exp.attached_node, scope); 2796 } 2797 } 2798 2799 // translation of tag to css: 2800 var css_translation = { 2801 "constant": "constants", 2802 "keyword": "constants", 2803 "method": "color1", 2804 "type": "color3", 2805 "function": "functions", 2806 "string": "string", 2807 "regexp": "string", 2808 "value": "value", 2809 "comments": "comments", 2810 "symbol": "symbol", 2811 "variable": "variable", 2812 "splice": "preprocessor", 2813 "unquote": "preprocessor", 2814 "preprocessor": "preprocessor", 2815 "meta": "preprocessor", 2816 "'": "preprocessor", 2817 "#'": "preprocessor", 2818 "(": "plain", 2819 ")": "plain", 2820 "{": "keyword", 2821 "}": "keyword", 2822 "#{": "keyword", 2823 "[": "keyword", 2824 "]": "keyword", 2825 "invalid": "invalid", 2826 "@": "plain" 2827 }; 2828 2829 function translate_tags_to_css(tokens) { 2830 for (var i = 0, j = tokens.length; i < j; i++) { 2831 var token = tokens[i]; 2832 token.css = css_translation[token.tag]; 2833 for (var k in token.secondary_tags) if (token.secondary_tags.hasOwnProperty(k)) 2834 token.css += " " + k ; 2835 }; 2836 } 2837 2838 2839 // create the new brush 2840 2841 SH.brushes.Clojure = function () {}; 2842 SH.brushes.Clojure.prototype = new SyntaxHighlighter.Highlighter(); 2843 2844 SH.brushes.Clojure.prototype.findMatches = function find_matches (regexpList, code) { 2845 // this is a nasty global hack. need to resolve this 2846 if (this.params && this.params.locals) { 2847 show_locals = this.params.locals === true || this.params.locals === "true"; 2848 } 2849 else { 2850 show_locals = true; 2851 } 2852 2853 var tokens = tokenize(code); 2854 annotate_expressions(build_tree(tokens), {}); 2855 translate_tags_to_css(tokens); 2856 2857 return tokens; 2858 }; 2859 2860 SH.brushes.Clojure.aliases = ['clojure', 'Clojure', 'clj']; 2861 SH.brushes.Clojure.register_annotation_rule = register_annotation_rule; 2862 2863 return { 2864 tokenize: tokenize, 2865 build_tree: build_tree 2866 }; 2867 })(SyntaxHighlighter); 2868 </script><title>selmer -- Marginalia</title></head><body><table><tr><td class="docs"><div class="header"><h1 class="project-name"><a href="https://github.com/yogthos/Selmer">selmer</a></h1><h2 class="project-version">1.11.1</h2><br /><p>Django style templates for Clojure</p> 2869 </div><div class="dependencies"><h3>dependencies</h3><table><tr><td class="dep-name">org.clojure/clojure</td><td class="dotted"><hr /></td><td class="dep-version">1.7.0</td></tr><tr><td class="dep-name">criterium</td><td class="dotted"><hr /></td><td class="dep-version">0.4.4</td></tr><tr><td class="dep-name">joda-time</td><td class="dotted"><hr /></td><td class="dep-version">2.9.6</td></tr><tr><td class="dep-name">commons-codec</td><td class="dotted"><hr /></td><td class="dep-version">1.10</td></tr><tr><td class="dep-name">json-html</td><td class="dotted"><hr /></td><td class="dep-version">0.4.0</td></tr><tr><td class="dep-name">cheshire</td><td class="dotted"><hr /></td><td class="dep-version">5.6.3</td></tr></table></div></td><td class="codes" style="text-align: center; vertical-align: middle;color: #666;padding-right:20px"><br /><br /><br />(this space intentionally left almost blank)</td></tr><tr><td class="docs"><div class="toc"><a name="toc"><h3>namespaces</h3></a><ul><li><a href="#selmer.filter-parser">selmer.filter-parser</a></li><li><a href="#selmer.filters">selmer.filters</a></li><li><a href="#selmer.middleware">selmer.middleware</a></li><li><a href="#selmer.node">selmer.node</a></li><li><a href="#selmer.parser">selmer.parser</a></li><li><a href="#selmer.tags">selmer.tags</a></li><li><a href="#selmer.template-parser">selmer.template-parser</a></li><li><a href="#selmer.util">selmer.util</a></li><li><a href="#selmer.validator">selmer.validator</a></li></ul></div></td><td class="codes"> </td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.filter-parser" name="selmer.filter-parser"><h1 class="project-name">selmer.filter-parser</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>Accessors are separated by dots like {{ foo.bar.0 }} 2870 which gets translated into (get-in context-map [:foo :bar 0]). So you 2871 can nest vectors and maps in your context-map.</p> 2872 2873 <p>Filters can be applied by separating then from the accessor 2874 with pipes: {{ foo|lower|capitalize }}. They are applied one after 2875 the other from left to right. Arguments can be passed to a filter 2876 separated by colons: {{ foo|pluralize:y:ies }}. If an argument includes 2877 spaces you can enclose it with doublequotes or colons: {{ foo|join:", " }}.</p> 2878 2879 <p>You can escape doublequotes inside doublequotes. And you can put colons 2880 inside doublequotes which will be ignored for the purpose of separating 2881 arguments.</p> 2882 </td><td class="codes"><pre class="brush: clojure">(ns selmer.filter-parser 2883 (:require [selmer.filters :refer [get-filter]] 2884 [selmer.util :refer [exception *escape-variables*]] 2885 [clojure.string :as s]))</pre></td></tr><tr><td class="docs"><p>More Utils</p> 2886 </td><td class="codes"><pre class="brush: clojure">(defn escape-html* 2887 [^String s] 2888 "HTML-escapes the given string. Escapes the same characters as django's escape." 2889 ;; This method is "Java in Clojure" for serious speedups. 2890 ;; Stolen from davidsantiago/quoin and modified. 2891 (if *escape-variables* 2892 (let [sb (StringBuilder.) 2893 slength (count s)] 2894 (loop [idx 0] 2895 (if (>= idx slength) 2896 (.toString sb) 2897 (let [c (char (.charAt s idx))] 2898 (case c 2899 \& (.append sb "&amp;") 2900 \< (.append sb "&lt;") 2901 \> (.append sb "&gt;") 2902 \" (.append sb "&quot;") 2903 \' (.append sb "&#39;") 2904 (.append sb c)) 2905 (recur (inc idx)))))) 2906 s))</pre></td></tr><tr><td class="docs"><p>Removes doublequotes from the start and end of a string if any.</p> 2907 </td><td class="codes"><pre class="brush: clojure">(defn strip-doublequotes 2908 [^String s] 2909 (if (and (> (count s) 1) 2910 (= \" (first s) (.charAt s (dec (count s))))) 2911 (.substring s 1 (dec (count s))) 2912 s))</pre></td></tr><tr><td class="docs"><p>Must have the form [:safe safe-string] to prevent escaping. Alternatively, 2913 you can call selmer.util/turn-off-escaping! to turn it off completely.</p> 2914 </td><td class="codes"><pre class="brush: clojure">(defn escape-html 2915 [x] 2916 (if (and (vector? x) 2917 (= :safe (first x))) 2918 (second x) 2919 (let [s (str x)] 2920 (escape-html* s))))</pre></td></tr><tr><td class="docs"><p>Turns strings into keywords and strings like "0" into Longs 2921 so it can access vectors as well as maps.</p> 2922 2923 <p>Compile filters</p> 2924 </td><td class="codes"><pre class="brush: clojure">(defn fix-accessor 2925 [ks] 2926 (mapv (fn [^String s] 2927 (try (Long/valueOf s) 2928 (catch NumberFormatException _ 2929 (keyword s)))) 2930 ks))</pre></td></tr><tr><td class="docs"><p>Split accessors like foo.bar.baz by the dot. 2931 But if there is a double dot '..' then it will leave it</p> 2932 </td><td class="codes"><pre class="brush: clojure">(defn split-filter-val 2933 [s] 2934 (let [ks (clojure.string/split s #"(?<!\.)\.(?!\.)") 2935 kss (map 2936 (fn [s] (clojure.string/replace s ".." ".")) ks)] ;we remove the double dot here 2937 (fix-accessor kss)))</pre></td></tr><tr><td class="docs"><p>Map any sort of needed fixes to the arguments before passing them 2938 to the filters. Only strips enclosing doublequotes for now.</p> 2939 </td><td class="codes"><pre class="brush: clojure">(defn fix-filter-args 2940 [args] 2941 ;; TODO - figure out what kind of extra args filters can take 2942 (map (fn [^String s] 2943 (strip-doublequotes s)) 2944 args))</pre></td></tr><tr><td class="docs"><p>Given a context map, return a function that accepts a filter 2945 argument and if it begins with @, return the value from the 2946 context map instead of treating it as a literal.</p> 2947 </td><td class="codes"><pre class="brush: clojure">(defn lookup-args 2948 [context-map] 2949 (fn [^String arg] 2950 (if (and (> (count arg) 1) (.startsWith arg "@")) 2951 (let [accessor (split-filter-val (subs arg 1))] 2952 (get-in context-map accessor arg)) 2953 arg)))</pre></td></tr><tr><td class="docs"><p>Turns a filter string like "pluralize:y:ies" into a function that 2954 expects a value obtained from a context map or from a previously 2955 applied filter.</p> 2956 </td><td class="codes"><pre class="brush: clojure">(defn filter-str->fn 2957 [s] 2958 (let [[filter-name & args] 2959 ;; Ignore colons inside doublequotes 2960 (re-seq #"(?:[^:\"]|\"[^\"]*\")+" s) 2961 args (fix-filter-args args) 2962 filter (get-filter filter-name)] 2963 (if filter 2964 (fn [x context-map] 2965 (apply filter x (map (lookup-args context-map) args))) 2966 (exception "No filter defined with the name '" filter-name "'"))))</pre></td></tr><tr><td class="docs"> 2967 </td><td class="codes"><pre class="brush: clojure">(def safe-filter ::selmer-safe-filter)</pre></td></tr><tr><td class="docs"> 2968 </td><td class="codes"><pre class="brush: clojure">(defn- literal? [^String val] 2969 (or 2970 (and (.startsWith val "\) (.endsWith val "\)) 2971 (re-matches #"[0-9]+" val)))</pre></td></tr><tr><td class="docs"> 2972 </td><td class="codes"><pre class="brush: clojure">(defn- parse-literal [^String val] 2973 (if (.startsWith val "\) 2974 (subs val 1 (dec (count val))) 2975 val))</pre></td></tr><tr><td class="docs"> 2976 </td><td class="codes"><pre class="brush: clojure">(defn- apply-filters [val s filter-strs filters context-map] 2977 (reduce 2978 (fn [acc [filter-str filter]] 2979 (try (filter acc context-map) 2980 (catch Exception e 2981 (exception 2982 "On filter body '" s "' and filter '" filter-str "' this error occurred:" (.getMessage e))))) 2983 val 2984 (map vector filter-strs filters)))</pre></td></tr><tr><td class="docs"> 2985 </td><td class="codes"><pre class="brush: clojure">(defn get-accessor [m k] 2986 "Returns the value of `k` from map `m`, either as a keyword or string lookup." 2987 (or (get m k) 2988 (when (keyword? k) 2989 (if-let [n (namespace k)] 2990 (get m (str n "/" (name k))) 2991 (get m (name k))))))</pre></td></tr><tr><td class="docs"><p>Turns a string like foo|filter1:x|filter2:y into a fn that expects a 2992 context-map and will apply the filters one after the other to the value 2993 from the map. It will escape the end result unless the last 2994 filter is "safe" or when it's called with escape? equal to true, 2995 which is the default behavior.</p> 2996 </td><td class="codes"><pre class="brush: clojure">(defn compile-filter-body 2997 ([s] (compile-filter-body s true)) 2998 ([s escape?] 2999 (let [[val & filter-strs] (->> s 3000 (s/trim) 3001 ;; Ignore pipes and allow escaped doublequotes inside doublequotes 3002 (re-seq #"(?:[^|\"]|\"[^\"]*\")+")) 3003 accessor (split-filter-val val) 3004 filters (map filter-str->fn filter-strs)] 3005 (if (literal? val) 3006 (fn [context-map] 3007 (apply-filters 3008 (parse-literal val) 3009 s 3010 filter-strs 3011 filters 3012 context-map)) 3013 (fn [context-map] 3014 (let [val (reduce get-accessor context-map accessor)] 3015 (when (or val (and selmer.util/*filter-missing-values* (seq filters))) 3016 (let [x (apply-filters 3017 val 3018 s 3019 filter-strs 3020 filters 3021 context-map)] 3022 ;; Escape by default unless the last filter is 'safe' or safe-filter is set in the context-map 3023 (cond 3024 (safe-filter context-map) x 3025 escape? (escape-html x) 3026 :else x)))))))))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.filters" name="selmer.filters"><h1 class="project-name">selmer.filters</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>To create a filter use the function add-filter! which takes a name and a fn. 3027 The first argument to the fn is always the value obtained from the context 3028 map. The rest of the arguments are optional and are always strings.</p> 3029 </td><td class="codes"><pre class="brush: clojure">(ns selmer.filters 3030 (:require [clojure.string :as s] 3031 [cheshire.core :as json :only [generate-string]] 3032 [selmer.util :refer [exception]]) 3033 (:import java.util.Locale 3034 org.joda.time.DateTime 3035 java.text.NumberFormat 3036 [org.joda.time.format DateTimeFormat DateTimeFormatter] 3037 [org.apache.commons.codec.digest DigestUtils]))</pre></td></tr><tr><td class="docs"> 3038 </td><td class="codes"><pre class="brush: clojure">(def valid-date-formats 3039 {"shortDate" (DateTimeFormat/shortDate) 3040 "shortTime" (DateTimeFormat/shortTime) 3041 "shortDateTime" (DateTimeFormat/shortDateTime) 3042 "mediumDate" (DateTimeFormat/mediumDate) 3043 "mediumTime" (DateTimeFormat/mediumTime) 3044 "mediumDateTime" (DateTimeFormat/mediumDateTime) 3045 "longDate" (DateTimeFormat/longDate) 3046 "longTime" (DateTimeFormat/longTime) 3047 "longDateTime" (DateTimeFormat/longDateTime) 3048 "fullDate" (DateTimeFormat/fullDate) 3049 "fullTime" (DateTimeFormat/fullTime) 3050 "fullDateTime" (DateTimeFormat/fullDateTime) 3051 })</pre></td></tr><tr><td class="docs"> 3052 </td><td class="codes"><pre class="brush: clojure">(defn ^DateTime fix-date [d] 3053 (cond (instance? DateTime d) d 3054 (instance? java.util.Date d) (DateTime. d) 3055 :else 3056 (try (DateTime. d) 3057 (catch Exception _ 3058 (throw (IllegalArgumentException. (str d " is not a valid date format.")))))))</pre></td></tr><tr><td class="docs"><p>Throws an exception with the given msg when (seq x) will fail (excluding nil)</p> 3059 3060 <p>Used in filters when we are expecting a collection but instead got nil or a number 3061 or something else just as useless. 3062 Some clojure functions silently do the wrong thing when given invalid arguments. This 3063 aims to prevent that.</p> 3064 </td><td class="codes"><pre class="brush: clojure">(defn throw-when-expecting-seqable 3065 [x & [msg]] 3066 (let [is-seqable (and (not (nil? x)) 3067 (or (seq? x) 3068 (instance? clojure.lang.Seqable x) 3069 (string? x) 3070 (instance? Iterable x) 3071 (-> ^Object x .getClass .isArray) 3072 (instance? java.util.Map x))) 3073 ^String msg (if msg msg (str "Expected '" (if (nil? x) "nil" (str x)) "' to be a collection of some sort."))] 3074 (when-not is-seqable 3075 (exception msg))))</pre></td></tr><tr><td class="docs"><p>Similar to the above only with numbers</p> 3076 </td><td class="codes"><pre class="brush: clojure">(defn throw-when-expecting-number 3077 [x & [msg]] 3078 (let [^String msg (if msg msg (str "Expected '" (if (nil? x) "nil" (str x)) "' to be a number."))] 3079 (when-not (number? x) 3080 (exception msg))))</pre></td></tr><tr><td class="docs"> 3081 </td><td class="codes"><pre class="brush: clojure">(defonce filters 3082 (atom 3083 {;;; Useful for doing crazy stuff like {{ foo|length-is:3|join:"/" }} 3084 ;;; Without blowing up I guess 3085 :str 3086 str 3087 ;;; Try to add the arguments as numbers 3088 ;;; If it fails concatenate them as strings 3089 :add 3090 (fn [x y & rest] 3091 (let [args (conj rest y (str x))] 3092 (try (apply + 3093 (map #(Long/valueOf ^String %) args)) 3094 (catch NumberFormatException _ 3095 (apply str args))))) 3096 ;;; Add backslashes to quotes 3097 :addslashes 3098 (fn [s] 3099 (->> s 3100 (str) 3101 (mapcat (fn [c] 3102 (if (or (= \" c) (= \' c)) 3103 [\\ c] 3104 [c]))) 3105 (apply str))) 3106 ;;; Center a string given a width 3107 :center 3108 (fn [s w] 3109 (let [s (str s) 3110 w (Long/valueOf (s/trim w)) 3111 c (count s) 3112 l (Math/ceil (/ (- w c) 2)) 3113 r (Math/floor (/ (- w c) 2))] 3114 (str 3115 (apply str (repeat l \space)) 3116 s 3117 (apply str (repeat r \space))))) 3118 :currency-format 3119 (fn [n & [locale country]] 3120 (throw-when-expecting-number n) 3121 (let [n (double n) 3122 locale (cond 3123 (and locale country) (Locale. locale country) 3124 locale (Locale. locale) 3125 :else (Locale/getDefault)) 3126 currency-format (java.text.NumberFormat/getCurrencyInstance locale)] 3127 (.format ^NumberFormat currency-format n))) 3128 :number-format 3129 (fn [n fmt & [locale]] 3130 (throw-when-expecting-number n) 3131 (let [locale (if locale (java.util.Locale. locale) 3132 (Locale/getDefault))] 3133 (String/format locale fmt (into-array Object [n])))) 3134 ;;; Formats a date with default locale, expects an instance of DateTime (Joda Time) or Date. 3135 ;;; The format can be a key from valid-date-formats or a manually defined format 3136 ;;; Look in 3137 ;;; http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html 3138 ;;; for formatting help. 3139 ;;; You can also format time with this. 3140 ;;; An optional locale for formatting can be given as second parameter 3141 :date 3142 (fn [d fmt & [locale]] 3143 (when d 3144 (let [fixed-date (fix-date d) 3145 locale (if locale (java.util.Locale. locale) 3146 (Locale/getDefault)) 3147 ^DateTimeFormatter fmt (.withLocale 3148 (or ^DateTimeFormatter (valid-date-formats fmt) 3149 ^DateTimeFormatter (DateTimeFormat/forPattern fmt)) locale)] 3150 (.print fmt fixed-date)))) 3151 ;;; Default if x is falsey 3152 :default 3153 (fn [x default] 3154 (if x 3155 x 3156 default)) 3157 ;;; Default if coll is empty 3158 :default-if-empty 3159 (fn [coll default] 3160 (try 3161 (cond 3162 (nil? coll) default 3163 (empty? coll) default 3164 :else coll) 3165 (catch Exception _ 3166 (throw-when-expecting-seqable coll)))) 3167 ;;; With no decimal places it rounds to 1 decimal place 3168 :double-format 3169 (fn [n & [decimal-places]] 3170 (throw-when-expecting-number n) 3171 (let [n (double n)] 3172 (format (str "%." (if decimal-places decimal-places "1") "f") 3173 n))) 3174 :first 3175 (fn [coll] 3176 (throw-when-expecting-seqable coll) 3177 (first coll)) 3178 :take 3179 (fn [coll n] 3180 (throw-when-expecting-seqable coll) 3181 (vec (take (Long/valueOf ^String n) coll))) 3182 :drop 3183 (fn [coll n] 3184 (throw-when-expecting-seqable coll) 3185 (vec (drop (Long/valueOf ^String n) coll))) 3186 ;;; Get the ith digit of a number 3187 ;;; 1 is the rightmost digit 3188 ;;; Returns the number if the index is out of bounds 3189 :get-digit 3190 (fn [n i] 3191 (let [nv (vec (str n)) 3192 i (Long/valueOf ^String i) 3193 i (- (count nv) i)] 3194 (if (or (< i 0) (>= i (count nv))) 3195 n 3196 (let [d (nv i)] 3197 (if (= \. d) 3198 (nv (dec i)) 3199 d))))) 3200 :hash 3201 (fn [s hash] 3202 (let [s (str s)] 3203 (case hash 3204 "md5" (DigestUtils/md5Hex s) 3205 "sha" (DigestUtils/shaHex s) 3206 "sha256" (DigestUtils/sha256Hex s) 3207 "sha384" (DigestUtils/sha384Hex s) 3208 "sha512" (DigestUtils/sha512Hex s) 3209 (throw (IllegalArgumentException. (str "'" hash "' is not a valid hash algorithm.")))))) 3210 :join 3211 (fn [coll & [sep]] 3212 (throw-when-expecting-seqable coll) 3213 (if sep (s/join sep coll) (s/join coll))) 3214 :empty? 3215 empty? 3216 :not-empty 3217 not-empty 3218 :json 3219 (fn [x] (json/generate-string x)) 3220 :last 3221 (fn [coll] 3222 (throw-when-expecting-seqable coll) 3223 (if (vector? coll) 3224 (coll (dec (count coll))) 3225 (last coll))) 3226 ;;; Exception to the rule: nil counts to 0 3227 :length 3228 (fn [coll] 3229 (if (nil? coll) 3230 0 3231 (do 3232 (throw-when-expecting-seqable coll) 3233 (count coll)))) 3234 ;;; Exception to the rule: nil counts to 0 3235 :count 3236 (fn [coll] 3237 (if (nil? coll) 3238 0 3239 (do 3240 (throw-when-expecting-seqable coll) 3241 (count coll)))) 3242 ;;; Return true when the count of the coll matches the argument 3243 :length-is 3244 (fn [coll n] 3245 (when-not (nil? coll) 3246 (throw-when-expecting-seqable coll)) 3247 (let [n (Long/valueOf ^String n)] 3248 (= n (count coll)))) 3249 :count-is 3250 (fn [coll n] 3251 (when-not (nil? coll) 3252 (throw-when-expecting-seqable coll)) 3253 (let [n (Long/valueOf ^String n)] 3254 (= n (count coll)))) 3255 ;;; Single newlines become <br />, double newlines mean new paragraph 3256 :linebreaks 3257 (fn [s] 3258 (let [s (str s) 3259 br (s/replace s #"\n" "<br />") 3260 p (s/replace br #"<br /><br />" "</p><p>") 3261 c (s/replace p #"<p>$" )] 3262 (if (re-seq #"</p>$" c) 3263 (str "<p>" c) 3264 (str "<p>" c "</p>")))) 3265 :linebreaks-br 3266 (fn [s] 3267 (let [s (str s)] 3268 (s/replace s #"\n" "<br />"))) 3269 ;;; Display text with line numbers 3270 :linenumbers 3271 (fn [s] 3272 (let [s (str s)] 3273 (->> (s/split s #"\n") 3274 (map-indexed 3275 (fn [i line] 3276 (str (inc i) ". " line))) 3277 (s/join "\n")))) 3278 :rand-nth 3279 (fn [coll] 3280 (throw-when-expecting-seqable coll) 3281 (rand-nth coll)) 3282 ;;; Turns the to-remove string into a set of chars 3283 ;;; That are removed from the context string 3284 :remove 3285 (fn [s to-remove] 3286 (let [s (str s) 3287 to-remove (set to-remove)] 3288 (apply str (remove to-remove s)))) 3289 ;;; Use like the following: 3290 ;;; You have {{ num-cherries }} cherr{{ num-cherries|pluralize:y:ies }} 3291 ;;; You have {{ num-walruses }} walrus{{ num-walruses|pluralize:es }} 3292 ;;; You have {{ num-messages }} message{{ num-messages|pluralize }} 3293 :pluralize 3294 (fn [n-or-coll & opts] 3295 (let [n (if (number? n-or-coll) n-or-coll 3296 (do (throw-when-expecting-seqable n-or-coll) 3297 (count n-or-coll))) 3298 plural (case (count opts) 3299 0 "s" 3300 1 (first opts) 3301 2 (second opts)) 3302 singular (case (count opts) 3303 (list 0 1) 3304 2 (first opts))] 3305 (if (== 1 n) 3306 singular 3307 plural))) 3308 ;;; Do not escape html 3309 :safe 3310 (fn [s] [:safe s]) 3311 :urlescape 3312 (fn [s] (java.net.URLEncoder/encode s)) 3313 :lower 3314 (fn [s] (s/lower-case (str s))) 3315 :upper 3316 (fn [s] (s/upper-case (str s))) 3317 :capitalize 3318 (fn [s] (s/capitalize (str s))) 3319 ;; Capitalize every word 3320 :title 3321 (fn [s] (->> (s/split (str s) #" ") 3322 (map s/capitalize) 3323 (s/join " "))) 3324 :sort 3325 (fn [coll] 3326 (throw-when-expecting-seqable coll) 3327 (sort coll)) 3328 ;;; Sort by a keyword 3329 :sort-by 3330 (fn [coll k] 3331 (throw-when-expecting-seqable coll) 3332 (sort-by (keyword k) coll)) 3333 :sort-by-reversed 3334 (fn [coll k] 3335 (throw-when-expecting-seqable coll) 3336 (sort-by (keyword k) (comp - compare) coll)) 3337 :sort-reversed 3338 (fn [coll] 3339 (throw-when-expecting-seqable coll) 3340 (sort (comp - compare) coll)) 3341 ;;; Remove tags 3342 ;;; Use like {{ value|remove-tags:b:span }} 3343 :remove-tags 3344 (fn [s & tags] 3345 (if-not tags 3346 s 3347 (let [s (str s) 3348 tags (str "(" (s/join "|" tags) ")") 3349 opening (re-pattern (str "(?i)<" tags "(/?>|(\\s+[^>]*>))")) 3350 closing (re-pattern (str "(?i)</" tags ">"))] 3351 (-> s 3352 (s/replace opening ) 3353 (s/replace closing ))))) 3354 :name 3355 name}))</pre></td></tr><tr><td class="docs"> 3356 </td><td class="codes"><pre class="brush: clojure">(defn get-filter 3357 [name] 3358 (get @filters (keyword name)))</pre></td></tr><tr><td class="docs"> 3359 </td><td class="codes"><pre class="brush: clojure">(defn call-filter 3360 [name & args] 3361 (apply (get-filter name) args))</pre></td></tr><tr><td class="docs"> 3362 </td><td class="codes"><pre class="brush: clojure">(defn add-filter! 3363 [name f] 3364 (swap! filters assoc (keyword name) f))</pre></td></tr><tr><td class="docs"> 3365 </td><td class="codes"><pre class="brush: clojure">(defn remove-filter! 3366 [name] 3367 (swap! filters dissoc (keyword name)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.middleware" name="selmer.middleware"><h1 class="project-name">selmer.middleware</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"> 3368 </td><td class="codes"><pre class="brush: clojure">(ns selmer.middleware 3369 (:require [selmer.parser :as parser]))</pre></td></tr><tr><td class="docs"><p>development middleware for rendering a friendly error page when a parsing error occurs</p> 3370 </td><td class="codes"><pre class="brush: clojure">(defn wrap-error-page 3371 [handler] 3372 (fn [request] 3373 (try 3374 (handler request) 3375 (catch clojure.lang.ExceptionInfo ex 3376 (let [{:keys [type error-template] :as data} (ex-data ex)] 3377 (if (= :selmer-validation-error type) 3378 {:status 500 3379 :headers {"Content-Type" "text/html; charset=utf-8"} 3380 :body (parser/render error-template data)} 3381 (throw ex)))))))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.node" name="selmer.node"><h1 class="project-name">selmer.node</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p> Node protocol for the objects that get accum'd in the post-parse vector. 3382 Same vector that will be processed by the runtime context-aware renderer. 3383 Currently only TextNodes and FunctionNodes. Anything that requires action 3384 upon context map data at runtime is handled by a generated anonymous function. </p> 3385 </td><td class="codes"><pre class="brush: clojure">(ns selmer.node 3386 (:gen-class))</pre></td></tr><tr><td class="docs"><p>Generic INode protocol</p> 3387 </td><td class="codes"></td></tr><tr><td class="docs"> 3388 </td><td class="codes"><pre class="brush: clojure">(defprotocol INode 3389 (render-node [this context-map] "Renders the context"))</pre></td></tr><tr><td class="docs"><p>Implements fn handler for the context map. fn handlers can 3390 access any data in the context map.</p> 3391 </td><td class="codes"></td></tr><tr><td class="docs"> 3392 </td><td class="codes"><pre class="brush: clojure">(deftype FunctionNode [handler] 3393 INode 3394 (render-node [this context-map] 3395 (handler context-map)) 3396 clojure.lang.IMeta 3397 (meta [this] 3398 (meta handler)))</pre></td></tr><tr><td class="docs"><p>Implements dumb text content injection at runtime.</p> 3399 </td><td class="codes"></td></tr><tr><td class="docs"> 3400 </td><td class="codes"><pre class="brush: clojure">(deftype TextNode [text] 3401 INode 3402 (render-node [this context-map] 3403 (str text)) 3404 (toString [_] 3405 (str text)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.parser" name="selmer.parser"><h1 class="project-name">selmer.parser</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p> Parsing and handling of compile-time vs. 3406 run-time. Avoiding unnecessary work by pre-processing 3407 the template structure and content and reacting to 3408 the runtime context map with a prepared data structure 3409 instead of a raw template. Anything other than a raw tag 3410 value injection is a runtime dispatch fn. Compile-time here 3411 means the first time we see a template <em>at runtime</em>, not the 3412 implementation's compile-time. </p> 3413 </td><td class="codes"><pre class="brush: clojure">(ns selmer.parser 3414 (:require [selmer.template-parser :refer [preprocess-template]] 3415 [selmer.filters :refer [filters]] 3416 [selmer.filter-parser :refer [compile-filter-body]] 3417 [selmer.tags :refer :all] 3418 [selmer.util :refer :all] 3419 [selmer.validator :refer [validation-error]] 3420 selmer.node) 3421 (:import [selmer.node INode TextNode FunctionNode]))</pre></td></tr><tr><td class="docs"><p>Ahead decl because some fns call into each other.</p> 3422 </td><td class="codes"></td></tr><tr><td class="docs"> 3423 </td><td class="codes"><pre class="brush: clojure">(declare parse parse-input parse-file tag-content)</pre></td></tr><tr><td class="docs"><p>Memoization atom for templates. If you pass a filepath instead 3424 of a string, we'll use the last-modified timestamp to cache the 3425 template. Works fine for active local development and production.</p> 3426 </td><td class="codes"></td></tr><tr><td class="docs"> 3427 </td><td class="codes"><pre class="brush: clojure">(defonce templates (atom {}))</pre></td></tr><tr><td class="docs"><p>Can be overridden by closure/argument 'cache</p> 3428 </td><td class="codes"><pre class="brush: clojure">(defonce cache? (atom true))</pre></td></tr><tr><td class="docs"> 3429 </td><td class="codes"><pre class="brush: clojure">(defn cache-on! [] 3430 (reset! cache? true))</pre></td></tr><tr><td class="docs"> 3431 </td><td class="codes"><pre class="brush: clojure">(defn cache-off! [] 3432 (reset! cache? false))</pre></td></tr><tr><td class="docs"><p>append '/' to the given string unless it already ends with a slash</p> 3433 </td><td class="codes"><pre class="brush: clojure">(defn- append-slash 3434 [^String s] 3435 (if (or (nil? s) 3436 (.endsWith s "/")) 3437 s 3438 (str s "/")))</pre></td></tr><tr><td class="docs"> 3439 </td><td class="codes"><pre class="brush: clojure">(defn- make-resource-path 3440 [path] 3441 (cond 3442 (nil? path) 3443 nil 3444 (instance? java.net.URL path) 3445 (append-slash (str path)) 3446 :else 3447 (append-slash 3448 (try 3449 (str (java.net.URL. path)) 3450 (catch java.net.MalformedURLException err 3451 (str "file:///" path))))))</pre></td></tr><tr><td class="docs"><p>set custom location, where templates are being searched for. path 3452 may be a java.net.URL instance or a string. If it's a string, we 3453 first try to convert it to a java.net.URL instance and if it doesn't 3454 work it's interpreted as a path in the local filesystem.</p> 3455 </td><td class="codes"><pre class="brush: clojure">(defn set-resource-path! 3456 [path] 3457 (set-custom-resource-path! (make-resource-path path)))</pre></td></tr><tr><td class="docs"> 3458 </td><td class="codes"><pre class="brush: clojure">(defn update-tag [tag-map tag tags] 3459 (assoc tag-map tag (concat (get tag-map tag) tags)))</pre></td></tr><tr><td class="docs"> 3460 </td><td class="codes"><pre class="brush: clojure">(defn set-closing-tags! [& tags] 3461 (loop [[tag & tags] tags] 3462 (when tag 3463 (swap! selmer.tags/closing-tags update-tag tag tags) 3464 (recur tags))))</pre></td></tr><tr><td class="docs"><p> tag name, fn handler, and maybe tags </p> 3465 3466 <p>add-tag! is a hella nifty macro. Example use: 3467 (add-tag! :joined (fn [args context-map] (clojure.string/join "," args)))</p> 3468 </td><td class="codes"><pre class="brush: clojure">(defmacro add-tag! 3469 [k handler & tags] 3470 `(do 3471 (set-closing-tags! ~k ~@tags) 3472 (swap! selmer.tags/expr-tags assoc ~k (tag-handler ~handler ~k ~@tags))))</pre></td></tr><tr><td class="docs"> 3473 </td><td class="codes"><pre class="brush: clojure">(defn remove-tag! 3474 [k] 3475 (swap! expr-tags dissoc k) 3476 (swap! closing-tags dissoc k))</pre></td></tr><tr><td class="docs"><p>render-template renders at runtime, accepts 3477 post-parsing vectors of INode elements.</p> 3478 </td><td class="codes"></td></tr><tr><td class="docs"> 3479 </td><td class="codes"><pre class="brush: clojure">(defn render-template [template context-map] 3480 " vector of ^selmer.node.INodes and a context map." 3481 (let [buf (StringBuilder.)] 3482 (doseq [^selmer.node.INode element template] 3483 (if-let [value (.render-node element context-map)] 3484 (.append buf value) 3485 (.append buf (*missing-value-formatter* (:tag (meta element)) context-map)))) 3486 (.toString buf)))</pre></td></tr><tr><td class="docs"> 3487 </td><td class="codes"><pre class="brush: clojure">(defn render [s context-map & [opts]] 3488 " render takes the string, the context-map and possibly also opts. " 3489 (render-template (parse parse-input (java.io.StringReader. s) opts) context-map))</pre></td></tr><tr><td class="docs"><p>Primary fn you interact with as a user, you pass a path that 3490 exists somewhere in your class-path, typically something like 3491 resources/templates/template_name.html. You also pass a context 3492 map and potentially opts. Smart (last-modified timestamp) 3493 auto-memoization of compiler output.</p> 3494 </td><td class="codes"></td></tr><tr><td class="docs"> 3495 </td><td class="codes"><pre class="brush: clojure">(defn render-file [filename-or-url context-map & [{:keys [cache custom-resource-path] 3496 :or {cache @cache? 3497 custom-resource-path *custom-resource-path*} 3498 :as opts}]] 3499 " Parses files if there isn't a memoized post-parse vector ready to go, 3500 renders post-parse vector with passed context-map regardless. Double-checks 3501 last-modified on files. Uses classpath for filename-or-url path " 3502 (binding [*custom-resource-path* (make-resource-path custom-resource-path)] 3503 (if-let [resource (resource-path filename-or-url)] 3504 (let [{:keys [template last-modified]} (get @templates resource) 3505 ;;for some resources, such as ones inside a jar, it's 3506 ;;not possible to check the last modified timestamp 3507 last-modified-time (if (or (nil? last-modified) (pos? last-modified)) 3508 (resource-last-modified resource) -1)] 3509 (check-template-exists resource) 3510 (if (and cache last-modified (= last-modified last-modified-time)) 3511 (render-template template context-map) 3512 (let [template (parse parse-file filename-or-url opts)] 3513 (swap! templates assoc resource {:template template 3514 :last-modified last-modified-time}) 3515 (render-template template context-map)))) 3516 (validation-error 3517 (str "resource-path for " filename-or-url " returned nil, typically means the file doesn't exist in your classpath.") 3518 nil nil nil))))</pre></td></tr><tr><td class="docs"><p>For a given tag, get the fn handler for the tag type, 3519 pass it the arguments, tag-content, render-template fn, 3520 and reader.</p> 3521 </td><td class="codes"></td></tr><tr><td class="docs"> 3522 </td><td class="codes"><pre class="brush: clojure">(defn expr-tag [{:keys [tag-name args] :as tag} rdr] 3523 (if-let [handler (tag-name @expr-tags)] 3524 (handler args tag-content render-template rdr) 3525 (exception "unrecognized tag: " tag-name " - did you forget to close a tag?")))</pre></td></tr><tr><td class="docs"><p>Same as a vanilla data tag with a value, but composes 3526 the filter fns. Like, {{ data-var | upper | safe }} 3527 (-> {:data-var "woohoo"} upper safe) => "WOOHOO" 3528 Happens at compile-time.</p> 3529 </td><td class="codes"></td></tr><tr><td class="docs"> 3530 </td><td class="codes"><pre class="brush: clojure">(defn filter-tag [{:keys [tag-value]}] 3531 " Compile-time parser of var tag filters. " 3532 (compile-filter-body tag-value))</pre></td></tr><tr><td class="docs"><p>Generally either a filter tag, if tag, ifequal, 3533 or for. filter-tags are conflated with vanilla tag</p> 3534 </td><td class="codes"></td></tr><tr><td class="docs"> 3535 </td><td class="codes"><pre class="brush: clojure">(defn parse-tag [{:keys [tag-type] :as tag} rdr] 3536 (with-meta 3537 (if (= :filter tag-type) 3538 (filter-tag tag) 3539 (expr-tag tag rdr)) 3540 {:tag tag}))</pre></td></tr><tr><td class="docs"><p>Parses and detects tags which turn into 3541 FunctionNode call-sites or TextNode content. open-tag? fn returns 3542 true or false based on character lookahead to see if it's {{ or {%</p> 3543 </td><td class="codes"></td></tr><tr><td class="docs"> 3544 </td><td class="codes"><pre class="brush: clojure">(defn append-node [content tag ^StringBuilder buf rdr] 3545 (-> content 3546 (conj (TextNode. (.toString buf))) 3547 (conj (FunctionNode. (parse-tag tag rdr)))))</pre></td></tr><tr><td class="docs"> 3548 </td><td class="codes"><pre class="brush: clojure">(defn update-tags [tag tags content args ^StringBuilder buf] 3549 (assoc tags tag 3550 {:args args 3551 :content (conj content (TextNode. (.toString buf)))}))</pre></td></tr><tr><td class="docs"> 3552 </td><td class="codes"><pre class="brush: clojure">(defn tag-content [rdr start-tag & end-tags] 3553 (let [buf (StringBuilder.)] 3554 (loop [ch (read-char rdr) 3555 tags {} 3556 content [] 3557 cur-tag start-tag 3558 end-tags end-tags] 3559 (cond 3560 (and (nil? ch) (not-empty end-tags)) 3561 (exception "No closing tag found for " start-tag) 3562 (nil? ch) 3563 tags 3564 (open-tag? ch rdr) 3565 (let [{:keys [tag-name args] :as tag} (read-tag-info rdr)] 3566 (if-let [open-tag (and tag-name (some #{tag-name} end-tags))] 3567 (let [tags (update-tags cur-tag tags content args buf) 3568 end-tags (next (drop-while #(not= tag-name %) end-tags))] 3569 (.setLength buf 0) 3570 (recur (when-not (empty? end-tags) (read-char rdr)) tags [] open-tag end-tags)) 3571 (let [content (append-node content tag buf rdr)] 3572 (.setLength buf 0) 3573 (recur (read-char rdr) tags content cur-tag end-tags)))) 3574 :else 3575 (do 3576 (.append buf ch) 3577 (recur (read-char rdr) tags content cur-tag end-tags))))))</pre></td></tr><tr><td class="docs"> 3578 </td><td class="codes"><pre class="brush: clojure">(defn skip-short-comment-tag [template rdr] 3579 (loop [ch1 (read-char rdr) 3580 ch2 (read-char rdr)] 3581 (cond 3582 (nil? ch2) 3583 (exception "short-form comment tag was not closed") 3584 (and (= *short-comment-second* ch1) (= *tag-close* ch2)) 3585 template 3586 :else (recur ch2 (read-char rdr)))))</pre></td></tr><tr><td class="docs"><p>Compile-time parsing of tags. Accumulates a transient vector 3587 before returning the persistent vector of INodes (TextNode, FunctionNode)</p> 3588 </td><td class="codes"></td></tr><tr><td class="docs"> 3589 </td><td class="codes"><pre class="brush: clojure">(defn add-node [template buf rdr] 3590 (let [template (if-let [text (not-empty (.toString ^StringBuilder buf))] 3591 (conj! template (TextNode. text)) 3592 template)] 3593 (.setLength ^StringBuilder buf 0) 3594 (conj! template (FunctionNode. (parse-tag (read-tag-info rdr) rdr)))))</pre></td></tr><tr><td class="docs"> 3595 </td><td class="codes"><pre class="brush: clojure">(defn parse* [input] 3596 (with-open [rdr (clojure.java.io/reader input)] 3597 (let [buf (StringBuilder.)] 3598 (loop [template (transient []) 3599 ch (read-char rdr)] 3600 (if ch 3601 (cond 3602 ;; We hit a tag so we append the buffer content to the template 3603 ;; and empty the buffer, then we proceed to parse the tag 3604 (and (open-tag? ch rdr) (some #{(peek-rdr rdr)} [*tag-second* *filter-open*])) 3605 (recur (add-node template buf rdr) (read-char rdr)) 3606 ;; Short comment tags are dropped 3607 (open-short-comment? ch rdr) 3608 (recur (skip-short-comment-tag template rdr) (read-char rdr)) 3609 ;; Default case, here we append the character and 3610 ;; read the next char 3611 :else 3612 (do 3613 (.append buf ch) 3614 (recur template (read-char rdr)))) 3615 ;; Add the leftover content of the buffer and return the template 3616 (->> buf (.toString) (TextNode.) (conj! template) persistent!))))))</pre></td></tr><tr><td class="docs"><p>Primary compile-time parse routine. Work we don't want happening after 3617 first template render. Vector output from parse* gets memoized by render-file.</p> 3618 </td><td class="codes"></td></tr><tr><td class="docs"> 3619 </td><td class="codes"><pre class="brush: clojure">(defn parse-input [input & [{:keys [custom-tags custom-filters]}]] 3620 (swap! expr-tags merge custom-tags) 3621 (swap! filters merge custom-filters) 3622 (parse* input))</pre></td></tr><tr><td class="docs"><p>File-aware parse wrapper.</p> 3623 </td><td class="codes"></td></tr><tr><td class="docs"> 3624 </td><td class="codes"><pre class="brush: clojure">(defn parse-file [file params] 3625 (-> file preprocess-template (java.io.StringReader.) (parse-input params)))</pre></td></tr><tr><td class="docs"> 3626 </td><td class="codes"><pre class="brush: clojure">(defn parse [parse-fn input & [{:keys [tag-open tag-close filter-open filter-close tag-second short-comment-second] 3627 :or {tag-open *tag-open* 3628 tag-close *tag-close* 3629 filter-open *filter-open* 3630 filter-close *filter-close* 3631 tag-second *tag-second* 3632 short-comment-second *short-comment-second*} 3633 :as params}]] 3634 (binding [*tag-open* tag-open 3635 *tag-close* tag-close 3636 *filter-open* filter-open 3637 *filter-close* filter-close 3638 *tag-second* tag-second 3639 *short-comment-second* short-comment-second 3640 *tag-second-pattern* (pattern tag-second) 3641 *filter-open-pattern* (pattern "\\" tag-open "\\" filter-open "\\s*") 3642 *filter-close-pattern* (pattern "\\s*\\" filter-close "\\" tag-close) 3643 *filter-pattern* (pattern "\\" tag-open "\\" filter-open "\\s*.*\\s*\\" filter-close "\\" tag-close) 3644 *tag-open-pattern* (pattern "\\" tag-open "\\" tag-second "\\s*") 3645 *tag-close-pattern* (pattern "\\s*\\" tag-second "\\" tag-close) 3646 *tag-pattern* (pattern "\\" tag-open "\\" tag-second "\\s*.*\\s*\\" tag-second "\\" tag-close) 3647 *include-pattern* (pattern "\\" tag-open "\\" tag-second "\\s*include.*") 3648 *extends-pattern* (pattern "\\" tag-open "\\" tag-second "\\s*extends.*") 3649 *block-pattern* (pattern "\\" tag-open "\\" tag-second "\\s*block.*") 3650 *block-super-pattern* (pattern "\\" tag-open "\\" filter-open "\\s*block.super\\s*\\" filter-close "\\" tag-close) 3651 *endblock-pattern* (pattern "\\" tag-open "\\" tag-second "\\s*endblock.*")] 3652 (parse-fn input params)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.tags" name="selmer.tags"><h1 class="project-name">selmer.tags</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"> 3653 </td><td class="codes"><pre class="brush: clojure">(ns selmer.tags 3654 (:require selmer.node 3655 [selmer.filter-parser :refer [split-filter-val safe-filter compile-filter-body fix-accessor get-accessor]] 3656 [selmer.filters :refer [filters]] 3657 [selmer.util :refer :all] 3658 [json-html.core :refer [edn->html]]) 3659 (:import [selmer.node INode TextNode FunctionNode]))</pre></td></tr><tr><td class="docs"><p>A tag can modify the context map for its body 3660 It has full control of its body which means that it has to 3661 take care of its compilation.</p> 3662 </td><td class="codes"><pre class="brush: clojure">(defn parse-arg [^String arg] 3663 (fix-accessor (.split arg "\\.")))</pre></td></tr><tr><td class="docs"> 3664 </td><td class="codes"><pre class="brush: clojure">(defn create-value-mappings [context-map ids value] 3665 (if (= 1 (count ids)) 3666 (assoc-in context-map (first ids) value) 3667 (reduce 3668 (fn [m [path value]] (assoc-in m path value)) 3669 context-map (map vector ids value))))</pre></td></tr><tr><td class="docs"> 3670 </td><td class="codes"><pre class="brush: clojure">(defn aggregate-args [args] 3671 (->> args 3672 (map #(.split ^String % ",")) 3673 (apply concat) 3674 (split-with (partial not= "in"))))</pre></td></tr><tr><td class="docs"> 3675 </td><td class="codes"><pre class="brush: clojure">(defn compile-filters [items filter-names] 3676 (map #(compile-filter-body (str items "|" %) false) filter-names))</pre></td></tr><tr><td class="docs"> 3677 </td><td class="codes"><pre class="brush: clojure">(defn apply-filters [item filters context-map items] 3678 (reduce 3679 (fn [value filter] 3680 (filter (assoc context-map 3681 (keyword items) value 3682 (name items) value))) 3683 item filters))</pre></td></tr><tr><td class="docs"> 3684 </td><td class="codes"><pre class="brush: clojure">(defn for-handler [args tag-content render rdr] 3685 (let [content (tag-content rdr :for :empty :endfor) 3686 for-content (get-in content [:for :content]) 3687 empty-content (get-in content [:empty :content]) 3688 [ids [_ items]] (aggregate-args args) 3689 ids (map parse-arg ids) 3690 [items & filter-names] (if items (.split ^String items "\\|")) 3691 filters (compile-filters items filter-names) 3692 item-keys (parse-arg items)] 3693 (fn [context-map] 3694 (let [buf (StringBuilder.) 3695 items (-> (reduce get-accessor context-map item-keys) 3696 (apply-filters filters context-map items)) 3697 length (count items)] 3698 (if (and empty-content (empty? items)) 3699 (.append buf (render empty-content context-map)) 3700 (doseq [[counter value] (map-indexed vector items)] 3701 (let [loop-info 3702 {:length length 3703 :counter0 counter 3704 :counter (inc counter) 3705 :revcounter (- length (inc counter)) 3706 :revcounter0 (- length counter) 3707 :first (= counter 0) 3708 :last (= counter (dec length))}] 3709 (->> (assoc (create-value-mappings context-map ids value) 3710 :forloop loop-info 3711 :parentloop loop-info) 3712 (render for-content) 3713 (.append buf))))) 3714 (.toString buf)))))</pre></td></tr><tr><td class="docs"> 3715 </td><td class="codes"><pre class="brush: clojure">(defn render-if [render context-map condition first-block second-block] 3716 (render 3717 (cond 3718 (and condition first-block) 3719 (:content first-block) 3720 (and (not condition) first-block) 3721 (:content second-block) 3722 condition 3723 (:content second-block) 3724 :else [(TextNode. )]) 3725 context-map))</pre></td></tr><tr><td class="docs"> 3726 </td><td class="codes"><pre class="brush: clojure">(defn if-result [value] 3727 (condp = value 3728 nil false 3729 false 3730 "false" false 3731 false false 3732 true))</pre></td></tr><tr><td class="docs"> 3733 </td><td class="codes"><pre class="brush: clojure">(defn if-default-handler [[condition1 condition2] if-tags else-tags render] 3734 " Handler of if-condition tags. Expects conditions, enclosed 3735 tag-content, render boolean. Returns anonymous fn that will expect 3736 runtime context-map. (Separate from compile-time) " 3737 (let [not? (and condition1 condition2 (= condition1 "not")) 3738 condition (compile-filter-body (or condition2 condition1))] 3739 (fn [context-map] 3740 (let [condition (if-result (condition context-map))] 3741 (render-if render context-map (if not? (not condition) condition) if-tags else-tags)))))</pre></td></tr><tr><td class="docs"> 3742 </td><td class="codes"><pre class="brush: clojure">(defn match-comparator [op] 3743 (condp = op ">" > "<" < "=" == ">=" >= "<=" <= 3744 (exception "Unrecognized operator in 'if' statement: " op)))</pre></td></tr><tr><td class="docs"> 3745 </td><td class="codes"><pre class="brush: clojure">(defn- num? [v] 3746 (re-matches #"[0-9]*\.?[0-9]+" v))</pre></td></tr><tr><td class="docs"> 3747 </td><td class="codes"><pre class="brush: clojure">(defn- parse-double [v] 3748 (java.lang.Double/parseDouble v))</pre></td></tr><tr><td class="docs"> 3749 </td><td class="codes"><pre class="brush: clojure">(defn parse-numeric-params [p1 op p2] 3750 (let [comparator (match-comparator op)] 3751 (cond 3752 (and (not (num? p1)) (not (num? p2))) 3753 [#(comparator (parse-double %1) (parse-double %2)) p1 p2] 3754 (num? p1) 3755 [#(comparator (parse-double p1) (parse-double %)) nil p2] 3756 (num? p2) 3757 [#(comparator (parse-double %) (parse-double p2)) p1 nil])))</pre></td></tr><tr><td class="docs"> 3758 </td><td class="codes"><pre class="brush: clojure">(defn render-if-numeric [render negate? [comparator context-key1 context-key2] context-map if-tags else-tags] 3759 (render 3760 (let [[value1 value2] 3761 (cond 3762 (and context-key1 context-key2) 3763 [(not-empty ((compile-filter-body context-key1) context-map)) 3764 (not-empty ((compile-filter-body context-key2) context-map))] 3765 context-key1 3766 [(not-empty ((compile-filter-body context-key1) context-map))] 3767 context-key2 3768 [(not-empty ((compile-filter-body context-key2) context-map))]) 3769 result (cond 3770 (and value1 value2) 3771 (comparator value1 value2) 3772 value1 3773 (comparator value1) 3774 value2 3775 (comparator value2))] 3776 (or (:content (if (if negate? (not result) result) if-tags else-tags)) 3777 [(TextNode. )])) 3778 context-map))</pre></td></tr><tr><td class="docs"> 3779 </td><td class="codes"><pre class="brush: clojure">(defn if-numeric-handler [[p1 p2 p3 p4 :as params] if-tags else-tags render] 3780 (cond 3781 (and p4 (not= p1 "not")) 3782 (exception "invalid params for if-tag: " params) 3783 (= "not" p1) 3784 #(render-if-numeric render true (parse-numeric-params p2 p3 p4) % if-tags else-tags) 3785 :else 3786 #(render-if-numeric render false (parse-numeric-params p1 p2 p3) % if-tags else-tags)))</pre></td></tr><tr><td class="docs"> 3787 </td><td class="codes"><pre class="brush: clojure">(defn render-if-any-all [not? op params if-tags else-tags render] 3788 (let [filters (map compile-filter-body params)] 3789 (fn [context-map] 3790 (render-if 3791 render 3792 context-map 3793 (let [test (op #{true} (map #(if-result (% context-map)) filters))] 3794 (if not? (not test) test)) 3795 if-tags else-tags))))</pre></td></tr><tr><td class="docs"> 3796 </td><td class="codes"><pre class="brush: clojure">(defn if-handler [params tag-content render rdr] 3797 (let [{if-tags :if else-tags :else} (tag-content rdr :if :else :endif)] 3798 (cond 3799 (some #{"any" "all"} (take 2 params)) 3800 (let [[not? op] (if (= "not" (first params)) 3801 [true (second params)] 3802 [false (first params)]) 3803 params (if not? (drop 2 params) (rest params))] 3804 (render-if-any-all not? (if (= "any" op) some every?) params if-tags else-tags render)) 3805 (< (count params) 3) 3806 (if-default-handler params if-tags else-tags render) 3807 :else 3808 (if-numeric-handler params if-tags else-tags render))))</pre></td></tr><tr><td class="docs"> 3809 </td><td class="codes"><pre class="brush: clojure">(defn compare-tag [args comparator render success failure] 3810 (fn [context-map] 3811 (let [condition (apply comparator (map #(if (fn? %) (% context-map) %) args))] 3812 (render-if render context-map condition success failure))))</pre></td></tr><tr><td class="docs"> 3813 </td><td class="codes"><pre class="brush: clojure">(defn parse-eq-args [args] 3814 (for [^String arg args] 3815 (cond 3816 (= \" (first arg)) 3817 (.substring arg 1 (dec (.length arg))) 3818 (= \: (first arg)) 3819 arg 3820 :else 3821 (compile-filter-body arg))))</pre></td></tr><tr><td class="docs"> 3822 </td><td class="codes"><pre class="brush: clojure">(defn ifequal-handler [args tag-content render rdr] 3823 (let [{:keys [ifequal else]} (tag-content rdr :ifequal :else :endifequal) 3824 args (parse-eq-args args)] 3825 (compare-tag args = render ifequal else)))</pre></td></tr><tr><td class="docs"> 3826 </td><td class="codes"><pre class="brush: clojure">(defn ifunequal-handler [args tag-content render rdr] 3827 (let [{:keys [ifunequal else]} (tag-content rdr :ifunequal :else :endifunequal) 3828 args (parse-eq-args args)] 3829 (compare-tag args not= render ifunequal else)))</pre></td></tr><tr><td class="docs"> 3830 </td><td class="codes"><pre class="brush: clojure">(defn block-handler [args tag-content render rdr] 3831 (let [content (get-in (tag-content rdr :block :endblock) [:block :content])] 3832 (fn [context-map] (render content context-map))))</pre></td></tr><tr><td class="docs"> 3833 </td><td class="codes"><pre class="brush: clojure">(defn sum-handler [args _ _ _] 3834 (fn [context-map] 3835 (reduce + (map (fn [val] 3836 (let [accessor (split-filter-val val)] 3837 (get-in context-map accessor))) args))))</pre></td></tr><tr><td class="docs"> 3838 </td><td class="codes"><pre class="brush: clojure">(defn now-handler [args _ _ _] 3839 (fn [context-map] 3840 ((:date @filters) (java.util.Date.) (clojure.string/join " " args))))</pre></td></tr><tr><td class="docs"> 3841 </td><td class="codes"><pre class="brush: clojure">(defn comment-handler [args tag-content render rdr] 3842 (let [content (tag-content rdr :comment :endcomment)] 3843 (fn [_] 3844 (render (filter (partial instance? selmer.node.TextNode) content) {}))))</pre></td></tr><tr><td class="docs"> 3845 </td><td class="codes"><pre class="brush: clojure">(defn first-of-handler [args _ _ _] 3846 (let [args (map compile-filter-body args)] 3847 (fn [context-map] 3848 (let [first-true (->> args (map #(% context-map)) (remove empty?) (drop-while false?) first)] 3849 (or first-true )))))</pre></td></tr><tr><td class="docs"> 3850 </td><td class="codes"><pre class="brush: clojure">(defn read-verbatim [rdr] 3851 (->buf [buf] 3852 (loop [ch (read-char rdr)] 3853 (when ch 3854 (cond 3855 (open-tag? ch rdr) 3856 (let [tag (read-tag-content rdr)] 3857 (if-not (re-matches #"\{\%\s*endverbatim\s*\%\}" tag) 3858 (do (.append buf tag) 3859 (recur (read-char rdr))))) 3860 :else 3861 (do 3862 (.append buf ch) 3863 (recur (read-char rdr))))))))</pre></td></tr><tr><td class="docs"> 3864 </td><td class="codes"><pre class="brush: clojure">(defn verbatim-handler [args _ render rdr] 3865 (let [content (read-verbatim rdr)] 3866 (fn [context-map] content)))</pre></td></tr><tr><td class="docs"> 3867 </td><td class="codes"><pre class="brush: clojure">(defn compile-args [args] 3868 (when-not (even? (count args)) 3869 (exception "invalid arguments passed to 'with' tag: " args)) 3870 (for [[id value] (partition 2 args)] 3871 [(keyword id) (compile-filter-body value false)]))</pre></td></tr><tr><td class="docs"> 3872 </td><td class="codes"><pre class="brush: clojure">(defn with-handler [args tag-content render rdr] 3873 (let [content (get-in (tag-content rdr :with :endwith) [:with :content]) 3874 args (->> args 3875 (mapcat #(.split ^String % "=")) 3876 (remove #{"="}) 3877 (compile-args))] 3878 (fn [context-map] 3879 (render content 3880 (reduce 3881 (fn [context-map [k v]] 3882 (assoc context-map k (v context-map))) 3883 context-map args)))))</pre></td></tr><tr><td class="docs"><p>Accepts <code>uri</code> passed in as first argument to {% script %} or {% style %} tag 3884 and context map. Returns string - new URI built with value of 3885 <code>selmer/context</code> context parameter in mind. <code>uri</code> can be a string literal or 3886 name of context parameter (filters also supported).</p> 3887 </td><td class="codes"><pre class="brush: clojure">(defn- build-uri-for-script-or-style-tag 3888 [^String uri {:keys [selmer/context] :as context-map}] 3889 (let [literal? (and (.startsWith uri "\"") (.endsWith uri "\"")) 3890 uri 3891 (if literal? 3892 (.replace uri "\"" "") ; case of {% style "/css/foo.css" %} 3893 (-> uri ; case of {% style context-param|some-filter:arg1:arg2 %} 3894 (compile-filter-body) 3895 (apply [context-map])))] 3896 (-> selmer/context (str uri) (.replace "//" "/"))))</pre></td></tr><tr><td class="docs"><p>Returns function that renders HTML <code><SCRIPT/></code> tag. Accepts <code>uri</code> that would 3897 be used to build value for 'src' attribute of generated tag and variable 3898 number of optional arguments. Value for 'src' attribute is built accounting 3899 value of <code>selmer/context</code> context parameter and <code>uri</code> can be a string literal 3900 or name of context parameter (filters also supported). Optional arguments are: 3901 * <code>async</code> - when evaluates to logical true then 'async' attribute would be 3902 added to generated tag.</p> 3903 </td><td class="codes"><pre class="brush: clojure">(defn script-handler 3904 [[^String uri & args] _ _ _] 3905 (let [args 3906 (->> args 3907 (mapcat #(.split ^String % "=")) 3908 (remove #{"="}) 3909 (compile-args))] 3910 (fn [{:keys [selmer/context] :as context-map}] 3911 (let [args 3912 (reduce 3913 (fn [context-map [k v]] 3914 (assoc context-map k (v context-map))) 3915 context-map 3916 args) 3917 async-attr (when (:async args) "async ") 3918 src-attr-val (build-uri-for-script-or-style-tag uri context-map)] 3919 (str "<script " async-attr "src=\"" src-attr-val "\" type=\"text/javascript\"></script>")))))</pre></td></tr><tr><td class="docs"><p>Returns function that renders HTML <code><LINK/></code> tag. Accepts <code>uri</code> that would 3920 be used to build value for 'href' attribute of generated tag. Value for 'href' 3921 attribute is built accounting value of <code>selmer/context</code> context parameter and 3922 <code>uri</code> can be a string literal or name of context parameter (filters also 3923 supported).</p> 3924 </td><td class="codes"><pre class="brush: clojure">(defn style-handler 3925 [[^String uri] _ _ _] 3926 (fn [{:keys [selmer/context] :as context-map}] 3927 (let [href-attr-val (build-uri-for-script-or-style-tag uri context-map)] 3928 (str "<link href=\"" href-attr-val "\" rel=\"stylesheet\" type=\"text/css\" />"))))</pre></td></tr><tr><td class="docs"> 3929 </td><td class="codes"><pre class="brush: clojure">(defn cycle-handler [args _ _ _] 3930 (let [fields (vec args) 3931 length (dec (count fields)) 3932 i (int-array [0])] 3933 (fn [_] 3934 (let [cur-i (aget i 0) 3935 val (fields cur-i)] 3936 (aset i 0 (if (< cur-i length) (inc cur-i) 0)) 3937 val))))</pre></td></tr><tr><td class="docs"> 3938 </td><td class="codes"><pre class="brush: clojure">(defn safe-handler [args tag-content render rdr] 3939 (let [content (get-in (tag-content rdr :safe :endsafe) [:safe :content])] 3940 (fn [context-map] 3941 (render content (assoc context-map safe-filter true)))))</pre></td></tr><tr><td class="docs"> 3942 </td><td class="codes"><pre class="brush: clojure">(defn debug-handler [_ _ _ _] 3943 (fn [context-map] 3944 (str 3945 "<style>" 3946 (-> "json.human.css" clojure.java.io/resource slurp) 3947 "</style>" 3948 (edn->html context-map))))</pre></td></tr><tr><td class="docs"><p>expr-tags are {% if ... %}, {% ifequal ... %}, 3949 {% for ... %}, and {% block blockname %}</p> 3950 </td><td class="codes"></td></tr><tr><td class="docs"> 3951 </td><td class="codes"><pre class="brush: clojure">(defonce expr-tags 3952 (atom {:if if-handler 3953 :ifequal ifequal-handler 3954 :ifunequal ifunequal-handler 3955 :sum sum-handler 3956 :for for-handler 3957 :block block-handler 3958 :cycle cycle-handler 3959 :now now-handler 3960 :comment comment-handler 3961 :firstof first-of-handler 3962 :verbatim verbatim-handler 3963 :with with-handler 3964 :script script-handler 3965 :style style-handler 3966 :safe safe-handler 3967 :debug debug-handler 3968 :extends nil 3969 :include nil}))</pre></td></tr><tr><td class="docs"> 3970 </td><td class="codes"><pre class="brush: clojure">(defonce closing-tags 3971 (atom {:if [:else :endif] 3972 :else [:endif :endifequal :endifunequal] 3973 :ifequal [:else :endifequal] 3974 :ifunequal [:else :endifunequal] 3975 :block [:endblock] 3976 :for [:empty :endfor] 3977 :empty [:endfor] 3978 :comment [:endcomment] 3979 :safe [:endsafe] 3980 :verbatim [:endverbatim] 3981 :with [:endwith]}))</pre></td></tr><tr><td class="docs"><p>helpers for custom tag definition</p> 3982 </td><td class="codes"><pre class="brush: clojure">(defn render-tags [context-map tags] 3983 (into {} 3984 (for [[tag content] tags] 3985 [tag 3986 (update-in content [:content] 3987 (fn [^selmer.node.INode node] 3988 (clojure.string/join (map #(.render-node ^selmer.node.INode % context-map) node))))])))</pre></td></tr><tr><td class="docs"> 3989 </td><td class="codes"><pre class="brush: clojure">(defn tag-handler [handler & tags] 3990 (fn [args tag-content render rdr] 3991 (if-let [content (if (> (count tags) 1) (apply (partial tag-content rdr) tags))] 3992 (fn [context-map] 3993 (render 3994 [(->> content (render-tags context-map) (handler args context-map) (TextNode.))] 3995 context-map)) 3996 (fn [context-map] 3997 (handler args context-map)))))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.template-parser" name="selmer.template-parser"><h1 class="project-name">selmer.template-parser</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p> Where we preprocess the inheritance and mixin components of the templates. 3998 These are presumed to be static and we only aggregate them on the first 3999 template render. The compile-time tag parsing routines happen on a flat string 4000 composed from the result of <code>extends</code> inheritance and <code>include</code> mixins. </p> 4001 </td><td class="codes"><pre class="brush: clojure">(ns selmer.template-parser 4002 (:require [clojure.java.io :refer [reader]] 4003 [selmer.util :refer :all] 4004 [clojure.string :as s :refer [split trim]] 4005 [selmer.validator :as validator]) 4006 (:import java.io.StringReader))</pre></td></tr><tr><td class="docs"> 4007 </td><td class="codes"><pre class="brush: clojure">(declare consume-block preprocess-template)</pre></td></tr><tr><td class="docs"> 4008 </td><td class="codes"><pre class="brush: clojure">(defn get-tag-params [tag-id block-str] 4009 (let [tag-id (re-pattern (str "^.+?" tag-id "\\s*"))] 4010 (-> block-str (s/replace tag-id ) (split *tag-second-pattern*) first trim)))</pre></td></tr><tr><td class="docs"> 4011 </td><td class="codes"><pre class="brush: clojure">(defn parse-defaults [defaults] 4012 (when defaults 4013 (->> defaults 4014 (interpose " ") 4015 (apply str) 4016 split-by-args 4017 (partition 2) 4018 (map vec) 4019 (into {}))))</pre></td></tr><tr><td class="docs"> 4020 </td><td class="codes"><pre class="brush: clojure">(defn split-include-tag [^String tag-str] 4021 (seq (.split ^String (get-tag-params "include" (.replace tag-str "\\" "/")) " ")))</pre></td></tr><tr><td class="docs"> 4022 </td><td class="codes"><pre class="brush: clojure">(defn string->reader [string] 4023 (reader (StringReader. string)))</pre></td></tr><tr><td class="docs"><p>parse any included templates and splice them in replacing the include tags</p> 4024 </td><td class="codes"><pre class="brush: clojure">(defn insert-includes 4025 [template] 4026 ;; We really need to split out the "gather all parent templates recursively" 4027 ;; and separate that from the buffer appending so we can gather the template 4028 ;; hierarchy for smarter cache invalidation - will eliminate almost all 4029 ;; existing reasons for cache-off! 4030 (->buf [buf] 4031 (with-open [rdr (reader (StringReader. template))] 4032 (loop [ch (read-char rdr)] 4033 (when ch 4034 (if (and (= *tag-open* ch) (= *tag-second* (peek-rdr rdr))) 4035 (let [tag-str (read-tag-content rdr)] 4036 (.append buf 4037 (if (re-matches *include-pattern* tag-str) 4038 (let [params (split-include-tag tag-str) 4039 source (.replaceAll ^String (first params) "\"" "") 4040 defaults (parse-defaults (nnext params))] 4041 (preprocess-template source {} defaults)) 4042 tag-str))) 4043 (.append buf ch)) 4044 (recur (read-char rdr)))))))</pre></td></tr><tr><td class="docs"> 4045 </td><td class="codes"><pre class="brush: clojure">(defn get-parent [tag-str] 4046 (let [template (get-tag-params "extends" tag-str)] 4047 (.substring ^String template 1 (dec (.length ^String template)))))</pre></td></tr><tr><td class="docs"> 4048 </td><td class="codes"><pre class="brush: clojure">(defn write-tag? [buf super-tag? existing-block blocks-to-close omit-close-tag?] 4049 (and buf 4050 (or super-tag? 4051 (and 4052 (not existing-block) 4053 (> blocks-to-close (if omit-close-tag? 1 0))))))</pre></td></tr><tr><td class="docs"> 4054 </td><td class="codes"><pre class="brush: clojure">(defn consume-block [rdr & [^StringBuilder buf blocks omit-close-tag?]] 4055 (loop [blocks-to-close 1 4056 has-super? false] 4057 (if (and (pos? blocks-to-close) (peek-rdr rdr)) 4058 (let [ch (read-char rdr)] 4059 (if (open-tag? ch rdr) 4060 (let [tag-str (read-tag-content rdr) 4061 block? (re-matches *block-pattern* tag-str) 4062 block-name (if block? (get-tag-params "block" tag-str)) 4063 super-tag? (re-matches *block-super-pattern* tag-str) 4064 existing-block (if block-name (get-in blocks [block-name :content]))] 4065 ;;check if we wish to write the closing tag for the block. If we're 4066 ;;injecting block.super, then we want to omit it 4067 (when (write-tag? buf super-tag? existing-block blocks-to-close omit-close-tag?) 4068 (.append buf tag-str)) 4069 (recur 4070 (long 4071 (cond 4072 existing-block 4073 (do 4074 (consume-block rdr) 4075 (consume-block 4076 (StringReader. existing-block) buf (dissoc blocks block-name)) 4077 blocks-to-close) 4078 block? 4079 (inc blocks-to-close) 4080 (re-matches *endblock-pattern* tag-str) 4081 (dec blocks-to-close) 4082 :else blocks-to-close)) 4083 (or has-super? super-tag?))) 4084 (do 4085 (when buf (.append buf ch)) 4086 (recur blocks-to-close has-super?)))) 4087 (boolean has-super?))))</pre></td></tr><tr><td class="docs"> 4088 </td><td class="codes"><pre class="brush: clojure">(defn rewrite-super [block parent-content] 4089 (clojure.string/replace block *block-super-pattern* parent-content))</pre></td></tr><tr><td class="docs"> 4090 </td><td class="codes"><pre class="brush: clojure">(defn read-block [rdr block-tag blocks] 4091 (let [block-name (get-tag-params "block" block-tag) 4092 existing-block (get blocks block-name)] 4093 (cond 4094 ;;we have a child block with a {{block.super}} tag, we'll need to 4095 ;;grab the contents of the parent and inject them in the child 4096 (:super existing-block) 4097 (let [child-content (:content existing-block) 4098 parent-content (StringBuilder.) 4099 has-super? (consume-block rdr parent-content blocks true)] 4100 (assoc blocks block-name 4101 {:super has-super? 4102 :content (rewrite-super child-content (.toString parent-content))})) 4103 ;;we've got a child block without a super tag, the parent will be replaced 4104 existing-block 4105 (do (consume-block rdr) blocks) 4106 ;;this is the first occurance of the block and we simply add it to the 4107 ;;map of blocks we've already seen 4108 :else 4109 (let [buf (doto (StringBuilder.) (.append block-tag)) 4110 has-super? (consume-block rdr buf blocks)] 4111 (assoc blocks block-name 4112 {:super has-super? 4113 :content (.toString buf)})))))</pre></td></tr><tr><td class="docs"> 4114 </td><td class="codes"><pre class="brush: clojure">(defn process-block [rdr buf block-tag blocks] 4115 (let [block-name (get-tag-params "block" block-tag)] 4116 (if-let [child-content (get-in blocks [block-name :content])] 4117 (.append ^StringBuilder buf 4118 (rewrite-super 4119 child-content 4120 (->buf [buf] (consume-block rdr buf blocks true)))) 4121 (do 4122 (.append ^StringBuilder buf block-tag) 4123 (consume-block rdr buf blocks)))))</pre></td></tr><tr><td class="docs"> 4124 </td><td class="codes"><pre class="brush: clojure">(defn wrap-in-expression-tag [string] 4125 (str *tag-open* *tag-second* string *tag-second* *tag-close*))</pre></td></tr><tr><td class="docs"> 4126 </td><td class="codes"><pre class="brush: clojure">(defn wrap-in-variable-tag [string] 4127 (str *tag-open* *filter-open* string *filter-close* *tag-close*))</pre></td></tr><tr><td class="docs"> 4128 </td><td class="codes"><pre class="brush: clojure">(defn trim-regex [string & regexes] 4129 (reduce #(clojure.string/replace %1 %2 ) string regexes))</pre></td></tr><tr><td class="docs"> 4130 </td><td class="codes"><pre class="brush: clojure">(defn trim-variable-tag [string] 4131 (trim-regex string *filter-open-pattern* *filter-close-pattern*))</pre></td></tr><tr><td class="docs"> 4132 </td><td class="codes"><pre class="brush: clojure">(defn trim-expression-tag [string] 4133 (trim-regex string *tag-open-pattern* *tag-close-pattern*))</pre></td></tr><tr><td class="docs"> 4134 </td><td class="codes"><pre class="brush: clojure">(defn to-expression-string [tag-name args] 4135 (let [tag-name' (name tag-name) 4136 args' (clojure.string/join \space args) 4137 joined (if (seq args) (str tag-name' \space args') tag-name')] 4138 (wrap-in-expression-tag joined)))</pre></td></tr><tr><td class="docs"> 4139 </td><td class="codes"><pre class="brush: clojure">(defn add-default [identifier default] 4140 (str identifier "|default:" \" default \"))</pre></td></tr><tr><td class="docs"> 4141 </td><td class="codes"><pre class="brush: clojure">(defn try-add-default [identifier defaults] 4142 (if-let [default (get defaults identifier)] 4143 (add-default identifier default) 4144 identifier))</pre></td></tr><tr><td class="docs"> 4145 </td><td class="codes"><pre class="brush: clojure">(defn add-defaults-to-variable-tag [tag-str defaults] 4146 (let [tag-name (trim-variable-tag tag-str)] 4147 (wrap-in-variable-tag (try-add-default tag-name defaults))))</pre></td></tr><tr><td class="docs"> 4148 </td><td class="codes"><pre class="brush: clojure">(defn add-defaults-to-expression-tag [tag-str defaults] 4149 (let [tag-str' (->> (trim-expression-tag tag-str) 4150 ;; NOTE: we add a character here since read-tag-info 4151 ;; consumes the first character before parsing. 4152 (str *tag-second*)) 4153 {:keys [tag-name args]} (read-tag-info (string->reader tag-str')) ] 4154 (to-expression-string tag-name (map #(try-add-default % defaults) args))))</pre></td></tr><tr><td class="docs"> 4155 </td><td class="codes"><pre class="brush: clojure">(defn get-template-path [template] 4156 (resource-path template))</pre></td></tr><tr><td class="docs"> 4157 </td><td class="codes"><pre class="brush: clojure">(defn read-template [template blocks defaults] 4158 (let [path (resource-path template)] 4159 (when-not path 4160 (validator/validation-error 4161 (str "resource-path for " template " returned nil, typically means the file doesn't exist in your classpath.") 4162 nil nil nil)) 4163 (validator/validate path) 4164 (check-template-exists (get-template-path template)) 4165 (let [buf (StringBuilder.) 4166 [parent blocks] 4167 (with-open [rdr (reader path)] 4168 (loop [blocks (or blocks {}) 4169 ch (read-char rdr) 4170 parent nil] 4171 (cond 4172 (nil? ch) [parent blocks] 4173 (open-tag? ch rdr) 4174 (let [tag-str (read-tag-content rdr)] 4175 (cond 4176 (and defaults 4177 (re-matches *filter-pattern* tag-str)) 4178 (do (.append buf (add-defaults-to-variable-tag tag-str defaults)) 4179 (recur blocks (read-char rdr) parent)) 4180 (and defaults 4181 (re-matches *tag-pattern* tag-str)) 4182 (do (.append buf (add-defaults-to-expression-tag tag-str defaults)) 4183 (recur blocks (read-char rdr) parent)) 4184 ;;if the template extends another it's not the root 4185 ;;this template is allowed to only contain blocks 4186 (re-matches *extends-pattern* tag-str) 4187 (recur blocks (read-char rdr) (get-parent tag-str)) 4188 ;;if we have a parent then we simply want to add the 4189 ;;block to the block map if it hasn't been added already 4190 (and parent (re-matches *block-pattern* tag-str)) 4191 (recur (read-block rdr tag-str blocks) (read-char rdr) parent) 4192 ;;if the template has blocks, but no parent it's the root 4193 ;;we either replace the block with an existing one from a child 4194 ;;template or read the block from this template 4195 (re-matches *block-pattern* tag-str) 4196 (do 4197 (process-block rdr buf tag-str blocks) 4198 (recur blocks (read-char rdr) parent)) 4199 ;;if we are in the root template we'll accumulate the content 4200 ;;into a buffer, this will be the resulting template string 4201 (nil? parent) 4202 (do 4203 (.append buf tag-str) 4204 (recur blocks (read-char rdr) parent)))) 4205 :else 4206 (do 4207 (if (nil? parent) (.append buf ch)) 4208 (recur blocks (read-char rdr) parent)))))] 4209 (if parent (recur parent blocks defaults) (.toString buf)))))</pre></td></tr><tr><td class="docs"> 4210 </td><td class="codes"><pre class="brush: clojure">(defn preprocess-template [template & [blocks defaults]] 4211 (insert-includes (read-template template blocks defaults)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.util" name="selmer.util"><h1 class="project-name">selmer.util</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"> 4212 </td><td class="codes"><pre class="brush: clojure">(ns selmer.util 4213 (:import java.io.StringReader 4214 java.util.regex.Pattern))</pre></td></tr><tr><td class="docs"> 4215 </td><td class="codes"><pre class="brush: clojure">(defmacro exception [& [param & more :as params]] 4216 (if (class? param) 4217 `(throw (new ~param (str ~@more))) 4218 `(throw (Exception. (str ~@params)))))</pre></td></tr><tr><td class="docs"> 4219 </td><td class="codes"><pre class="brush: clojure">(def ^:dynamic *custom-resource-path* nil)</pre></td></tr><tr><td class="docs"> 4220 </td><td class="codes"><pre class="brush: clojure">(defn set-custom-resource-path! 4221 [path] 4222 (alter-var-root #'*custom-resource-path* (constantly path)) 4223 (when (thread-bound? #'*custom-resource-path*) 4224 (set! *custom-resource-path* path)))</pre></td></tr><tr><td class="docs"> 4225 </td><td class="codes"><pre class="brush: clojure">(def ^:dynamic *escape-variables* true)</pre></td></tr><tr><td class="docs"> 4226 </td><td class="codes"><pre class="brush: clojure">(defn turn-off-escaping! [] 4227 (alter-var-root #'*escape-variables* 4228 (constantly false)))</pre></td></tr><tr><td class="docs"> 4229 </td><td class="codes"><pre class="brush: clojure">(defn turn-on-escaping! [] 4230 (alter-var-root #'*escape-variables* 4231 (constantly true)))</pre></td></tr><tr><td class="docs"> 4232 </td><td class="codes"><pre class="brush: clojure">(defmacro with-escaping [& body] 4233 `(binding [*escape-variables* true] 4234 ~@body))</pre></td></tr><tr><td class="docs"> 4235 </td><td class="codes"><pre class="brush: clojure">(defmacro without-escaping [& body] 4236 `(binding [*escape-variables* false] 4237 ~@body))</pre></td></tr><tr><td class="docs"> 4238 </td><td class="codes"><pre class="brush: clojure">(defn pattern [& content] 4239 (re-pattern (clojure.string/join content)))</pre></td></tr><tr><td class="docs"> 4240 </td><td class="codes"><pre class="brush: clojure">(defn read-char [^java.io.Reader rdr] 4241 (let [ch (.read rdr)] 4242 (if-not (== -1 ch) (char ch))))</pre></td></tr><tr><td class="docs"><p>Works best for small collections seemingly.</p> 4243 </td><td class="codes"><pre class="brush: clojure">(defn assoc-in* 4244 [m ks v] 4245 (let [k (first ks)] 4246 (if (zero? (count ks)) 4247 (assoc m k (assoc-in* (get m k) (next ks) v)) 4248 (assoc m k v))))</pre></td></tr><tr><td class="docs"><p>default tag characters</p> 4249 </td><td class="codes"><pre class="brush: clojure">(def ^:dynamic ^Character *tag-open* \{) 4250 (def ^:dynamic ^Character *tag-close* \}) 4251 (def ^:dynamic ^Character *filter-open* \{) 4252 (def ^:dynamic ^Character *filter-close* \}) 4253 (def ^:dynamic ^Character *tag-second* \%) 4254 (def ^:dynamic ^Character *short-comment-second* \#)</pre></td></tr><tr><td class="docs"><p>tag regex patterns</p> 4255 </td><td class="codes"><pre class="brush: clojure">(def ^:dynamic ^Pattern *tag-second-pattern* nil) 4256 (def ^:dynamic ^Pattern *filter-open-pattern* nil) 4257 (def ^:dynamic ^Pattern *filter-close-pattern* nil) 4258 (def ^:dynamic ^Pattern *filter-pattern* nil) 4259 (def ^:dynamic ^Pattern *tag-open-pattern* nil) 4260 (def ^:dynamic ^Pattern *tag-close-pattern* nil) 4261 (def ^:dynamic ^Pattern *tag-pattern* nil) 4262 (def ^:dynamic ^Pattern *include-pattern* nil) 4263 (def ^:dynamic ^Pattern *extends-pattern* nil) 4264 (def ^:dynamic ^Pattern *block-pattern* nil) 4265 (def ^:dynamic ^Pattern *block-super-pattern* nil) 4266 (def ^:dynamic ^Pattern *endblock-pattern* nil)</pre></td></tr><tr><td class="docs"> 4267 </td><td class="codes"><pre class="brush: clojure">(def match-unquoted " *(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)")</pre></td></tr><tr><td class="docs"> 4268 </td><td class="codes"><pre class="brush: clojure">(defn check-tag-args [args] 4269 (if (even? (count (filter #{\"} args))) 4270 args (exception "malformed tag arguments in " args)))</pre></td></tr><tr><td class="docs"> 4271 </td><td class="codes"><pre class="brush: clojure">(defn read-tag-info [rdr] 4272 (let [buf (StringBuilder.) 4273 tag-type (if (= *filter-open* (read-char rdr)) :filter :expr)] 4274 (loop [ch1 (read-char rdr) 4275 ch2 (read-char rdr)] 4276 (when-not (or (nil? ch1) 4277 (and (or (= *filter-close* ch1) (= *tag-second* ch1)) 4278 (= *tag-close* ch2))) 4279 (.append buf ch1) 4280 (recur ch2 (read-char rdr)))) 4281 (let [content (->> (.toString buf) 4282 (check-tag-args) 4283 (re-seq #"(?:[^\s\"]|\"[^\"]*\")+") 4284 (remove empty?) 4285 (map (fn [^String s] (.trim s))))] 4286 (merge {:tag-type tag-type} 4287 (if (= :filter tag-type) 4288 {:tag-value (first content)} 4289 {:tag-name (keyword (first content)) 4290 :args (next content)})))))</pre></td></tr><tr><td class="docs"> 4291 </td><td class="codes"><pre class="brush: clojure">(defn peek-rdr [^java.io.Reader rdr] 4292 (.mark rdr 1) 4293 (let [result (read-char rdr)] 4294 (.reset rdr) 4295 result))</pre></td></tr><tr><td class="docs"> 4296 </td><td class="codes"><pre class="brush: clojure">(defmacro ->buf [[buf] & body] 4297 `(let [~buf (StringBuilder.)] 4298 (do ~@body) 4299 (.toString ~buf)))</pre></td></tr><tr><td class="docs"> 4300 </td><td class="codes"><pre class="brush: clojure">(defn read-tag-content [rdr] 4301 (->buf [buf] 4302 (let [next-ch (peek-rdr rdr) 4303 filter? (not= *tag-second* next-ch)] 4304 (.append buf *tag-open*) 4305 (when next-ch 4306 (loop [ch (read-char rdr)] 4307 (.append buf ch) 4308 (when (and (not= *tag-close* ch) (not= *filter-close* ch)) 4309 (recur (read-char rdr)))) 4310 (when filter? 4311 (.append buf (read-char rdr)))))))</pre></td></tr><tr><td class="docs"> 4312 </td><td class="codes"><pre class="brush: clojure">(defn open-tag? [ch rdr] 4313 (and (= *tag-open* ch) 4314 (let [next-ch (peek-rdr rdr)] 4315 (or (= *filter-open* next-ch) 4316 (= *tag-second* next-ch)))))</pre></td></tr><tr><td class="docs"> 4317 </td><td class="codes"><pre class="brush: clojure">(defn open-short-comment? [ch rdr] 4318 (and (= *tag-open* ch) 4319 (let [next-ch (peek-rdr rdr)] 4320 (= *short-comment-second* next-ch))))</pre></td></tr><tr><td class="docs"> 4321 </td><td class="codes"><pre class="brush: clojure">(defn split-by-args [s] 4322 (let [rdr (StringReader. s) 4323 buf (StringBuilder.)] 4324 (loop [items [] 4325 ch (read-char rdr) 4326 open? false] 4327 (cond 4328 (nil? ch) items 4329 (and open? (= ch \")) 4330 (let [value (.trim (.toString buf))] 4331 (.setLength buf 0) 4332 (recur (conj items value) (read-char rdr) false)) 4333 (= ch \") 4334 (recur items (read-char rdr) true) 4335 (and (not open?) (= ch \=)) 4336 (let [id (.trim (.toString buf))] 4337 (.setLength buf 0) 4338 (recur (conj items id) (read-char rdr) open?)) 4339 :else 4340 (do 4341 (.append buf ch) 4342 (recur items (read-char rdr) open?))))))</pre></td></tr><tr><td class="docs"> 4343 </td><td class="codes"><pre class="brush: clojure">(defn get-resource [resource] 4344 (-> (Thread/currentThread) 4345 (.getContextClassLoader) 4346 (.getResource resource)))</pre></td></tr><tr><td class="docs"> 4347 </td><td class="codes"><pre class="brush: clojure">(defn resource-path [template] 4348 (if (instance? java.net.URL template) 4349 template 4350 (if-let [path *custom-resource-path*] 4351 (java.net.URL. (str path template)) 4352 (get-resource template))))</pre></td></tr><tr><td class="docs"> 4353 </td><td class="codes"><pre class="brush: clojure">(defn resource-last-modified [^java.net.URL resource] 4354 (let [path (.getPath resource)] 4355 (try 4356 (.lastModified (java.io.File. ^String path)) 4357 (catch NullPointerException _ -1))))</pre></td></tr><tr><td class="docs"> 4358 </td><td class="codes"><pre class="brush: clojure">(defn check-template-exists [^java.net.URL resource] 4359 (when-not resource 4360 (exception "template: \ (.getPath ^java.net.URL resource) "\" not found")))</pre></td></tr><tr><td class="docs"> 4361 </td><td class="codes"><pre class="brush: clojure">(def default-missing-value-formatter (constantly ))</pre></td></tr><tr><td class="docs"> 4362 </td><td class="codes"><pre class="brush: clojure">(def ^:dynamic *missing-value-formatter* default-missing-value-formatter) 4363 (def ^:dynamic *filter-missing-values* true)</pre></td></tr><tr><td class="docs"><p>Takes a function of two arguments which is called on a missing value. 4364 The function should return the value to be output in place of an empty string 4365 (which is the default from 'default-missing-value-formatter').</p> 4366 4367 <p> Call with named argument :filter-missing-values true to force filtering of missing 4368 values (although for most use cases this will not make sense).</p> 4369 4370 <p> Arguments to missing-value-fn: 4371 tag - map with data for the tag being evaluated. 4372 Contains the key :tag-type with the value :filter or :expr (for filter or expression tag types. 4373 For :filter: 4374 tag-value - the contents of the filter tag as a string. 4375 For :expr: 4376 tag-name - the name of the expression. 4377 args - the args provided to the expression. 4378 context-map - the context-map provided to the render function.</p> 4379 </td><td class="codes"><pre class="brush: clojure">(defn set-missing-value-formatter! 4380 [missing-value-fn & {:keys [filter-missing-values] :or {filter-missing-values false}}] 4381 (alter-var-root #'*missing-value-formatter* (constantly missing-value-fn)) 4382 (alter-var-root #'*filter-missing-values* (constantly filter-missing-values)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#selmer.validator" name="selmer.validator"><h1 class="project-name">selmer.validator</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"> 4383 </td><td class="codes"><pre class="brush: clojure">(ns selmer.validator 4384 (:use selmer.tags 4385 selmer.filters 4386 selmer.util 4387 [clojure.set :only [difference]] 4388 [clojure.java.io :only [reader]]))</pre></td></tr><tr><td class="docs"> 4389 </td><td class="codes"><pre class="brush: clojure">(def error-template 4390 (slurp (get-resource "selmer-error-template.html")))</pre></td></tr><tr><td class="docs"> 4391 </td><td class="codes"><pre class="brush: clojure">(def validate? (atom true))</pre></td></tr><tr><td class="docs"> 4392 </td><td class="codes"><pre class="brush: clojure">(defn validate-on! [] (reset! validate? true))</pre></td></tr><tr><td class="docs"> 4393 </td><td class="codes"><pre class="brush: clojure">(defn validate-off! [] (reset! validate? false))</pre></td></tr><tr><td class="docs"> 4394 </td><td class="codes"><pre class="brush: clojure">(defn format-tag [{:keys [tag-name tag-value tag-type args]}] 4395 (condp = tag-type 4396 :expr (str *tag-open* *tag-second* " " (name tag-name) " " (if args (str (clojure.string/join args) " ")) *tag-second* *tag-close*) 4397 :filter (str *tag-open* *filter-open* (name tag-value) *filter-close* *tag-close*) 4398 (str tag-name " " tag-value " " tag-type " " args)))</pre></td></tr><tr><td class="docs"> 4399 </td><td class="codes"><pre class="brush: clojure">(defn validation-error 4400 ([error tag line template] 4401 (validation-error 4402 (str error 4403 (if tag (str " " (format-tag tag))) 4404 (if line (str " on line " line)) 4405 (if template (str " for template " template))) 4406 error line [{:tag tag :line line}] template)) 4407 ([long-error short-error line error-tags template] 4408 (throw 4409 (ex-info long-error 4410 {:type :selmer-validation-error 4411 :error short-error 4412 :error-template error-template 4413 :line line 4414 :template template 4415 :validation-errors 4416 (for [error error-tags] 4417 (update-in error [:tag] format-tag))}))))</pre></td></tr><tr><td class="docs"> 4418 </td><td class="codes"><pre class="brush: clojure">(defn validate-filters [template line {:keys [tag-value] :as tag}] 4419 (let [tag-filters (map 4420 #(-> ^String % (.split ":") first keyword) 4421 (-> tag-value name (.split "\\|") rest))] 4422 (if-not (empty? (difference (set tag-filters) (set (keys @filters)))) 4423 (validation-error (str "Unrecognized filter " tag-value " found inside the tag") tag line template))))</pre></td></tr><tr><td class="docs"> 4424 </td><td class="codes"><pre class="brush: clojure">(defn close-tags [] 4425 (apply concat (vals @closing-tags)))</pre></td></tr><tr><td class="docs"> 4426 </td><td class="codes"><pre class="brush: clojure">(defn valide-tag [template line tags {:keys [tag-name args tag-value tag-type] :as tag}] 4427 (condp = tag-type 4428 :expr 4429 (let [last-tag (last tags) 4430 end-tags (get @closing-tags (:tag-name last-tag))] 4431 (doseq [arg args] (validate-filters template line (assoc tag :tag-value arg))) 4432 (cond 4433 (nil? tag-name) 4434 (validation-error "No tag name supplied for the tag" tag line template) 4435 (not-any? #{tag-name} (concat (close-tags) (keys @expr-tags))) 4436 (validation-error "Unrecognized tag found" tag line template) 4437 ;; check if we have closing tag 4438 ;; handle the case where it's an intermediate tag 4439 ;; throw an exception if it doesn't belong to the last open tag 4440 (some #{tag-name} (close-tags)) 4441 (let [tags (vec (butlast tags))] 4442 (if (some #{tag-name} end-tags) 4443 (if (not-empty (get @closing-tags tag-name)) 4444 (conj tags (assoc tag :line line)) tags) 4445 (validation-error "No closing tag found for the tag" last-tag (:line last-tag) template))) 4446 (not-empty (get @closing-tags tag-name)) 4447 (conj tags (assoc tag :line line)) 4448 (some #{tag-name} (close-tags)) 4449 (validation-error "Found an orphan closing tag" tag line template) 4450 :else tags)) 4451 :filter 4452 (do (validate-filters template line tag) tags)))</pre></td></tr><tr><td class="docs"> 4453 </td><td class="codes"><pre class="brush: clojure">(defn skip-verbatim-tags [tag-info rdr line template] 4454 (if (= :verbatim (:tag-name tag-info)) 4455 (loop [ch (read-char rdr)] 4456 (if ch 4457 (if-not (and 4458 (open-tag? ch rdr) 4459 (= :endverbatim (:tag-name (read-tag-info rdr)))) 4460 (recur (read-char rdr))))) 4461 tag-info))</pre></td></tr><tr><td class="docs"> 4462 </td><td class="codes"><pre class="brush: clojure">(defn read-tag [rdr line template] 4463 (try 4464 (-> (read-tag-info rdr) (skip-verbatim-tags rdr line template)) 4465 (catch Exception ex 4466 (validation-error (str "Error parsing the tag: " (.getMessage ex)) nil line template))))</pre></td></tr><tr><td class="docs"> 4467 </td><td class="codes"><pre class="brush: clojure">(defn validate-tags [template] 4468 (with-open [rdr (reader template)] 4469 (loop [tags [], ch (read-char rdr), line 1] 4470 (if ch 4471 (if (open-tag? ch rdr) 4472 (if-let [tag-info (read-tag rdr line template)] 4473 (recur (valide-tag template line tags tag-info) (read-char rdr) line) 4474 (recur tags (read-char rdr) line)) 4475 (recur tags (read-char rdr) (if (= \newline ch) (inc line) line))) 4476 tags))))</pre></td></tr><tr><td class="docs"> 4477 </td><td class="codes"><pre class="brush: clojure">(defn validate [template] 4478 (when @validate? 4479 (check-template-exists template) 4480 (if-let [orphan-tags (not-empty (validate-tags template))] 4481 (validation-error 4482 (->> orphan-tags 4483 (map (fn [{:keys [tag-name line] :as tag}] (str (format-tag tag) " on line " line))) 4484 (interpose ", ") 4485 doall 4486 (clojure.string/join "The template contains orphan tags: ")) 4487 "The template contains orphan tags." 4488 nil 4489 orphan-tags 4490 template))))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr></table><div class="footer">Generated by <a href="https://github.com/gdeer81/marginalia">Marginalia</a>. Syntax highlighting provided by Alex Gorbatchev's <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a><div id="floating-toc"><ul><li class="floating-toc-li" id="floating-toc_selmer.filter-parser">selmer.filter-parser</li><li class="floating-toc-li" id="floating-toc_selmer.filters">selmer.filters</li><li class="floating-toc-li" id="floating-toc_selmer.middleware">selmer.middleware</li><li class="floating-toc-li" id="floating-toc_selmer.node">selmer.node</li><li class="floating-toc-li" id="floating-toc_selmer.parser">selmer.parser</li><li class="floating-toc-li" id="floating-toc_selmer.tags">selmer.tags</li><li class="floating-toc-li" id="floating-toc_selmer.template-parser">selmer.template-parser</li><li class="floating-toc-li" id="floating-toc_selmer.util">selmer.util</li><li class="floating-toc-li" id="floating-toc_selmer.validator">selmer.validator</li></ul></div></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false; 4491 SyntaxHighlighter.all(); 4492 4493 // hackity hack 4494 $(window).load(function() { 4495 var ft = $("#floating-toc"); 4496 var ul = ft.find('ul'); 4497 var lis = ft.find('li'); 4498 var liHeight = $(lis.first()).height(); 4499 4500 ul.css('margin', '0px'); 4501 ft.css('height', liHeight + 'px'); 4502 4503 showNs = function(ns) { 4504 var index = 0; 4505 4506 for(i in nsPositions.nss) { 4507 if(ns == nsPositions.nss[i]) index = i; 4508 } 4509 4510 if(index != lastNsIndex) { 4511 lastNsIndex = index; 4512 ul.animate({marginTop: (-1 * liHeight * index) + 'px'}, 4513 300); 4514 } 4515 4516 } 4517 4518 var calcNsPositions = function() { 4519 var hheight = $('.docs-header').first().height(); 4520 var nss = []; 4521 var anchors = []; 4522 var positions = []; 4523 $.each(lis, function(i, el) { 4524 var ns = $(el).attr('id').split('_')[1]; 4525 nss.push(ns); 4526 var a = $("a[name='"+ns+"']"); 4527 anchors.push(a); 4528 positions.push(a.offset().top - hheight); 4529 // console.log(a.offset().top) 4530 }); 4531 4532 return {nss: nss, positions: positions}; 4533 } 4534 4535 var nsPositions = calcNsPositions(); 4536 // console.log(nsPositions) 4537 var lastNsIndex = -1; 4538 var $window = $(window); 4539 4540 var currentSection = function(nsp) { 4541 var ps = nsp.positions; 4542 var scroll = $window.scrollTop(); 4543 var nsIndex = -1; 4544 4545 for(var i = 0, length = ps.length; i < length; i++) { 4546 if(ps[i] >= scroll) { 4547 nsIndex = i-1; 4548 break; 4549 } 4550 } 4551 4552 if(nsIndex == -1) { 4553 if(scroll >= ps[0]) { 4554 nsIndex = ps.length - 1; 4555 } else { 4556 nsIndex = 0; 4557 } 4558 } 4559 4560 return nsp.nss[nsIndex]; 4561 } 4562 4563 $(window).scroll(function(e) { 4564 showNs(currentSection(nsPositions)); 4565 }); 4566 }); 4567 </script></body></html>