... which it turns out have NEVER worked, and badly written tests were masking the problem. Also tagging rules with metadata as first step towards mixing production and flow rules.
4020 lines
245 KiB
HTML
4020 lines
245 KiB
HTML
<!DOCTYPE html>
|
|
<html><head><meta charset="utf-8" content="text/html" http-equiv="Content-Type" /><meta content="Parser for production rules for MicroWorld engine" name="description" /><style type="text/css">/**
|
|
* SyntaxHighlighter
|
|
* http://alexgorbatchev.com/SyntaxHighlighter
|
|
*
|
|
* SyntaxHighlighter is donationware. If you are using it, please donate.
|
|
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
|
|
*
|
|
* @version
|
|
* 3.0.83 (July 02 2010)
|
|
*
|
|
* @copyright
|
|
* Copyright (C) 2004-2010 Alex Gorbatchev.
|
|
*
|
|
* @license
|
|
* Dual licensed under the MIT and GPL licenses.
|
|
*/
|
|
.syntaxhighlighter a,
|
|
.syntaxhighlighter div,
|
|
.syntaxhighlighter code,
|
|
.syntaxhighlighter table,
|
|
.syntaxhighlighter table td,
|
|
.syntaxhighlighter table tr,
|
|
.syntaxhighlighter table tbody,
|
|
.syntaxhighlighter table thead,
|
|
.syntaxhighlighter table caption,
|
|
.syntaxhighlighter textarea {
|
|
-moz-border-radius: 0 0 0 0 !important;
|
|
-webkit-border-radius: 0 0 0 0 !important;
|
|
background: none !important;
|
|
border: 0 !important;
|
|
bottom: auto !important;
|
|
float: none !important;
|
|
height: auto !important;
|
|
left: auto !important;
|
|
line-height: 1.1em !important;
|
|
/* margin: 0 !important; */
|
|
outline: 0 !important;
|
|
overflow: visible !important;
|
|
padding: 0 !important;
|
|
position: static !important;
|
|
right: auto !important;
|
|
text-align: left !important;
|
|
top: auto !important;
|
|
vertical-align: baseline !important;
|
|
width: auto !important;
|
|
box-sizing: content-box !important;
|
|
font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
|
|
font-weight: normal !important;
|
|
font-style: normal !important;
|
|
min-height: inherit !important;
|
|
min-height: auto !important;
|
|
}
|
|
|
|
.syntaxhighlighter {
|
|
/* width: 100% !important; */
|
|
margin: 1em 0 1em 0 !important;
|
|
position: relative !important;
|
|
overflow: auto !important;
|
|
}
|
|
.syntaxhighlighter.source {
|
|
overflow: hidden !important;
|
|
}
|
|
.syntaxhighlighter .bold {
|
|
font-weight: bold !important;
|
|
}
|
|
.syntaxhighlighter .italic {
|
|
font-style: italic !important;
|
|
}
|
|
.syntaxhighlighter .line {
|
|
white-space: pre !important;
|
|
}
|
|
.syntaxhighlighter table {
|
|
/* width: 100% !important;*/
|
|
}
|
|
.syntaxhighlighter table caption {
|
|
text-align: left !important;
|
|
padding: .5em 0 0.5em 1em !important;
|
|
}
|
|
.syntaxhighlighter table td.code {
|
|
width: 100% !important;
|
|
}
|
|
.syntaxhighlighter table td.code .container {
|
|
position: relative !important;
|
|
}
|
|
.syntaxhighlighter table td.code .container textarea {
|
|
box-sizing: border-box !important;
|
|
position: absolute !important;
|
|
left: 0 !important;
|
|
top: 0 !important;
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
border: none !important;
|
|
background: white !important;
|
|
padding-left: 1em !important;
|
|
overflow: hidden !important;
|
|
white-space: pre !important;
|
|
}
|
|
.syntaxhighlighter table td.gutter .line {
|
|
text-align: right !important;
|
|
padding: 0 0.5em 0 1em !important;
|
|
}
|
|
.syntaxhighlighter table td.code .line {
|
|
padding: 0 1em !important;
|
|
}
|
|
.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
|
|
padding-left: 0em !important;
|
|
}
|
|
.syntaxhighlighter.show {
|
|
display: block !important;
|
|
}
|
|
.syntaxhighlighter.collapsed table {
|
|
display: none !important;
|
|
}
|
|
.syntaxhighlighter.collapsed .toolbar {
|
|
display: none;
|
|
/* padding: 0.1em 0.8em 0em 0.8em !important;
|
|
font-size: 1em !important;
|
|
position: static !important;
|
|
width: auto !important;
|
|
height: auto !important;*/
|
|
}
|
|
.syntaxhighlighter.collapsed .toolbar span {
|
|
display: inline !important;
|
|
margin-right: 1em !important;
|
|
}
|
|
.syntaxhighlighter.collapsed .toolbar span a {
|
|
padding: 0 !important;
|
|
display: none !important;
|
|
}
|
|
.syntaxhighlighter.collapsed .toolbar span a.expandSource {
|
|
display: inline !important;
|
|
}
|
|
.syntaxhighlighter .toolbar {
|
|
display: none;
|
|
/* position: absolute !important;
|
|
right: 1px !important;
|
|
top: 1px !important;
|
|
width: 11px !important;
|
|
height: 11px !important;
|
|
font-size: 10px !important;
|
|
z-index: 10 !important;*/
|
|
}
|
|
.syntaxhighlighter .toolbar span.title {
|
|
display: inline !important;
|
|
}
|
|
.syntaxhighlighter .toolbar a {
|
|
display: block !important;
|
|
text-align: center !important;
|
|
text-decoration: none !important;
|
|
padding-top: 1px !important;
|
|
}
|
|
.syntaxhighlighter .toolbar a.expandSource {
|
|
display: none !important;
|
|
}
|
|
.syntaxhighlighter.ie {
|
|
font-size: .9em !important;
|
|
padding: 1px 0 1px 0 !important;
|
|
}
|
|
.syntaxhighlighter.ie .toolbar {
|
|
line-height: 8px !important;
|
|
}
|
|
.syntaxhighlighter.ie .toolbar a {
|
|
padding-top: 0px !important;
|
|
}
|
|
.syntaxhighlighter.printing .line.alt1 .content,
|
|
.syntaxhighlighter.printing .line.alt2 .content,
|
|
.syntaxhighlighter.printing .line.highlighted .number,
|
|
.syntaxhighlighter.printing .line.highlighted.alt1 .content,
|
|
.syntaxhighlighter.printing .line.highlighted.alt2 .content {
|
|
background: none !important;
|
|
}
|
|
.syntaxhighlighter.printing .line .number {
|
|
color: #bbbbbb !important;
|
|
}
|
|
.syntaxhighlighter.printing .line .content {
|
|
color: black !important;
|
|
}
|
|
.syntaxhighlighter.printing .toolbar {
|
|
display: none !important;
|
|
}
|
|
.syntaxhighlighter.printing a {
|
|
text-decoration: none !important;
|
|
}
|
|
.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
|
|
color: black !important;
|
|
}
|
|
.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
|
|
color: #008200 !important;
|
|
}
|
|
.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
|
|
color: blue !important;
|
|
}
|
|
.syntaxhighlighter.printing .keyword {
|
|
color: #006699 !important;
|
|
font-weight: bold !important;
|
|
}
|
|
.syntaxhighlighter.printing .preprocessor {
|
|
color: gray !important;
|
|
}
|
|
.syntaxhighlighter.printing .variable {
|
|
color: #aa7700 !important;
|
|
}
|
|
.syntaxhighlighter.printing .value {
|
|
color: #009900 !important;
|
|
}
|
|
.syntaxhighlighter.printing .functions {
|
|
color: #ff1493 !important;
|
|
}
|
|
.syntaxhighlighter.printing .constants {
|
|
color: #0066cc !important;
|
|
}
|
|
.syntaxhighlighter.printing .script {
|
|
font-weight: bold !important;
|
|
}
|
|
.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
|
|
color: gray !important;
|
|
}
|
|
.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
|
|
color: #ff1493 !important;
|
|
}
|
|
.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
|
|
color: red !important;
|
|
}
|
|
.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
|
|
color: black !important;
|
|
}
|
|
</style><style type="text/css">.syntaxhighlighter{overflow:hidden !important;}</style><style type="text/css">/**
|
|
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
|
|
*
|
|
* @version
|
|
* 3.0.83 (July 02 2010)
|
|
*
|
|
* @copyright
|
|
* Copyright (C) 2004-2010 Alex Gorbatchev.
|
|
*
|
|
* @license
|
|
* Dual licensed under the MIT and GPL licenses.
|
|
*/
|
|
.syntaxhighlighter {
|
|
background-color: transparent !important;
|
|
}
|
|
.syntaxhighlighter .line.alt1 {
|
|
background-color: transparent !important;
|
|
}
|
|
.syntaxhighlighter .line.alt2 {
|
|
background-color: transparent !important;
|
|
}
|
|
.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
|
|
background-color: #c3defe !important;
|
|
}
|
|
.syntaxhighlighter .line.highlighted.number {
|
|
color: white !important;
|
|
}
|
|
.syntaxhighlighter table caption {
|
|
color: black !important;
|
|
}
|
|
.syntaxhighlighter .gutter {
|
|
color: #787878 !important;
|
|
}
|
|
.syntaxhighlighter .gutter .line {
|
|
border-right: 3px solid #d4d0c8 !important;
|
|
}
|
|
.syntaxhighlighter .gutter .line.highlighted {
|
|
background-color: #d4d0c8 !important;
|
|
color: white !important;
|
|
}
|
|
.syntaxhighlighter.printing .line .content {
|
|
border: none !important;
|
|
}
|
|
.syntaxhighlighter.collapsed {
|
|
overflow: visible !important;
|
|
}
|
|
.syntaxhighlighter.collapsed .toolbar {
|
|
color: #3f5fbf !important;
|
|
background: white !important;
|
|
border: 1px solid #d4d0c8 !important;
|
|
}
|
|
.syntaxhighlighter.collapsed .toolbar a {
|
|
color: #3f5fbf !important;
|
|
}
|
|
.syntaxhighlighter.collapsed .toolbar a:hover {
|
|
color: #aa7700 !important;
|
|
}
|
|
.syntaxhighlighter .toolbar {
|
|
color: #a0a0a0 !important;
|
|
background: #d4d0c8 !important;
|
|
border: none !important;
|
|
}
|
|
.syntaxhighlighter .toolbar a {
|
|
color: #a0a0a0 !important;
|
|
}
|
|
.syntaxhighlighter .toolbar a:hover {
|
|
color: red !important;
|
|
}
|
|
.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
|
|
color: black !important;
|
|
}
|
|
.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
|
|
color: #3f5fbf !important;
|
|
}
|
|
.syntaxhighlighter .string, .syntaxhighlighter .string a {
|
|
color: #2a00ff !important;
|
|
}
|
|
.syntaxhighlighter .keyword {
|
|
color: #7f0055 !important;
|
|
}
|
|
.syntaxhighlighter .preprocessor {
|
|
color: #646464 !important;
|
|
}
|
|
.syntaxhighlighter .variable {
|
|
color: #aa7700 !important;
|
|
}
|
|
.syntaxhighlighter .value {
|
|
color: #009900 !important;
|
|
}
|
|
.syntaxhighlighter .functions {
|
|
color: #ff1493 !important;
|
|
}
|
|
.syntaxhighlighter .constants {
|
|
color: #0066cc !important;
|
|
}
|
|
.syntaxhighlighter .script {
|
|
font-weight: bold !important;
|
|
color: #7f0055 !important;
|
|
background-color: none !important;
|
|
}
|
|
.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
|
|
color: gray !important;
|
|
}
|
|
.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
|
|
color: #ff1493 !important;
|
|
}
|
|
.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
|
|
color: red !important;
|
|
}
|
|
|
|
.syntaxhighlighter .xml .keyword {
|
|
color: #3f7f7f !important;
|
|
font-weight: normal !important;
|
|
}
|
|
.syntaxhighlighter .xml .color1, .syntaxhighlighter .xml .color1 a {
|
|
color: #7f007f !important;
|
|
}
|
|
.syntaxhighlighter .xml .string {
|
|
font-style: italic !important;
|
|
color: #2a00ff !important;
|
|
}
|
|
|
|
.clojure.syntaxhighlighter .invalid {
|
|
background-color: #FAA !important;
|
|
}
|
|
|
|
.clojure.syntaxhighlighter .quoted {
|
|
font-style: italic !important;
|
|
}
|
|
|
|
.syntaxhighlighter .clojure.variable,
|
|
.syntaxhighlighter .clojure.symbol,
|
|
.syntaxhighlighter .clojure.value
|
|
{
|
|
color: #006060 !important;
|
|
}
|
|
|
|
.syntaxhighlighter .clojure.string {
|
|
color: #55B !important;
|
|
}
|
|
|
|
.syntaxhighlighter .clojure.functions {
|
|
color: black !important;
|
|
}
|
|
|
|
.syntaxhighlighter .clojure.color1 {
|
|
color: #666 !important;
|
|
}
|
|
|
|
.syntaxhighlighter .clojure.color3 {
|
|
color: #900 !important;
|
|
}
|
|
|
|
.syntaxhighlighter .clojure.constants {
|
|
color: #1A734D !important;
|
|
}
|
|
|
|
</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 */
|
|
(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")};
|
|
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()
|
|
{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);
|
|
</script><script type="text/javascript">//XRegExp 1.5.0 <xregexp.com> MIT License
|
|
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")})})();
|
|
</script><script type="text/javascript">/**
|
|
* SyntaxHighlighter
|
|
* http://alexgorbatchev.com/SyntaxHighlighter
|
|
*
|
|
* SyntaxHighlighter is donationware. If you are using it, please donate.
|
|
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
|
|
*
|
|
* @version
|
|
* 3.0.83 (July 02 2010)
|
|
*
|
|
* @copyright
|
|
* Copyright (C) 2004-2010 Alex Gorbatchev.
|
|
*
|
|
* @license
|
|
* Dual licensed under the MIT and GPL licenses.
|
|
*/
|
|
//
|
|
// Begin anonymous function. This is used to contain local scope variables without polutting global scope.
|
|
//
|
|
var SyntaxHighlighter = function() {
|
|
|
|
// CommonJS
|
|
if (typeof(require) != 'undefined' && typeof(XRegExp) == 'undefined')
|
|
{
|
|
XRegExp = require('XRegExp').XRegExp;
|
|
}
|
|
|
|
// Shortcut object which will be assigned to the SyntaxHighlighter variable.
|
|
// This is a shorthand for local reference in order to avoid long namespace
|
|
// references to SyntaxHighlighter.whatever...
|
|
var sh = {
|
|
defaults : {
|
|
/** Additional CSS class names to be added to highlighter elements. */
|
|
'class-name' : '',
|
|
|
|
/** First line number. */
|
|
'first-line' : 1,
|
|
|
|
/**
|
|
* Pads line numbers. Possible values are:
|
|
*
|
|
* false - don't pad line numbers.
|
|
* true - automaticaly pad numbers with minimum required number of leading zeroes.
|
|
* [int] - length up to which pad line numbers.
|
|
*/
|
|
'pad-line-numbers' : false,
|
|
|
|
/** Lines to highlight. */
|
|
'highlight' : null,
|
|
|
|
/** Title to be displayed above the code block. */
|
|
'title' : null,
|
|
|
|
/** Enables or disables smart tabs. */
|
|
'smart-tabs' : true,
|
|
|
|
/** Gets or sets tab size. */
|
|
'tab-size' : 4,
|
|
|
|
/** Enables or disables gutter. */
|
|
'gutter' : true,
|
|
|
|
/** Enables or disables toolbar. */
|
|
'toolbar' : true,
|
|
|
|
/** Enables quick code copy and paste from double click. */
|
|
'quick-code' : true,
|
|
|
|
/** Forces code view to be collapsed. */
|
|
'collapse' : false,
|
|
|
|
/** Enables or disables automatic links. */
|
|
'auto-links' : true,
|
|
|
|
/** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */
|
|
'light' : false,
|
|
|
|
'html-script' : false
|
|
},
|
|
|
|
config : {
|
|
space : ' ',
|
|
|
|
/** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */
|
|
useScriptTags : true,
|
|
|
|
/** Blogger mode flag. */
|
|
bloggerMode : false,
|
|
|
|
stripBrs : false,
|
|
|
|
/** Name of the tag that SyntaxHighlighter will automatically look for. */
|
|
tagName : 'pre',
|
|
|
|
strings : {
|
|
expandSource : 'expand source',
|
|
help : '?',
|
|
alert: 'SyntaxHighlighter\n\n',
|
|
noBrush : 'Can\'t find brush for: ',
|
|
brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ',
|
|
|
|
// this is populated by the build script
|
|
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>'
|
|
}
|
|
},
|
|
|
|
/** Internal 'global' variables. */
|
|
vars : {
|
|
discoveredBrushes : null,
|
|
highlighters : {}
|
|
},
|
|
|
|
/** This object is populated by user included external brush files. */
|
|
brushes : {},
|
|
|
|
/** Common regular expressions. */
|
|
regexLib : {
|
|
multiLineCComments : /\/\*[\s\S]*?\*\//gm,
|
|
singleLineCComments : /\/\/.*$/gm,
|
|
singleLinePerlComments : /#.*$/gm,
|
|
doubleQuotedString : /"([^\\"\n]|\\.)*"/g,
|
|
singleQuotedString : /'([^\\'\n]|\\.)*'/g,
|
|
multiLineDoubleQuotedString : new XRegExp('"([^\\\\"]|\\\\.)*"', 'gs'),
|
|
multiLineSingleQuotedString : new XRegExp("'([^\\\\']|\\\\.)*'", 'gs'),
|
|
xmlComments : /(<|<)!--[\s\S]*?--(>|>)/gm,
|
|
url : /\w+:\/\/[\w-.\/?%&=:@;]*/g,
|
|
|
|
/** <?= ?> tags. */
|
|
phpScriptTags : { left: /(<|<)\?=?/g, right: /\?(>|>)/g },
|
|
|
|
/** <%= %> tags. */
|
|
aspScriptTags : { left: /(<|<)%=?/g, right: /%(>|>)/g },
|
|
|
|
scriptScriptTags : { left: /(<|<)\s*script.*?(>|>)/gi, right: /(<|<)\/\s*script\s*(>|>)/gi }
|
|
},
|
|
|
|
toolbar: {
|
|
/**
|
|
* Generates HTML markup for the toolbar.
|
|
* @param {Highlighter} highlighter Highlighter instance.
|
|
* @return {String} Returns HTML markup.
|
|
*/
|
|
getHtml: function(highlighter)
|
|
{
|
|
var html = '<div class="toolbar">',
|
|
items = sh.toolbar.items,
|
|
list = items.list
|
|
;
|
|
|
|
function defaultGetHtml(highlighter, name)
|
|
{
|
|
return sh.toolbar.getButtonHtml(highlighter, name, sh.config.strings[name]);
|
|
};
|
|
|
|
for (var i = 0; i < list.length; i++)
|
|
html += (items[list[i]].getHtml || defaultGetHtml)(highlighter, list[i]);
|
|
|
|
html += '</div>';
|
|
|
|
return html;
|
|
},
|
|
|
|
/**
|
|
* Generates HTML markup for a regular button in the toolbar.
|
|
* @param {Highlighter} highlighter Highlighter instance.
|
|
* @param {String} commandName Command name that would be executed.
|
|
* @param {String} label Label text to display.
|
|
* @return {String} Returns HTML markup.
|
|
*/
|
|
getButtonHtml: function(highlighter, commandName, label)
|
|
{
|
|
return '<span><a href="#" class="toolbar_item'
|
|
+ ' command_' + commandName
|
|
+ ' ' + commandName
|
|
+ '">' + label + '</a></span>'
|
|
;
|
|
},
|
|
|
|
/**
|
|
* Event handler for a toolbar anchor.
|
|
*/
|
|
handler: function(e)
|
|
{
|
|
var target = e.target,
|
|
className = target.className || ''
|
|
;
|
|
|
|
function getValue(name)
|
|
{
|
|
var r = new RegExp(name + '_(\\w+)'),
|
|
match = r.exec(className)
|
|
;
|
|
|
|
return match ? match[1] : null;
|
|
};
|
|
|
|
var highlighter = getHighlighterById(findParentElement(target, '.syntaxhighlighter').id),
|
|
commandName = getValue('command')
|
|
;
|
|
|
|
// execute the toolbar command
|
|
if (highlighter && commandName)
|
|
sh.toolbar.items[commandName].execute(highlighter);
|
|
|
|
// disable default A click behaviour
|
|
e.preventDefault();
|
|
},
|
|
|
|
/** Collection of toolbar items. */
|
|
items : {
|
|
// Ordered lis of items in the toolbar. Can't expect `for (var n in items)` to be consistent.
|
|
list: ['expandSource', 'help'],
|
|
|
|
expandSource: {
|
|
getHtml: function(highlighter)
|
|
{
|
|
if (highlighter.getParam('collapse') != true)
|
|
return '';
|
|
|
|
var title = highlighter.getParam('title');
|
|
return sh.toolbar.getButtonHtml(highlighter, 'expandSource', title ? title : sh.config.strings.expandSource);
|
|
},
|
|
|
|
execute: function(highlighter)
|
|
{
|
|
var div = getHighlighterDivById(highlighter.id);
|
|
removeClass(div, 'collapsed');
|
|
}
|
|
},
|
|
|
|
/** Command to display the about dialog window. */
|
|
help: {
|
|
execute: function(highlighter)
|
|
{
|
|
var wnd = popup('', '_blank', 500, 250, 'scrollbars=0'),
|
|
doc = wnd.document
|
|
;
|
|
|
|
doc.write(sh.config.strings.aboutDialog);
|
|
doc.close();
|
|
wnd.focus();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Finds all elements on the page which should be processes by SyntaxHighlighter.
|
|
*
|
|
* @param {Object} globalParams Optional parameters which override element's
|
|
* parameters. Only used if element is specified.
|
|
*
|
|
* @param {Object} element Optional element to highlight. If none is
|
|
* provided, all elements in the current document
|
|
* are returned which qualify.
|
|
*
|
|
* @return {Array} Returns list of <code>{ target: DOMElement, params: Object }</code> objects.
|
|
*/
|
|
findElements: function(globalParams, element)
|
|
{
|
|
var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)),
|
|
conf = sh.config,
|
|
result = []
|
|
;
|
|
|
|
// support for <SCRIPT TYPE="syntaxhighlighter" /> feature
|
|
if (conf.useScriptTags)
|
|
elements = elements.concat(getSyntaxHighlighterScriptTags());
|
|
|
|
if (elements.length === 0)
|
|
return result;
|
|
|
|
for (var i = 0; i < elements.length; i++)
|
|
{
|
|
var item = {
|
|
target: elements[i],
|
|
// local params take precedence over globals
|
|
params: merge(globalParams, parseParams(elements[i].className))
|
|
};
|
|
|
|
if (item.params['brush'] == null)
|
|
continue;
|
|
|
|
result.push(item);
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Shorthand to highlight all elements on the page that are marked as
|
|
* SyntaxHighlighter source code.
|
|
*
|
|
* @param {Object} globalParams Optional parameters which override element's
|
|
* parameters. Only used if element is specified.
|
|
*
|
|
* @param {Object} element Optional element to highlight. If none is
|
|
* provided, all elements in the current document
|
|
* are highlighted.
|
|
*/
|
|
highlight: function(globalParams, element)
|
|
{
|
|
var elements = this.findElements(globalParams, element),
|
|
propertyName = 'innerHTML',
|
|
highlighter = null,
|
|
conf = sh.config
|
|
;
|
|
|
|
if (elements.length === 0)
|
|
return;
|
|
|
|
for (var i = 0; i < elements.length; i++)
|
|
{
|
|
var element = elements[i],
|
|
target = element.target,
|
|
params = element.params,
|
|
brushName = params.brush,
|
|
code
|
|
;
|
|
|
|
if (brushName == null)
|
|
continue;
|
|
|
|
// Instantiate a brush
|
|
if (params['html-script'] == 'true' || sh.defaults['html-script'] == true)
|
|
{
|
|
highlighter = new sh.HtmlScript(brushName);
|
|
brushName = 'htmlscript';
|
|
}
|
|
else
|
|
{
|
|
var brush = findBrush(brushName);
|
|
|
|
if (brush)
|
|
highlighter = new brush();
|
|
else
|
|
continue;
|
|
}
|
|
|
|
code = target[propertyName];
|
|
|
|
// remove CDATA from <SCRIPT/> tags if it's present
|
|
if (conf.useScriptTags)
|
|
code = stripCData(code);
|
|
|
|
// Inject title if the attribute is present
|
|
if ((target.title || '') != '')
|
|
params.title = target.title;
|
|
|
|
params['brush'] = brushName;
|
|
highlighter.init(params);
|
|
element = highlighter.getDiv(code);
|
|
|
|
// carry over ID
|
|
if ((target.id || '') != '')
|
|
element.id = target.id;
|
|
|
|
target.parentNode.replaceChild(element, target);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Main entry point for the SyntaxHighlighter.
|
|
* @param {Object} params Optional params to apply to all highlighted elements.
|
|
*/
|
|
all: function(params)
|
|
{
|
|
attachEvent(
|
|
window,
|
|
'load',
|
|
function() { sh.highlight(params); }
|
|
);
|
|
}
|
|
}; // end of sh
|
|
|
|
sh['all'] = sh.all;
|
|
sh['highlight'] = sh.highlight;
|
|
|
|
/**
|
|
* Checks if target DOM elements has specified CSS class.
|
|
* @param {DOMElement} target Target DOM element to check.
|
|
* @param {String} className Name of the CSS class to check for.
|
|
* @return {Boolean} Returns true if class name is present, false otherwise.
|
|
*/
|
|
function hasClass(target, className)
|
|
{
|
|
return target.className.indexOf(className) != -1;
|
|
};
|
|
|
|
/**
|
|
* Adds CSS class name to the target DOM element.
|
|
* @param {DOMElement} target Target DOM element.
|
|
* @param {String} className New CSS class to add.
|
|
*/
|
|
function addClass(target, className)
|
|
{
|
|
if (!hasClass(target, className))
|
|
target.className += ' ' + className;
|
|
};
|
|
|
|
/**
|
|
* Removes CSS class name from the target DOM element.
|
|
* @param {DOMElement} target Target DOM element.
|
|
* @param {String} className CSS class to remove.
|
|
*/
|
|
function removeClass(target, className)
|
|
{
|
|
target.className = target.className.replace(className, '');
|
|
};
|
|
|
|
/**
|
|
* Converts the source to array object. Mostly used for function arguments and
|
|
* lists returned by getElementsByTagName() which aren't Array objects.
|
|
* @param {List} source Source list.
|
|
* @return {Array} Returns array.
|
|
*/
|
|
function toArray(source)
|
|
{
|
|
var result = [];
|
|
|
|
for (var i = 0; i < source.length; i++)
|
|
result.push(source[i]);
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Splits block of text into lines.
|
|
* @param {String} block Block of text.
|
|
* @return {Array} Returns array of lines.
|
|
*/
|
|
function splitLines(block)
|
|
{
|
|
return block.split('\n');
|
|
}
|
|
|
|
/**
|
|
* Generates HTML ID for the highlighter.
|
|
* @param {String} highlighterId Highlighter ID.
|
|
* @return {String} Returns HTML ID.
|
|
*/
|
|
function getHighlighterId(id)
|
|
{
|
|
var prefix = 'highlighter_';
|
|
return id.indexOf(prefix) == 0 ? id : prefix + id;
|
|
};
|
|
|
|
/**
|
|
* Finds Highlighter instance by ID.
|
|
* @param {String} highlighterId Highlighter ID.
|
|
* @return {Highlighter} Returns instance of the highlighter.
|
|
*/
|
|
function getHighlighterById(id)
|
|
{
|
|
return sh.vars.highlighters[getHighlighterId(id)];
|
|
};
|
|
|
|
/**
|
|
* Finds highlighter's DIV container.
|
|
* @param {String} highlighterId Highlighter ID.
|
|
* @return {Element} Returns highlighter's DIV element.
|
|
*/
|
|
function getHighlighterDivById(id)
|
|
{
|
|
return document.getElementById(getHighlighterId(id));
|
|
};
|
|
|
|
/**
|
|
* Stores highlighter so that getHighlighterById() can do its thing. Each
|
|
* highlighter must call this method to preserve itself.
|
|
* @param {Highilghter} highlighter Highlighter instance.
|
|
*/
|
|
function storeHighlighter(highlighter)
|
|
{
|
|
sh.vars.highlighters[getHighlighterId(highlighter.id)] = highlighter;
|
|
};
|
|
|
|
/**
|
|
* Looks for a child or parent node which has specified classname.
|
|
* Equivalent to jQuery's $(container).find(".className")
|
|
* @param {Element} target Target element.
|
|
* @param {String} search Class name or node name to look for.
|
|
* @param {Boolean} reverse If set to true, will go up the node tree instead of down.
|
|
* @return {Element} Returns found child or parent element on null.
|
|
*/
|
|
function findElement(target, search, reverse /* optional */)
|
|
{
|
|
if (target == null)
|
|
return null;
|
|
|
|
var nodes = reverse != true ? target.childNodes : [ target.parentNode ],
|
|
propertyToFind = { '#' : 'id', '.' : 'className' }[search.substr(0, 1)] || 'nodeName',
|
|
expectedValue,
|
|
found
|
|
;
|
|
|
|
expectedValue = propertyToFind != 'nodeName'
|
|
? search.substr(1)
|
|
: search.toUpperCase()
|
|
;
|
|
|
|
// main return of the found node
|
|
if ((target[propertyToFind] || '').indexOf(expectedValue) != -1)
|
|
return target;
|
|
|
|
for (var i = 0; nodes && i < nodes.length && found == null; i++)
|
|
found = findElement(nodes[i], search, reverse);
|
|
|
|
return found;
|
|
};
|
|
|
|
/**
|
|
* Looks for a parent node which has specified classname.
|
|
* This is an alias to <code>findElement(container, className, true)</code>.
|
|
* @param {Element} target Target element.
|
|
* @param {String} className Class name to look for.
|
|
* @return {Element} Returns found parent element on null.
|
|
*/
|
|
function findParentElement(target, className)
|
|
{
|
|
return findElement(target, className, true);
|
|
};
|
|
|
|
/**
|
|
* Finds an index of element in the array.
|
|
* @ignore
|
|
* @param {Object} searchElement
|
|
* @param {Number} fromIndex
|
|
* @return {Number} Returns index of element if found; -1 otherwise.
|
|
*/
|
|
function indexOf(array, searchElement, fromIndex)
|
|
{
|
|
fromIndex = Math.max(fromIndex || 0, 0);
|
|
|
|
for (var i = fromIndex; i < array.length; i++)
|
|
if(array[i] == searchElement)
|
|
return i;
|
|
|
|
return -1;
|
|
};
|
|
|
|
/**
|
|
* Generates a unique element ID.
|
|
*/
|
|
function guid(prefix)
|
|
{
|
|
return (prefix || '') + Math.round(Math.random() * 1000000).toString();
|
|
};
|
|
|
|
/**
|
|
* Merges two objects. Values from obj2 override values in obj1.
|
|
* Function is NOT recursive and works only for one dimensional objects.
|
|
* @param {Object} obj1 First object.
|
|
* @param {Object} obj2 Second object.
|
|
* @return {Object} Returns combination of both objects.
|
|
*/
|
|
function merge(obj1, obj2)
|
|
{
|
|
var result = {}, name;
|
|
|
|
for (name in obj1)
|
|
result[name] = obj1[name];
|
|
|
|
for (name in obj2)
|
|
result[name] = obj2[name];
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Attempts to convert string to boolean.
|
|
* @param {String} value Input string.
|
|
* @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise.
|
|
*/
|
|
function toBoolean(value)
|
|
{
|
|
var result = { "true" : true, "false" : false }[value];
|
|
return result == null ? value : result;
|
|
};
|
|
|
|
/**
|
|
* Opens up a centered popup window.
|
|
* @param {String} url URL to open in the window.
|
|
* @param {String} name Popup name.
|
|
* @param {int} width Popup width.
|
|
* @param {int} height Popup height.
|
|
* @param {String} options window.open() options.
|
|
* @return {Window} Returns window instance.
|
|
*/
|
|
function popup(url, name, width, height, options)
|
|
{
|
|
var x = (screen.width - width) / 2,
|
|
y = (screen.height - height) / 2
|
|
;
|
|
|
|
options += ', left=' + x +
|
|
', top=' + y +
|
|
', width=' + width +
|
|
', height=' + height
|
|
;
|
|
options = options.replace(/^,/, '');
|
|
|
|
var win = window.open(url, name, options);
|
|
win.focus();
|
|
return win;
|
|
};
|
|
|
|
/**
|
|
* Adds event handler to the target object.
|
|
* @param {Object} obj Target object.
|
|
* @param {String} type Name of the event.
|
|
* @param {Function} func Handling function.
|
|
*/
|
|
function attachEvent(obj, type, func, scope)
|
|
{
|
|
function handler(e)
|
|
{
|
|
e = e || window.event;
|
|
|
|
if (!e.target)
|
|
{
|
|
e.target = e.srcElement;
|
|
e.preventDefault = function()
|
|
{
|
|
this.returnValue = false;
|
|
};
|
|
}
|
|
|
|
func.call(scope || window, e);
|
|
};
|
|
|
|
if (obj.attachEvent)
|
|
{
|
|
obj.attachEvent('on' + type, handler);
|
|
}
|
|
else
|
|
{
|
|
obj.addEventListener(type, handler, false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Displays an alert.
|
|
* @param {String} str String to display.
|
|
*/
|
|
function alert(str)
|
|
{
|
|
window.alert(sh.config.strings.alert + str);
|
|
};
|
|
|
|
/**
|
|
* Finds a brush by its alias.
|
|
*
|
|
* @param {String} alias Brush alias.
|
|
* @param {Boolean} showAlert Suppresses the alert if false.
|
|
* @return {Brush} Returns bursh constructor if found, null otherwise.
|
|
*/
|
|
function findBrush(alias, showAlert)
|
|
{
|
|
var brushes = sh.vars.discoveredBrushes,
|
|
result = null
|
|
;
|
|
|
|
if (brushes == null)
|
|
{
|
|
brushes = {};
|
|
|
|
// Find all brushes
|
|
for (var brush in sh.brushes)
|
|
{
|
|
var info = sh.brushes[brush],
|
|
aliases = info.aliases
|
|
;
|
|
|
|
if (aliases == null)
|
|
continue;
|
|
|
|
// keep the brush name
|
|
info.brushName = brush.toLowerCase();
|
|
|
|
for (var i = 0; i < aliases.length; i++)
|
|
brushes[aliases[i]] = brush;
|
|
}
|
|
|
|
sh.vars.discoveredBrushes = brushes;
|
|
}
|
|
|
|
result = sh.brushes[brushes[alias]];
|
|
|
|
if (result == null && showAlert != false)
|
|
alert(sh.config.strings.noBrush + alias);
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Executes a callback on each line and replaces each line with result from the callback.
|
|
* @param {Object} str Input string.
|
|
* @param {Object} callback Callback function taking one string argument and returning a string.
|
|
*/
|
|
function eachLine(str, callback)
|
|
{
|
|
var lines = splitLines(str);
|
|
|
|
for (var i = 0; i < lines.length; i++)
|
|
lines[i] = callback(lines[i], i);
|
|
|
|
return lines.join('\n');
|
|
};
|
|
|
|
/**
|
|
* This is a special trim which only removes first and last empty lines
|
|
* and doesn't affect valid leading space on the first line.
|
|
*
|
|
* @param {String} str Input string
|
|
* @return {String} Returns string without empty first and last lines.
|
|
*/
|
|
function trimFirstAndLastLines(str)
|
|
{
|
|
return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, '');
|
|
};
|
|
|
|
/**
|
|
* Parses key/value pairs into hash object.
|
|
*
|
|
* Understands the following formats:
|
|
* - name: word;
|
|
* - name: [word, word];
|
|
* - name: "string";
|
|
* - name: 'string';
|
|
*
|
|
* For example:
|
|
* name1: value; name2: [value, value]; name3: 'value'
|
|
*
|
|
* @param {String} str Input string.
|
|
* @return {Object} Returns deserialized object.
|
|
*/
|
|
function parseParams(str)
|
|
{
|
|
var match,
|
|
result = {},
|
|
arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"),
|
|
regex = new XRegExp(
|
|
"(?<name>[\\w-]+)" +
|
|
"\\s*:\\s*" +
|
|
"(?<value>" +
|
|
"[\\w-%#]+|" + // word
|
|
"\\[.*?\\]|" + // [] array
|
|
'".*?"|' + // "" string
|
|
"'.*?'" + // '' string
|
|
")\\s*;?",
|
|
"g"
|
|
)
|
|
;
|
|
|
|
while ((match = regex.exec(str)) != null)
|
|
{
|
|
var value = match.value
|
|
.replace(/^['"]|['"]$/g, '') // strip quotes from end of strings
|
|
;
|
|
|
|
// try to parse array value
|
|
if (value != null && arrayRegex.test(value))
|
|
{
|
|
var m = arrayRegex.exec(value);
|
|
value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : [];
|
|
}
|
|
|
|
result[match.name] = value;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Wraps each line of the string into <code/> tag with given style applied to it.
|
|
*
|
|
* @param {String} str Input string.
|
|
* @param {String} css Style name to apply to the string.
|
|
* @return {String} Returns input string with each line surrounded by <span/> tag.
|
|
*/
|
|
function wrapLinesWithCode(str, css)
|
|
{
|
|
if (str == null || str.length == 0 || str == '\n')
|
|
return str;
|
|
|
|
str = str.replace(/</g, '<');
|
|
|
|
// Replace two or more sequential spaces with leaving last space untouched.
|
|
str = str.replace(/ {2,}/g, function(m)
|
|
{
|
|
var spaces = '';
|
|
|
|
for (var i = 0; i < m.length - 1; i++)
|
|
spaces += sh.config.space;
|
|
|
|
return spaces + ' ';
|
|
});
|
|
|
|
// Split each line and apply <span class="...">...</span> to them so that
|
|
// leading spaces aren't included.
|
|
if (css != null)
|
|
str = eachLine(str, function(line)
|
|
{
|
|
if (line.length == 0)
|
|
return '';
|
|
|
|
var spaces = '';
|
|
|
|
line = line.replace(/^( | )+/, function(s)
|
|
{
|
|
spaces = s;
|
|
return '';
|
|
});
|
|
|
|
if (line.length == 0)
|
|
return spaces;
|
|
|
|
return spaces + '<code class="' + css + '">' + line + '</code>';
|
|
});
|
|
|
|
return str;
|
|
};
|
|
|
|
/**
|
|
* Pads number with zeros until it's length is the same as given length.
|
|
*
|
|
* @param {Number} number Number to pad.
|
|
* @param {Number} length Max string length with.
|
|
* @return {String} Returns a string padded with proper amount of '0'.
|
|
*/
|
|
function padNumber(number, length)
|
|
{
|
|
var result = number.toString();
|
|
|
|
while (result.length < length)
|
|
result = '0' + result;
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Replaces tabs with spaces.
|
|
*
|
|
* @param {String} code Source code.
|
|
* @param {Number} tabSize Size of the tab.
|
|
* @return {String} Returns code with all tabs replaces by spaces.
|
|
*/
|
|
function processTabs(code, tabSize)
|
|
{
|
|
var tab = '';
|
|
|
|
for (var i = 0; i < tabSize; i++)
|
|
tab += ' ';
|
|
|
|
return code.replace(/\t/g, tab);
|
|
};
|
|
|
|
/**
|
|
* Replaces tabs with smart spaces.
|
|
*
|
|
* @param {String} code Code to fix the tabs in.
|
|
* @param {Number} tabSize Number of spaces in a column.
|
|
* @return {String} Returns code with all tabs replaces with roper amount of spaces.
|
|
*/
|
|
function processSmartTabs(code, tabSize)
|
|
{
|
|
var lines = splitLines(code),
|
|
tab = '\t',
|
|
spaces = ''
|
|
;
|
|
|
|
// Create a string with 1000 spaces to copy spaces from...
|
|
// It's assumed that there would be no indentation longer than that.
|
|
for (var i = 0; i < 50; i++)
|
|
spaces += ' '; // 20 spaces * 50
|
|
|
|
// This function inserts specified amount of spaces in the string
|
|
// where a tab is while removing that given tab.
|
|
function insertSpaces(line, pos, count)
|
|
{
|
|
return line.substr(0, pos)
|
|
+ spaces.substr(0, count)
|
|
+ line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab
|
|
;
|
|
};
|
|
|
|
// Go through all the lines and do the 'smart tabs' magic.
|
|
code = eachLine(code, function(line)
|
|
{
|
|
if (line.indexOf(tab) == -1)
|
|
return line;
|
|
|
|
var pos = 0;
|
|
|
|
while ((pos = line.indexOf(tab)) != -1)
|
|
{
|
|
// This is pretty much all there is to the 'smart tabs' logic.
|
|
// Based on the position within the line and size of a tab,
|
|
// calculate the amount of spaces we need to insert.
|
|
var spaces = tabSize - pos % tabSize;
|
|
line = insertSpaces(line, pos, spaces);
|
|
}
|
|
|
|
return line;
|
|
});
|
|
|
|
return code;
|
|
};
|
|
|
|
/**
|
|
* Performs various string fixes based on configuration.
|
|
*/
|
|
function fixInputString(str)
|
|
{
|
|
var br = /<br\s*\/?>|<br\s*\/?>/gi;
|
|
|
|
if (sh.config.bloggerMode == true)
|
|
str = str.replace(br, '\n');
|
|
|
|
if (sh.config.stripBrs == true)
|
|
str = str.replace(br, '');
|
|
|
|
return str;
|
|
};
|
|
|
|
/**
|
|
* Removes all white space at the begining and end of a string.
|
|
*
|
|
* @param {String} str String to trim.
|
|
* @return {String} Returns string without leading and following white space characters.
|
|
*/
|
|
function trim(str)
|
|
{
|
|
return str.replace(/^\s+|\s+$/g, '');
|
|
};
|
|
|
|
/**
|
|
* Unindents a block of text by the lowest common indent amount.
|
|
* @param {String} str Text to unindent.
|
|
* @return {String} Returns unindented text block.
|
|
*/
|
|
function unindent(str)
|
|
{
|
|
var lines = splitLines(fixInputString(str)),
|
|
indents = new Array(),
|
|
regex = /^\s*/,
|
|
min = 1000
|
|
;
|
|
|
|
// go through every line and check for common number of indents
|
|
for (var i = 0; i < lines.length && min > 0; i++)
|
|
{
|
|
var line = lines[i];
|
|
|
|
if (trim(line).length == 0)
|
|
continue;
|
|
|
|
var matches = regex.exec(line);
|
|
|
|
// In the event that just one line doesn't have leading white space
|
|
// we can't unindent anything, so bail completely.
|
|
if (matches == null)
|
|
return str;
|
|
|
|
min = Math.min(matches[0].length, min);
|
|
}
|
|
|
|
// trim minimum common number of white space from the begining of every line
|
|
if (min > 0)
|
|
for (var i = 0; i < lines.length; i++)
|
|
lines[i] = lines[i].substr(min);
|
|
|
|
return lines.join('\n');
|
|
};
|
|
|
|
/**
|
|
* Callback method for Array.sort() which sorts matches by
|
|
* index position and then by length.
|
|
*
|
|
* @param {Match} m1 Left object.
|
|
* @param {Match} m2 Right object.
|
|
* @return {Number} Returns -1, 0 or -1 as a comparison result.
|
|
*/
|
|
function matchesSortCallback(m1, m2)
|
|
{
|
|
// sort matches by index first
|
|
if(m1.index < m2.index)
|
|
return -1;
|
|
else if(m1.index > m2.index)
|
|
return 1;
|
|
else
|
|
{
|
|
// if index is the same, sort by length
|
|
if(m1.length < m2.length)
|
|
return -1;
|
|
else if(m1.length > m2.length)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
/**
|
|
* Executes given regular expression on provided code and returns all
|
|
* matches that are found.
|
|
*
|
|
* @param {String} code Code to execute regular expression on.
|
|
* @param {Object} regex Regular expression item info from <code>regexList</code> collection.
|
|
* @return {Array} Returns a list of Match objects.
|
|
*/
|
|
function getMatches(code, regexInfo)
|
|
{
|
|
function defaultAdd(match, regexInfo)
|
|
{
|
|
return match[0];
|
|
};
|
|
|
|
var index = 0,
|
|
match = null,
|
|
matches = [],
|
|
func = regexInfo.func ? regexInfo.func : defaultAdd
|
|
;
|
|
|
|
while((match = regexInfo.regex.exec(code)) != null)
|
|
{
|
|
var resultMatch = func(match, regexInfo);
|
|
|
|
if (typeof(resultMatch) == 'string')
|
|
resultMatch = [new sh.Match(resultMatch, match.index, regexInfo.css)];
|
|
|
|
matches = matches.concat(resultMatch);
|
|
}
|
|
|
|
return matches;
|
|
};
|
|
|
|
/**
|
|
* Turns all URLs in the code into <a/> tags.
|
|
* @param {String} code Input code.
|
|
* @return {String} Returns code with </a> tags.
|
|
*/
|
|
function processUrls(code)
|
|
{
|
|
var gt = /(.*)((>|<).*)/;
|
|
|
|
return code.replace(sh.regexLib.url, function(m)
|
|
{
|
|
var suffix = '',
|
|
match = null
|
|
;
|
|
|
|
// We include < and > in the URL for the common cases like <http://google.com>
|
|
// The problem is that they get transformed into <http://google.com>
|
|
// Where as > easily looks like part of the URL string.
|
|
|
|
if (match = gt.exec(m))
|
|
{
|
|
m = match[1];
|
|
suffix = match[2];
|
|
}
|
|
|
|
return '<a href="' + m + '">' + m + '</a>' + suffix;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Finds all <SCRIPT TYPE="syntaxhighlighter" /> elementss.
|
|
* @return {Array} Returns array of all found SyntaxHighlighter tags.
|
|
*/
|
|
function getSyntaxHighlighterScriptTags()
|
|
{
|
|
var tags = document.getElementsByTagName('script'),
|
|
result = []
|
|
;
|
|
|
|
for (var i = 0; i < tags.length; i++)
|
|
if (tags[i].type == 'syntaxhighlighter')
|
|
result.push(tags[i]);
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Strips <![CDATA[]]> from <SCRIPT /> content because it should be used
|
|
* there in most cases for XHTML compliance.
|
|
* @param {String} original Input code.
|
|
* @return {String} Returns code without leading <![CDATA[]]> tags.
|
|
*/
|
|
function stripCData(original)
|
|
{
|
|
var left = '<![CDATA[',
|
|
right = ']]>',
|
|
// for some reason IE inserts some leading blanks here
|
|
copy = trim(original),
|
|
changed = false,
|
|
leftLength = left.length,
|
|
rightLength = right.length
|
|
;
|
|
|
|
if (copy.indexOf(left) == 0)
|
|
{
|
|
copy = copy.substring(leftLength);
|
|
changed = true;
|
|
}
|
|
|
|
var copyLength = copy.length;
|
|
|
|
if (copy.indexOf(right) == copyLength - rightLength)
|
|
{
|
|
copy = copy.substring(0, copyLength - rightLength);
|
|
changed = true;
|
|
}
|
|
|
|
return changed ? copy : original;
|
|
};
|
|
|
|
|
|
/**
|
|
* Quick code mouse double click handler.
|
|
*/
|
|
function quickCodeHandler(e)
|
|
{
|
|
var target = e.target,
|
|
highlighterDiv = findParentElement(target, '.syntaxhighlighter'),
|
|
container = findParentElement(target, '.container'),
|
|
textarea = document.createElement('textarea'),
|
|
highlighter
|
|
;
|
|
|
|
if (!container || !highlighterDiv || findElement(container, 'textarea'))
|
|
return;
|
|
|
|
highlighter = getHighlighterById(highlighterDiv.id);
|
|
|
|
// add source class name
|
|
addClass(highlighterDiv, 'source');
|
|
|
|
// Have to go over each line and grab it's text, can't just do it on the
|
|
// container because Firefox loses all \n where as Webkit doesn't.
|
|
var lines = container.childNodes,
|
|
code = []
|
|
;
|
|
|
|
for (var i = 0; i < lines.length; i++)
|
|
code.push(lines[i].innerText || lines[i].textContent);
|
|
|
|
// using \r instead of \r or \r\n makes this work equally well on IE, FF and Webkit
|
|
code = code.join('\r');
|
|
|
|
// inject <textarea/> tag
|
|
textarea.appendChild(document.createTextNode(code));
|
|
container.appendChild(textarea);
|
|
|
|
// preselect all text
|
|
textarea.focus();
|
|
textarea.select();
|
|
|
|
// set up handler for lost focus
|
|
attachEvent(textarea, 'blur', function(e)
|
|
{
|
|
textarea.parentNode.removeChild(textarea);
|
|
removeClass(highlighterDiv, 'source');
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Match object.
|
|
*/
|
|
sh.Match = function(value, index, css)
|
|
{
|
|
this.value = value;
|
|
this.index = index;
|
|
this.length = value.length;
|
|
this.css = css;
|
|
this.brushName = null;
|
|
};
|
|
|
|
sh.Match.prototype.toString = function()
|
|
{
|
|
return this.value;
|
|
};
|
|
|
|
/**
|
|
* Simulates HTML code with a scripting language embedded.
|
|
*
|
|
* @param {String} scriptBrushName Brush name of the scripting language.
|
|
*/
|
|
sh.HtmlScript = function(scriptBrushName)
|
|
{
|
|
var brushClass = findBrush(scriptBrushName),
|
|
scriptBrush,
|
|
xmlBrush = new sh.brushes.Xml(),
|
|
bracketsRegex = null,
|
|
ref = this,
|
|
methodsToExpose = 'getDiv getHtml init'.split(' ')
|
|
;
|
|
|
|
if (brushClass == null)
|
|
return;
|
|
|
|
scriptBrush = new brushClass();
|
|
|
|
for(var i = 0; i < methodsToExpose.length; i++)
|
|
// make a closure so we don't lose the name after i changes
|
|
(function() {
|
|
var name = methodsToExpose[i];
|
|
|
|
ref[name] = function()
|
|
{
|
|
return xmlBrush[name].apply(xmlBrush, arguments);
|
|
};
|
|
})();
|
|
|
|
if (scriptBrush.htmlScript == null)
|
|
{
|
|
alert(sh.config.strings.brushNotHtmlScript + scriptBrushName);
|
|
return;
|
|
}
|
|
|
|
xmlBrush.regexList.push(
|
|
{ regex: scriptBrush.htmlScript.code, func: process }
|
|
);
|
|
|
|
function offsetMatches(matches, offset)
|
|
{
|
|
for (var j = 0; j < matches.length; j++)
|
|
matches[j].index += offset;
|
|
}
|
|
|
|
function process(match, info)
|
|
{
|
|
var code = match.code,
|
|
matches = [],
|
|
regexList = scriptBrush.regexList,
|
|
offset = match.index + match.left.length,
|
|
htmlScript = scriptBrush.htmlScript,
|
|
result
|
|
;
|
|
|
|
// add all matches from the code
|
|
for (var i = 0; i < regexList.length; i++)
|
|
{
|
|
result = getMatches(code, regexList[i]);
|
|
offsetMatches(result, offset);
|
|
matches = matches.concat(result);
|
|
}
|
|
|
|
// add left script bracket
|
|
if (htmlScript.left != null && match.left != null)
|
|
{
|
|
result = getMatches(match.left, htmlScript.left);
|
|
offsetMatches(result, match.index);
|
|
matches = matches.concat(result);
|
|
}
|
|
|
|
// add right script bracket
|
|
if (htmlScript.right != null && match.right != null)
|
|
{
|
|
result = getMatches(match.right, htmlScript.right);
|
|
offsetMatches(result, match.index + match[0].lastIndexOf(match.right));
|
|
matches = matches.concat(result);
|
|
}
|
|
|
|
for (var j = 0; j < matches.length; j++)
|
|
matches[j].brushName = brushClass.brushName;
|
|
|
|
return matches;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Main Highlither class.
|
|
* @constructor
|
|
*/
|
|
sh.Highlighter = function()
|
|
{
|
|
// not putting any code in here because of the prototype inheritance
|
|
};
|
|
|
|
sh.Highlighter.prototype = {
|
|
/**
|
|
* Returns value of the parameter passed to the highlighter.
|
|
* @param {String} name Name of the parameter.
|
|
* @param {Object} defaultValue Default value.
|
|
* @return {Object} Returns found value or default value otherwise.
|
|
*/
|
|
getParam: function(name, defaultValue)
|
|
{
|
|
var result = this.params[name];
|
|
return toBoolean(result == null ? defaultValue : result);
|
|
},
|
|
|
|
/**
|
|
* Shortcut to document.createElement().
|
|
* @param {String} name Name of the element to create (DIV, A, etc).
|
|
* @return {HTMLElement} Returns new HTML element.
|
|
*/
|
|
create: function(name)
|
|
{
|
|
return document.createElement(name);
|
|
},
|
|
|
|
/**
|
|
* Applies all regular expression to the code and stores all found
|
|
* matches in the `this.matches` array.
|
|
* @param {Array} regexList List of regular expressions.
|
|
* @param {String} code Source code.
|
|
* @return {Array} Returns list of matches.
|
|
*/
|
|
findMatches: function(regexList, code)
|
|
{
|
|
var result = [];
|
|
|
|
if (regexList != null)
|
|
for (var i = 0; i < regexList.length; i++)
|
|
// BUG: length returns len+1 for array if methods added to prototype chain (oising@gmail.com)
|
|
if (typeof (regexList[i]) == "object")
|
|
result = result.concat(getMatches(code, regexList[i]));
|
|
|
|
// sort and remove nested the matches
|
|
return this.removeNestedMatches(result.sort(matchesSortCallback));
|
|
},
|
|
|
|
/**
|
|
* Checks to see if any of the matches are inside of other matches.
|
|
* This process would get rid of highligted strings inside comments,
|
|
* keywords inside strings and so on.
|
|
*/
|
|
removeNestedMatches: function(matches)
|
|
{
|
|
// Optimized by Jose Prado (http://joseprado.com)
|
|
for (var i = 0; i < matches.length; i++)
|
|
{
|
|
if (matches[i] === null)
|
|
continue;
|
|
|
|
var itemI = matches[i],
|
|
itemIEndPos = itemI.index + itemI.length
|
|
;
|
|
|
|
for (var j = i + 1; j < matches.length && matches[i] !== null; j++)
|
|
{
|
|
var itemJ = matches[j];
|
|
|
|
if (itemJ === null)
|
|
continue;
|
|
else if (itemJ.index > itemIEndPos)
|
|
break;
|
|
else if (itemJ.index == itemI.index && itemJ.length > itemI.length)
|
|
matches[i] = null;
|
|
else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos)
|
|
matches[j] = null;
|
|
}
|
|
}
|
|
|
|
return matches;
|
|
},
|
|
|
|
/**
|
|
* Creates an array containing integer line numbers starting from the 'first-line' param.
|
|
* @return {Array} Returns array of integers.
|
|
*/
|
|
figureOutLineNumbers: function(code)
|
|
{
|
|
var lines = [],
|
|
firstLine = parseInt(this.getParam('first-line'))
|
|
;
|
|
|
|
eachLine(code, function(line, index)
|
|
{
|
|
lines.push(index + firstLine);
|
|
});
|
|
|
|
return lines;
|
|
},
|
|
|
|
/**
|
|
* Determines if specified line number is in the highlighted list.
|
|
*/
|
|
isLineHighlighted: function(lineNumber)
|
|
{
|
|
var list = this.getParam('highlight', []);
|
|
|
|
if (typeof(list) != 'object' && list.push == null)
|
|
list = [ list ];
|
|
|
|
return indexOf(list, lineNumber.toString()) != -1;
|
|
},
|
|
|
|
/**
|
|
* Generates HTML markup for a single line of code while determining alternating line style.
|
|
* @param {Integer} lineNumber Line number.
|
|
* @param {String} code Line HTML markup.
|
|
* @return {String} Returns HTML markup.
|
|
*/
|
|
getLineHtml: function(lineIndex, lineNumber, code)
|
|
{
|
|
var classes = [
|
|
'line',
|
|
'number' + lineNumber,
|
|
'index' + lineIndex,
|
|
'alt' + (lineNumber % 2 == 0 ? 1 : 2).toString()
|
|
];
|
|
|
|
if (this.isLineHighlighted(lineNumber))
|
|
classes.push('highlighted');
|
|
|
|
if (lineNumber == 0)
|
|
classes.push('break');
|
|
|
|
return '<div class="' + classes.join(' ') + '">' + code + '</div>';
|
|
},
|
|
|
|
/**
|
|
* Generates HTML markup for line number column.
|
|
* @param {String} code Complete code HTML markup.
|
|
* @param {Array} lineNumbers Calculated line numbers.
|
|
* @return {String} Returns HTML markup.
|
|
*/
|
|
getLineNumbersHtml: function(code, lineNumbers)
|
|
{
|
|
var html = '',
|
|
count = splitLines(code).length,
|
|
firstLine = parseInt(this.getParam('first-line')),
|
|
pad = this.getParam('pad-line-numbers')
|
|
;
|
|
|
|
if (pad == true)
|
|
pad = (firstLine + count - 1).toString().length;
|
|
else if (isNaN(pad) == true)
|
|
pad = 0;
|
|
|
|
for (var i = 0; i < count; i++)
|
|
{
|
|
var lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i,
|
|
code = lineNumber == 0 ? sh.config.space : padNumber(lineNumber, pad)
|
|
;
|
|
|
|
html += this.getLineHtml(i, lineNumber, code);
|
|
}
|
|
|
|
return html;
|
|
},
|
|
|
|
/**
|
|
* Splits block of text into individual DIV lines.
|
|
* @param {String} code Code to highlight.
|
|
* @param {Array} lineNumbers Calculated line numbers.
|
|
* @return {String} Returns highlighted code in HTML form.
|
|
*/
|
|
getCodeLinesHtml: function(html, lineNumbers)
|
|
{
|
|
html = trim(html);
|
|
|
|
var lines = splitLines(html),
|
|
padLength = this.getParam('pad-line-numbers'),
|
|
firstLine = parseInt(this.getParam('first-line')),
|
|
html = '',
|
|
brushName = this.getParam('brush')
|
|
;
|
|
|
|
for (var i = 0; i < lines.length; i++)
|
|
{
|
|
var line = lines[i],
|
|
indent = /^( |\s)+/.exec(line),
|
|
spaces = null,
|
|
lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i;
|
|
;
|
|
|
|
if (indent != null)
|
|
{
|
|
spaces = indent[0].toString();
|
|
line = line.substr(spaces.length);
|
|
spaces = spaces.replace(' ', sh.config.space);
|
|
}
|
|
|
|
line = trim(line);
|
|
|
|
if (line.length == 0)
|
|
line = sh.config.space;
|
|
|
|
html += this.getLineHtml(
|
|
i,
|
|
lineNumber,
|
|
(spaces != null ? '<code class="' + brushName + ' spaces">' + spaces + '</code>' : '') + line
|
|
);
|
|
}
|
|
|
|
return html;
|
|
},
|
|
|
|
/**
|
|
* Returns HTML for the table title or empty string if title is null.
|
|
*/
|
|
getTitleHtml: function(title)
|
|
{
|
|
return title ? '<caption>' + title + '</caption>' : '';
|
|
},
|
|
|
|
/**
|
|
* Finds all matches in the source code.
|
|
* @param {String} code Source code to process matches in.
|
|
* @param {Array} matches Discovered regex matches.
|
|
* @return {String} Returns formatted HTML with processed mathes.
|
|
*/
|
|
getMatchesHtml: function(code, matches)
|
|
{
|
|
var pos = 0,
|
|
result = '',
|
|
brushName = this.getParam('brush', '')
|
|
;
|
|
|
|
function getBrushNameCss(match)
|
|
{
|
|
var result = match ? (match.brushName || brushName) : brushName;
|
|
return result ? result + ' ' : '';
|
|
};
|
|
|
|
// Finally, go through the final list of matches and pull the all
|
|
// together adding everything in between that isn't a match.
|
|
for (var i = 0; i < matches.length; i++)
|
|
{
|
|
var match = matches[i],
|
|
matchBrushName
|
|
;
|
|
|
|
if (match === null || match.length === 0)
|
|
continue;
|
|
|
|
matchBrushName = getBrushNameCss(match);
|
|
|
|
result += wrapLinesWithCode(code.substr(pos, match.index - pos), matchBrushName + 'plain')
|
|
+ wrapLinesWithCode(match.value, matchBrushName + match.css)
|
|
;
|
|
|
|
pos = match.index + match.length + (match.offset || 0);
|
|
}
|
|
|
|
// don't forget to add whatever's remaining in the string
|
|
result += wrapLinesWithCode(code.substr(pos), getBrushNameCss() + 'plain');
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Generates HTML markup for the whole syntax highlighter.
|
|
* @param {String} code Source code.
|
|
* @return {String} Returns HTML markup.
|
|
*/
|
|
getHtml: function(code)
|
|
{
|
|
var html = '',
|
|
classes = [ 'syntaxhighlighter' ],
|
|
tabSize,
|
|
matches,
|
|
lineNumbers
|
|
;
|
|
|
|
// process light mode
|
|
if (this.getParam('light') == true)
|
|
this.params.toolbar = this.params.gutter = false;
|
|
|
|
className = 'syntaxhighlighter';
|
|
|
|
if (this.getParam('collapse') == true)
|
|
classes.push('collapsed');
|
|
|
|
if ((gutter = this.getParam('gutter')) == false)
|
|
classes.push('nogutter');
|
|
|
|
// add custom user style name
|
|
classes.push(this.getParam('class-name'));
|
|
|
|
// add brush alias to the class name for custom CSS
|
|
classes.push(this.getParam('brush'));
|
|
|
|
code = trimFirstAndLastLines(code)
|
|
.replace(/\r/g, ' ') // IE lets these buggers through
|
|
;
|
|
|
|
tabSize = this.getParam('tab-size');
|
|
|
|
// replace tabs with spaces
|
|
code = this.getParam('smart-tabs') == true
|
|
? processSmartTabs(code, tabSize)
|
|
: processTabs(code, tabSize)
|
|
;
|
|
|
|
// unindent code by the common indentation
|
|
code = unindent(code);
|
|
|
|
if (gutter)
|
|
lineNumbers = this.figureOutLineNumbers(code);
|
|
|
|
// find matches in the code using brushes regex list
|
|
matches = this.findMatches(this.regexList, code);
|
|
// processes found matches into the html
|
|
html = this.getMatchesHtml(code, matches);
|
|
// finally, split all lines so that they wrap well
|
|
html = this.getCodeLinesHtml(html, lineNumbers);
|
|
|
|
// finally, process the links
|
|
if (this.getParam('auto-links'))
|
|
html = processUrls(html);
|
|
|
|
if (typeof(navigator) != 'undefined' && navigator.userAgent && navigator.userAgent.match(/MSIE/))
|
|
classes.push('ie');
|
|
|
|
html =
|
|
'<div id="' + getHighlighterId(this.id) + '" class="' + classes.join(' ') + '">'
|
|
+ (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '')
|
|
+ '<table border="0" cellpadding="0" cellspacing="0">'
|
|
+ this.getTitleHtml(this.getParam('title'))
|
|
+ '<tbody>'
|
|
+ '<tr>'
|
|
+ (gutter ? '<td class="gutter">' + this.getLineNumbersHtml(code) + '</td>' : '')
|
|
+ '<td class="code">'
|
|
+ '<div class="container">'
|
|
+ html
|
|
+ '</div>'
|
|
+ '</td>'
|
|
+ '</tr>'
|
|
+ '</tbody>'
|
|
+ '</table>'
|
|
+ '</div>'
|
|
;
|
|
|
|
return html;
|
|
},
|
|
|
|
/**
|
|
* Highlights the code and returns complete HTML.
|
|
* @param {String} code Code to highlight.
|
|
* @return {Element} Returns container DIV element with all markup.
|
|
*/
|
|
getDiv: function(code)
|
|
{
|
|
if (code === null)
|
|
code = '';
|
|
|
|
this.code = code;
|
|
|
|
var div = this.create('div');
|
|
|
|
// create main HTML
|
|
div.innerHTML = this.getHtml(code);
|
|
|
|
// set up click handlers
|
|
if (this.getParam('toolbar'))
|
|
attachEvent(findElement(div, '.toolbar'), 'click', sh.toolbar.handler);
|
|
|
|
if (this.getParam('quick-code'))
|
|
attachEvent(findElement(div, '.code'), 'dblclick', quickCodeHandler);
|
|
|
|
return div;
|
|
},
|
|
|
|
/**
|
|
* Initializes the highlighter/brush.
|
|
*
|
|
* Constructor isn't used for initialization so that nothing executes during necessary
|
|
* `new SyntaxHighlighter.Highlighter()` call when setting up brush inheritence.
|
|
*
|
|
* @param {Hash} params Highlighter parameters.
|
|
*/
|
|
init: function(params)
|
|
{
|
|
this.id = guid();
|
|
|
|
// register this instance in the highlighters list
|
|
storeHighlighter(this);
|
|
|
|
// local params take precedence over defaults
|
|
this.params = merge(sh.defaults, params || {})
|
|
|
|
// process light mode
|
|
if (this.getParam('light') == true)
|
|
this.params.toolbar = this.params.gutter = false;
|
|
},
|
|
|
|
/**
|
|
* Converts space separated list of keywords into a regular expression string.
|
|
* @param {String} str Space separated keywords.
|
|
* @return {String} Returns regular expression string.
|
|
*/
|
|
getKeywords: function(str)
|
|
{
|
|
str = str
|
|
.replace(/^\s+|\s+$/g, '')
|
|
.replace(/\s+/g, '|')
|
|
;
|
|
|
|
return '\\b(?:' + str + ')\\b';
|
|
},
|
|
|
|
/**
|
|
* Makes a brush compatible with the `html-script` functionality.
|
|
* @param {Object} regexGroup Object containing `left` and `right` regular expressions.
|
|
*/
|
|
forHtmlScript: function(regexGroup)
|
|
{
|
|
this.htmlScript = {
|
|
left : { regex: regexGroup.left, css: 'script' },
|
|
right : { regex: regexGroup.right, css: 'script' },
|
|
code : new XRegExp(
|
|
"(?<left>" + regexGroup.left.source + ")" +
|
|
"(?<code>.*?)" +
|
|
"(?<right>" + regexGroup.right.source + ")",
|
|
"sgi"
|
|
)
|
|
};
|
|
}
|
|
}; // end of Highlighter
|
|
|
|
return sh;
|
|
}(); // end of anonymous function
|
|
|
|
// CommonJS
|
|
typeof(exports) != 'undefined' ? exports['SyntaxHighlighter'] = SyntaxHighlighter : null;
|
|
</script><script type="text/javascript">// (inc clojure-brush) ;; an improved SyntaxHighlighter brush for clojure
|
|
//
|
|
// Copyright (C) 2011 Andrew Brehaut
|
|
//
|
|
// Distributed under the Eclipse Public License, the same as Clojure.
|
|
//
|
|
// https://github.com/brehaut/inc-clojure-brush
|
|
//
|
|
// Written by Andrew Brehaut
|
|
// V0.9.1, November 2011
|
|
|
|
if (typeof net == "undefined") net = {};
|
|
if (!(net.brehaut)) net.brehaut = {};
|
|
|
|
net.brehaut.ClojureTools = (function (SH) {
|
|
"use strict";
|
|
// utiliies
|
|
if (!Object.create) Object.create = function object(o) {
|
|
function F() {};
|
|
F.prototype = o;
|
|
return new F();
|
|
};
|
|
|
|
// data
|
|
|
|
function Token(value, index, tag, length) {
|
|
this.value = value;
|
|
this.index = index;
|
|
this.length = length || value.length;
|
|
this.tag = tag;
|
|
this.secondary_tags = {};
|
|
}
|
|
|
|
// null_token exists so that LispNodes that have not had a closing tag attached
|
|
// can have a dummy token to simplify annotation
|
|
var null_token = new Token("", -1, "null", -1);
|
|
|
|
/* LispNodes are aggregate nodes for sexpressions.
|
|
*
|
|
*/
|
|
function LispNode(tag, children, opening) {
|
|
this.tag = tag; // current metadata for syntax inference
|
|
this.parent = null; // the parent expression
|
|
this.list = children; // all the child forms in order
|
|
this.opening = opening; // the token that opens this form.
|
|
this.closing = null_token; // the token that closes this form.
|
|
this.meta = null; // metadata nodes will be attached here if they are found
|
|
}
|
|
|
|
var null_lispnode = new LispNode("null", [], null_token);
|
|
|
|
|
|
function PrefixNode(tag, token, attached_node) {
|
|
this.tag = tag;
|
|
this.token = token;
|
|
this.attached_node = attached_node;
|
|
this.parent = null;
|
|
}
|
|
|
|
|
|
|
|
// tokenize
|
|
|
|
function tokenize(code) {
|
|
var tokens = [];
|
|
var tn = 0;
|
|
|
|
var zero = "0".charCodeAt(0);
|
|
var nine = "9".charCodeAt(0);
|
|
var lower_a = "a".charCodeAt(0);
|
|
var lower_f = "f".charCodeAt(0);
|
|
var upper_a = "A".charCodeAt(0);
|
|
var upper_f = "F".charCodeAt(0);
|
|
|
|
var dispatch = false; // have we just seen a # character?
|
|
|
|
// i tracks the start of the current window
|
|
// extent is the window for slicing
|
|
|
|
for (var i = 0,
|
|
extent = i,
|
|
j = code.length;
|
|
i < j && extent <= j;) {
|
|
|
|
var c = code[i];
|
|
|
|
// we care about capturing the whole token when dispatch is used, so back up the
|
|
// starting index by 1
|
|
if (dispatch) i--;
|
|
|
|
switch (c) {
|
|
// dispatch alters the value of the next thing read
|
|
case "#":
|
|
dispatch = true;
|
|
i++;
|
|
extent++;
|
|
continue;
|
|
|
|
case " ": // ignore whitespace
|
|
case "\t":
|
|
case "\n":
|
|
case "\r":
|
|
case ",":
|
|
extent++
|
|
break;
|
|
|
|
// simple terms
|
|
case "^":
|
|
case "`":
|
|
case ")":
|
|
case "[":
|
|
case "]":
|
|
case "}":
|
|
case "@":
|
|
tokens[tn++] = new Token(c, i, c, ++extent - i);
|
|
break;
|
|
|
|
case "'":
|
|
tokens[tn++] = new Token(code.slice(i, ++extent), i, dispatch ? "#'" : "'", extent - i);
|
|
break
|
|
|
|
case "(":
|
|
tokens[tn++] = new Token(code.slice(i, ++extent), i, "(", extent - i);
|
|
break;
|
|
|
|
case "{":
|
|
tokens[tn++] = new Token(code.slice(i, ++extent), i, dispatch ? "#{" : "{", extent - i);
|
|
break;
|
|
|
|
case "\\":
|
|
if (code.slice(i + 1, i + 8) === "newline") {
|
|
tokens[tn++] = new Token("\\newline", i, "value", 8);
|
|
extent = i + 9;
|
|
}
|
|
else if (code.slice(i + 1, i + 6) === "space") {
|
|
tokens[tn++] = new Token("\\space", i, "value", 6);
|
|
extent = i + 6;
|
|
}
|
|
else if (code.slice(i + 1, i + 4) === "tab") {
|
|
tokens[tn++] = new Token("\\tab", i, "value", 4);
|
|
extent = i + 5;
|
|
} // work around fun bug with &,>,< in character literals
|
|
else if (code.slice(i + 1, i + 6) === "&") {
|
|
tokens[tn++] = new Token("\\&", i, "value", 6);
|
|
extent = i + 6;
|
|
}
|
|
else if (code.slice(i + 1, i + 5) === "<") {
|
|
tokens[tn++] = new Token("\\<", i, "value", 5);
|
|
extent = i + 5;
|
|
}
|
|
else if (code.slice(i + 1, i + 5) === ">") {
|
|
tokens[tn++] = new Token("\\>", i, "value", 5);
|
|
extent = i + 5;
|
|
}
|
|
|
|
else {
|
|
extent += 2;
|
|
tokens[tn++] = new Token(code.slice(i, extent), i, "value", 2);
|
|
}
|
|
break;
|
|
|
|
case "~": // slice
|
|
if (code[i + 1] === "@") {
|
|
extent += 2;
|
|
tokens[tn++] = new Token(code.slice(i, extent), i, "splice", 2);
|
|
}
|
|
else {
|
|
tokens[tn++] = new Token(code.slice(i, ++extent), i, "unquote", 2);
|
|
}
|
|
break;
|
|
|
|
// complicated terms
|
|
case "\"": // strings and regexps
|
|
for (extent++; extent <= j; extent++) {
|
|
if (code[extent] === "\\") extent++;
|
|
else if (code[extent] === "\"") break;
|
|
}
|
|
tokens[tn++] = new Token(code.slice(i, ++extent), i, dispatch ? "regexp" : "string", extent - i);
|
|
break;
|
|
|
|
case ";":
|
|
for (; extent <= j && code[extent] !== "\n" && code[extent] !== "\r"; extent++);
|
|
tokens[tn++] = new Token(code.slice(i, ++extent), i, "comments", extent - i);
|
|
break;
|
|
|
|
case "+": // numbers; fall through to symbol for + and - not prefixing a number
|
|
case "-":
|
|
case "0":
|
|
case "1":
|
|
case "2":
|
|
case "3":
|
|
case "4":
|
|
case "5":
|
|
case "6":
|
|
case "7":
|
|
case "8":
|
|
case "9":
|
|
// todo: exponents, hex
|
|
// http://my.safaribooksonline.com/9781449310387/14?reader=pf&readerfullscreen=&readerleftmenu=1
|
|
var c2 = code.charCodeAt(i + 1);
|
|
if (((c === "+" || c === "-") && (c2 >= zero && c2 <= nine)) // prefixes
|
|
|| (c !== "+" && c !== "-")) {
|
|
if (c === "+" || c === "-") extent++;
|
|
for (; extent <= j; extent++) {
|
|
var charCode = code.charCodeAt(extent);
|
|
if (charCode < zero || charCode > nine) break;
|
|
}
|
|
|
|
c = code[extent];
|
|
c2 = code.charCodeAt(extent + 1);
|
|
if ((c === "r" || c === "R" || c === "/" || c === ".") // interstitial characters
|
|
&& (c2 >= zero && c2 <= nine)) {
|
|
for (extent++; extent <= j; extent++) {
|
|
var charCode = code.charCodeAt(extent);
|
|
if (charCode < zero || charCode > nine) break;
|
|
}
|
|
}
|
|
|
|
c = code[extent];
|
|
c2 = code.charCodeAt(extent + 1);
|
|
if ((c === "x" || c === "X") &&
|
|
((c2 >= zero && c2 <= nine)
|
|
|| (c2 >= lower_a && c2 <= lower_f)
|
|
|| (c2 >= upper_a && c2 <= upper_f))) {
|
|
for (extent++; extent <= j; extent++) {
|
|
var charCode = code.charCodeAt(extent);
|
|
if (((charCode >= zero && charCode <= nine)
|
|
|| (charCode >= lower_a && charCode <= lower_f)
|
|
|| (charCode >= upper_a && charCode <= upper_f))) continue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
c = code[extent];
|
|
c2 = code.charCodeAt(extent + 1);
|
|
if ((c === "e" || c === "E")
|
|
&& (c2 >= zero && c2 <= nine)) {
|
|
for (extent++; extent <= j; extent++) {
|
|
var charCode = code.charCodeAt(extent);
|
|
if (charCode < zero || charCode > nine) break;
|
|
}
|
|
}
|
|
|
|
c = code[extent];
|
|
if (c === "N" || c === "M") extent++;
|
|
|
|
tokens[tn++] = new Token(code.slice(i, extent), i, "value", extent - i);
|
|
break;
|
|
}
|
|
|
|
case "_":
|
|
if (dispatch && c === "_") {
|
|
tokens[tn++] = new Token(code.slice(i, ++extent), i, "skip", extent - i);
|
|
break;
|
|
} // if not a skip, fall through to symbols
|
|
|
|
// Allow just about any other symbol as a symbol. This is far more permissive than
|
|
// clojure actually allows, but should catch any weirdo crap that accidentally gets
|
|
// into the code.
|
|
default:
|
|
for (extent++; extent <= j; extent++) {
|
|
switch (code[extent]) {
|
|
case " ":
|
|
case "\t":
|
|
case "\n":
|
|
case "\r":
|
|
case "\\":
|
|
case ",":
|
|
case "{":
|
|
case "}":
|
|
case "(":
|
|
case ")":
|
|
case "[":
|
|
case "]":
|
|
case "^":
|
|
case "`":
|
|
case "@":
|
|
break;
|
|
case ";":
|
|
// theres a weird bug via syntax highligher that gives us escaped entities.
|
|
// need to watch out for these
|
|
if (code.slice(extent-3, extent+1) === "<"
|
|
||code.slice(extent-3, extent+1) === ">"
|
|
||code.slice(extent-4, extent+1) === "&") {
|
|
continue;
|
|
}
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
var value = code.slice(i, extent);
|
|
var tag = "symbol";
|
|
if (value[0] == ":") {
|
|
tag = "keyword";
|
|
}
|
|
else if (value === "true" || value === "false" || value === "nil") {
|
|
tag = "value";
|
|
}
|
|
tokens[tn++] = new Token(value, i, tag, extent - i);
|
|
}
|
|
|
|
dispatch = false;
|
|
i = extent;
|
|
}
|
|
|
|
return tokens;
|
|
}
|
|
|
|
|
|
function build_tree(tokens) {
|
|
var toplevel = {
|
|
list: [],
|
|
tag: "toplevel",
|
|
parent: null,
|
|
opening: null,
|
|
closing: null,
|
|
depth: -1
|
|
};
|
|
|
|
// loop variables hoisted out as semi globals to track position in token stream
|
|
var i = -1;
|
|
var j = tokens.length;
|
|
|
|
function parse_one(t) {
|
|
// ignore special tokens and forms that dont belong in the tree
|
|
for (; t && (t.tag === "comments" || t.tag === "invalid" || t.tag == "skip") && i < j; ) {
|
|
if (t.tag === "skip") {
|
|
t.tag = "preprocessor";
|
|
annotate_comment(parse_one(tokens[++i]));
|
|
}
|
|
t = tokens[++i];
|
|
}
|
|
|
|
if (!t) return {}; // hackity hack
|
|
|
|
switch (t.tag) {
|
|
case "{":
|
|
return build_aggregate(new LispNode("map", [], t), "}");
|
|
case "(":
|
|
return build_aggregate(new LispNode("list", [], t), ")");
|
|
case "#{":
|
|
return build_aggregate(new LispNode("set", [], t), "}");
|
|
case "[":
|
|
return build_aggregate(new LispNode("vector", [], t), "]");
|
|
case "'":
|
|
return new PrefixNode("quote", t, parse_one(tokens[++i]));
|
|
case "#'":
|
|
return new PrefixNode("varquote", t, parse_one(tokens[++i]));
|
|
case "@":
|
|
return new PrefixNode("deref", t, parse_one(tokens[++i]));
|
|
case "`":
|
|
return new PrefixNode("quasiquote", t, parse_one(tokens[++i]));
|
|
case "unquote":
|
|
return new PrefixNode("unquote", t, parse_one(tokens[++i]));
|
|
case "splice":
|
|
return new PrefixNode("splice", t, parse_one(tokens[++i]));
|
|
case "^":
|
|
t.tag = "meta";
|
|
var meta = parse_one(tokens[++i]);
|
|
var next = parse_one(tokens[++i]);
|
|
next.meta = meta;
|
|
return next;
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
// build_aggregate collects to ether sub forms for one aggregate for.
|
|
function build_aggregate(current, expected_closing) {
|
|
for (i++; i < j; i++) {
|
|
var t = tokens[i];
|
|
|
|
if (t.tag === "}" || t.tag === ")" || t.tag === "]") {
|
|
if (t.tag !== expected_closing) t.tag = "invalid";
|
|
current.closing = t;
|
|
if (expected_closing) return current;
|
|
}
|
|
var node = parse_one(t);
|
|
|
|
node.parent = current;
|
|
current.list[current.list.length] = node;
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
build_aggregate(toplevel, null);
|
|
|
|
return toplevel;
|
|
}
|
|
|
|
// annotation rules to apply to a form based on its head
|
|
|
|
var show_locals = true; // HACK. would rather not use a (semi)-global.
|
|
|
|
/* annotate_comment is a special case annotation.
|
|
* in addition to its role in styling specific forms, it is called by parse_one to
|
|
* ignore any forms skipped with #_
|
|
*/
|
|
function annotate_comment(exp) {
|
|
exp.tag = "comments";
|
|
|
|
if (exp.list) {
|
|
exp.opening.tag = "comments";
|
|
exp.closing.tag = "comments";
|
|
|
|
for (var i = 0; i < exp.list.length; i++) {
|
|
var child = exp.list[i];
|
|
if (child.list) {
|
|
annotate_comment(child);
|
|
}
|
|
if (child.attached_node) {
|
|
annotate_comment(child.attached_node);
|
|
}
|
|
else {
|
|
child.tag = "comments";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* custom annotation rules are stored here */
|
|
var annotation_rules = {};
|
|
|
|
// this function is exposed to allow ad hoc extension of the customisation rules
|
|
function register_annotation_rule(names, rule) {
|
|
for (var i = 0; i < names.length; i++) {
|
|
annotation_rules[names[i]] = rule;
|
|
}
|
|
}
|
|
|
|
|
|
function annotate_destructuring (exp, scope) {
|
|
if (exp.list) {
|
|
if (exp.tag === "vector") {
|
|
for (var i = 0; i < exp.list.length; i++) {
|
|
annotate_destructuring(exp.list[i], scope);
|
|
}
|
|
}
|
|
else if (exp.tag === "map") {
|
|
for (var i = 0; i < exp.list.length; i += 2) {
|
|
var key = exp.list[i];
|
|
var val = exp.list[i + 1];
|
|
|
|
if (key.tag === "keyword" && val.tag === "vector") {
|
|
for (var ii = 0, jj = val.list.length; ii < jj; ii++) {
|
|
if (val.list[ii].tag !== "symbol") continue;
|
|
val.list[ii].tag = "variable";
|
|
scope[val.list[ii].value] = true;
|
|
}
|
|
}
|
|
else {
|
|
annotate_destructuring(key, scope);
|
|
annotate_expressions(val, scope);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (exp.tag === "symbol" && (exp.value !== "&" && exp.value !== "&")){
|
|
exp.tag = "variable";
|
|
scope[exp.value] = true;
|
|
}
|
|
}
|
|
|
|
function _annotate_binding_vector (exp, scope) {
|
|
if (exp.tag !== "vector") return;
|
|
|
|
var bindings = exp.list;
|
|
|
|
if (bindings.length % 2 === 1) return;
|
|
|
|
for (var i = 0; i < bindings.length; i += 2) {
|
|
annotate_destructuring(bindings[i], scope);
|
|
annotate_expressions(bindings[i + 1], scope);
|
|
}
|
|
}
|
|
|
|
function annotate_binding (exp, scope) {
|
|
var bindings = exp.list[1];
|
|
if (!show_locals) return; // HACK
|
|
|
|
if (bindings) {
|
|
scope = Object.create(scope);
|
|
_annotate_binding_vector(bindings, scope);
|
|
}
|
|
for (var i = 2; i < exp.list.length; i++) {
|
|
annotate_expressions(exp.list[i], scope);
|
|
}
|
|
}
|
|
|
|
function _annotate_function_body (exp, scope, start_idx) {
|
|
var argvec = exp.list[start_idx];
|
|
if (argvec.tag !== "vector") return;
|
|
|
|
scope = Object.create(scope);
|
|
|
|
for (var i = 0, j = argvec.list.length; i < j; i++) {
|
|
annotate_destructuring(argvec.list[i], scope);
|
|
}
|
|
|
|
for (var i = start_idx, j = exp.list.length; i < j; i++) {
|
|
annotate_expressions(exp.list[i], scope);
|
|
}
|
|
}
|
|
|
|
function annotate_function (exp, scope) {
|
|
for (var i = 1, j = exp.list.length; i < j; i++) {
|
|
var child = exp.list[i];
|
|
|
|
if (child.tag === "vector") {
|
|
_annotate_function_body (exp, scope, i);
|
|
return;
|
|
}
|
|
else if (child.tag === "list") {
|
|
_annotate_function_body(child, scope, 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
function annotate_letfn (exp, scope) {
|
|
scope = Object.create(scope);
|
|
var bindings = exp.list[1];
|
|
|
|
var fn;
|
|
for (var i = 0, j = bindings.list.length; i < j; i++) {
|
|
fn = bindings.list[i];
|
|
if (!fn.list[0]) continue;
|
|
fn.list[0].tag = "variable";
|
|
scope[fn.list[0].value] = true;
|
|
}
|
|
|
|
for (i = 0, j = bindings.list.length; i < j; i++) {
|
|
var fn = bindings.list[i];
|
|
annotate_function(fn, scope);
|
|
}
|
|
|
|
for (i = 2, j = exp.list.length; i < j; i++) {
|
|
annotate_expressions(exp.list[i], scope);
|
|
}
|
|
}
|
|
|
|
register_annotation_rule(
|
|
["comment"],
|
|
annotate_comment
|
|
);
|
|
|
|
register_annotation_rule(
|
|
["let", "when-let", "if-let", "binding", "doseq", "for", "dotimes", "let*"],
|
|
annotate_binding
|
|
);
|
|
|
|
register_annotation_rule(
|
|
["defn", "defn-", "fn", "bound-fn", "defmacro", "fn*", "defmethod"],
|
|
annotate_function
|
|
);
|
|
|
|
register_annotation_rule(
|
|
["letfn"],
|
|
annotate_letfn
|
|
);
|
|
|
|
// standard annotations
|
|
|
|
function _annotate_metadata_recursive(meta, scope) {
|
|
if (!meta) return;
|
|
|
|
if (meta.list !== undefined && meta.list !== null) {
|
|
for (var i = 0, j = meta.list.length; i < j; i++) {
|
|
meta.opening.secondary_tags.meta = true
|
|
meta.closing.secondary_tags.meta = true
|
|
_annotate_metadata_recursive(meta.list[i], scope);
|
|
}
|
|
}
|
|
else if (meta.attached_node) {
|
|
meta.token.secondary_tags.meta = true;
|
|
_annotate_metadata_recursive(meta.attached_node, scope);
|
|
}
|
|
else {
|
|
meta.secondary_tags.meta = true;
|
|
}
|
|
}
|
|
|
|
function annotate_metadata(exp) {
|
|
if (!(exp && exp.meta)) return;
|
|
var meta = exp.meta;
|
|
|
|
annotate_expressions(meta, {});
|
|
_annotate_metadata_recursive(meta, {});
|
|
}
|
|
|
|
|
|
function annotate_quoted(exp, scope) {
|
|
if (!exp) return;
|
|
|
|
if (exp.list !== undefined && exp.list !== null) {
|
|
for (var i = 0, j = exp.list.length; i < j; i++) {
|
|
exp.opening.secondary_tags.quoted = true
|
|
exp.closing.secondary_tags.quoted = true
|
|
annotate_quoted(exp.list[i], scope);
|
|
}
|
|
}
|
|
else if (exp.attached_node) {
|
|
if (exp.tag === "unquote" || exp.tag === "splice") return;
|
|
exp.token.secondary_tags.quoted = true;
|
|
annotate_quoted(exp.attached_node, scope);
|
|
}
|
|
else {
|
|
exp.secondary_tags.quoted = true;
|
|
}
|
|
}
|
|
|
|
|
|
function annotate_expressions(exp, scope) {
|
|
annotate_metadata(exp);
|
|
|
|
switch (exp.tag) {
|
|
case "toplevel":
|
|
for (var i = 0; i < exp.list.length; i++) {
|
|
annotate_expressions(exp.list[i], scope);
|
|
}
|
|
break;
|
|
|
|
case "list": // functions, macros, special forms, comments
|
|
var head = exp.list[0];
|
|
|
|
if (head) {
|
|
if (head.tag === "list" || head.tag === "vector"
|
|
|| head.tag === "map" || head.tag === "set") {
|
|
annotate_expressions(head, scope);
|
|
}
|
|
else if (head.attached_node) {
|
|
annotate_expressions(head.attached_node, scope);
|
|
}
|
|
else {
|
|
head.tag = (head.value.match(/(^\.)|(\.$)|[A-Z].*\//)
|
|
? "method"
|
|
: "function");
|
|
}
|
|
|
|
// apply specific rules
|
|
if (annotation_rules.hasOwnProperty(head.value)) {
|
|
annotation_rules[head.value](exp, scope);
|
|
}
|
|
else {
|
|
for (var i = 1; i < exp.list.length; i++) {
|
|
annotate_expressions(exp.list[i], scope);
|
|
}
|
|
}
|
|
}
|
|
else { // empty list
|
|
exp.opening.tag = "value";
|
|
exp.closing.tag = "value";
|
|
}
|
|
|
|
break;
|
|
|
|
case "vector": // data
|
|
case "map":
|
|
case "set":
|
|
for (var i = 0; i < exp.list.length; i++) {
|
|
annotate_expressions(exp.list[i], scope);
|
|
}
|
|
break;
|
|
|
|
case "symbol":
|
|
if (exp.value.match(/[A-Z].*\/[A-Z_]+/)) {
|
|
exp.tag = "constant";
|
|
}
|
|
else if (show_locals && scope[exp.value]) {
|
|
exp.tag = "variable";
|
|
}
|
|
else if (exp.tag === "symbol" && exp.value.match(/([A-Z].*\/)?[A-Z_]+/)) {
|
|
exp.tag = "type";
|
|
}
|
|
break;
|
|
|
|
case "quote":
|
|
case "quasiquote":
|
|
annotate_quoted(exp.attached_node, scope);
|
|
|
|
default:
|
|
if (exp.attached_node) annotate_expressions(exp.attached_node, scope);
|
|
}
|
|
}
|
|
|
|
// translation of tag to css:
|
|
var css_translation = {
|
|
"constant": "constants",
|
|
"keyword": "constants",
|
|
"method": "color1",
|
|
"type": "color3",
|
|
"function": "functions",
|
|
"string": "string",
|
|
"regexp": "string",
|
|
"value": "value",
|
|
"comments": "comments",
|
|
"symbol": "symbol",
|
|
"variable": "variable",
|
|
"splice": "preprocessor",
|
|
"unquote": "preprocessor",
|
|
"preprocessor": "preprocessor",
|
|
"meta": "preprocessor",
|
|
"'": "preprocessor",
|
|
"#'": "preprocessor",
|
|
"(": "plain",
|
|
")": "plain",
|
|
"{": "keyword",
|
|
"}": "keyword",
|
|
"#{": "keyword",
|
|
"[": "keyword",
|
|
"]": "keyword",
|
|
"invalid": "invalid",
|
|
"@": "plain"
|
|
};
|
|
|
|
function translate_tags_to_css(tokens) {
|
|
for (var i = 0, j = tokens.length; i < j; i++) {
|
|
var token = tokens[i];
|
|
token.css = css_translation[token.tag];
|
|
for (var k in token.secondary_tags) if (token.secondary_tags.hasOwnProperty(k))
|
|
token.css += " " + k ;
|
|
};
|
|
}
|
|
|
|
|
|
// create the new brush
|
|
|
|
SH.brushes.Clojure = function () {};
|
|
SH.brushes.Clojure.prototype = new SyntaxHighlighter.Highlighter();
|
|
|
|
SH.brushes.Clojure.prototype.findMatches = function find_matches (regexpList, code) {
|
|
// this is a nasty global hack. need to resolve this
|
|
if (this.params && this.params.locals) {
|
|
show_locals = this.params.locals === true || this.params.locals === "true";
|
|
}
|
|
else {
|
|
show_locals = true;
|
|
}
|
|
|
|
var tokens = tokenize(code);
|
|
annotate_expressions(build_tree(tokens), {});
|
|
translate_tags_to_css(tokens);
|
|
|
|
return tokens;
|
|
};
|
|
|
|
SH.brushes.Clojure.aliases = ['clojure', 'Clojure', 'clj'];
|
|
SH.brushes.Clojure.register_annotation_rule = register_annotation_rule;
|
|
|
|
return {
|
|
tokenize: tokenize,
|
|
build_tree: build_tree
|
|
};
|
|
})(SyntaxHighlighter);
|
|
</script><title>mw-parser -- Marginalia</title></head><body><table><tr><td class="docs"><div class="header"><h1 class="project-name"><a href="http://www.journeyman.cc/microworld">mw-parser</a></h1><h2 class="project-version">0.2.0-SNAPSHOT</h2><br /><p>Parser for production rules for MicroWorld engine</p>
|
|
</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.11.1</td></tr><tr><td class="dep-name">org.clojure/tools.trace</td><td class="dotted"><hr /></td><td class="dep-version">0.7.11</td></tr><tr><td class="dep-name">instaparse</td><td class="dotted"><hr /></td><td class="dep-version">1.4.12</td></tr><tr><td class="dep-name">mw-engine</td><td class="dotted"><hr /></td><td class="dep-version">0.2.0-SNAPSHOT</td></tr><tr><td class="dep-name">trptr/java-wrapper</td><td class="dotted"><hr /></td><td class="dep-version">0.2.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="#mw-parser.simplify">mw-parser.simplify</a></li><li><a href="#mw-parser.bulk">mw-parser.bulk</a></li><li><a href="#mw-parser.utils">mw-parser.utils</a></li><li><a href="#mw-parser.flow">mw-parser.flow</a></li><li><a href="#mw-parser.core">mw-parser.core</a></li><li><a href="#mw-parser.errors">mw-parser.errors</a></li><li><a href="#mw-parser.generate">mw-parser.generate</a></li><li><a href="#mw-parser.declarative">mw-parser.declarative</a></li></ul></div></td><td class="codes"> </td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-parser.simplify" name="mw-parser.simplify"><h1 class="project-name">mw-parser.simplify</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>Simplify a parse tree.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.simplify)</pre></td></tr><tr><td class="docs"><p>mw-parser: a rule parser for MicroWorld.</p>
|
|
|
|
<p>This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.</p>
|
|
|
|
<p>This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.</p>
|
|
|
|
<p>You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
USA.</p>
|
|
|
|
<p>Copyright (C) 2014 Simon Brooke</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(declare simplify)</pre></td></tr><tr><td class="docs"><p>There are a number of possible simplifications such that if the <code>tree</code> has
|
|
only two elements, the second is semantically sufficient.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn simplify-second-of-two
|
|
[tree]
|
|
(if (= (count tree) 2) (simplify (nth tree 1)) tree))</pre></td></tr><tr><td class="docs"><p>Some parse trees take the form
|
|
<code>[:X [:Y 1] :NOISE :NOISE [:X [:Y 2] :NOISE :NOISE [:X [:Y 3]]]]</code>
|
|
where what's wanted is <code>[:X [:Y 1] [:Y 2] [:Y 2]]</code> -- :DISJUNCT-VALUE is a case
|
|
in point. This takes such a parse <code>tree</code>, where <code>branch-tag</code> is the tag of
|
|
the enclosing form and <code>leaf-tag</code> is the tag of the form to be collected, and
|
|
returns the desired form.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn simplify-chained-list
|
|
[tree branch-tag leaf-tag]
|
|
(cons
|
|
(first tree)
|
|
(reverse
|
|
(loop [chain (rest tree) v '()]
|
|
(let [car (first chain)]
|
|
(cond (empty? chain) v
|
|
(coll? car) (let [caar (first car)]
|
|
(cond
|
|
(= branch-tag caar) (recur car v)
|
|
(= leaf-tag caar) (recur
|
|
(rest chain)
|
|
(cons (simplify car) v))
|
|
:else (recur (rest chain) v)))
|
|
:else (recur (rest chain) v)))))))</pre></td></tr><tr><td class="docs"><p>Simplify/canonicalise this <code>tree</code>. Opportunistically replace complex fragments with
|
|
semantically identical simpler fragments</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn simplify
|
|
[tree]
|
|
(if
|
|
(coll? tree)
|
|
(case (first tree)
|
|
:ACTION (simplify-second-of-two tree)
|
|
:ACTIONS (cons (first tree) (simplify (rest tree)))
|
|
:AND nil
|
|
:CHANCE-IN nil
|
|
:COMPARATIVE (simplify-second-of-two tree)
|
|
:CONDITION (simplify-second-of-two tree)
|
|
:CONDITIONS (simplify-second-of-two tree)
|
|
:DISJUNCT-EXPRESSION (simplify-chained-list tree :DISJUNCT-VALUE :VALUE)
|
|
:EXPRESSION (simplify-second-of-two tree)
|
|
:IN nil
|
|
:PROPERTY (simplify-second-of-two tree)
|
|
:PROPERTY-CONDITION-OR-EXPRESSION (simplify-second-of-two tree)
|
|
:OR nil
|
|
:SPACE nil
|
|
:THEN nil
|
|
:VALUE (simplify-second-of-two tree)
|
|
(remove nil? (map simplify tree)))
|
|
tree))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn simplify-determiner-condition
|
|
[tree]
|
|
(apply vector
|
|
(cons :DETERMINER-CONDITION
|
|
(cons
|
|
(simplify-second-of-two (second tree))
|
|
(rest (rest tree))))))</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="#mw-parser.bulk" name="mw-parser.bulk"><h1 class="project-name">mw-parser.bulk</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>parse multiple rules from a stream, possibly a file.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.bulk
|
|
(:use mw-parser.core
|
|
mw-engine.utils
|
|
clojure.java.io
|
|
[clojure.string :only [split trim]])
|
|
(:import (java.io BufferedReader StringReader)))</pre></td></tr><tr><td class="docs"><p>mw-parser: a rule parser for MicroWorld.</p>
|
|
|
|
<p>This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.</p>
|
|
|
|
<p>This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.</p>
|
|
|
|
<p>You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
USA.</p>
|
|
|
|
<p>Copyright (C) 2014 Simon Brooke</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Is this <code>line</code> a comment?</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn comment?
|
|
[line]
|
|
(or (empty? (trim line)) (member? (first line) '(nil \# \;))))</pre></td></tr><tr><td class="docs"><p>Parse rules from successive lines in this <code>string</code>, assumed to have multiple
|
|
lines delimited by the new-line character. Return a list of S-expressions.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-string
|
|
[string]
|
|
;; TODO: tried to do this using with-open, but couldn't make it work.
|
|
(map #(parse-rule (trim %)) (remove comment? (split string #"\n"))))</pre></td></tr><tr><td class="docs"><p>Parse rules from successive lines in the file loaded from this <code>filename</code>.
|
|
Return a list of S-expressions.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-file
|
|
[filename]
|
|
(parse-string (slurp filename)))</pre></td></tr><tr><td class="docs"><p>Compile each non-comment line of this <code>string</code> into an executable anonymous
|
|
function, and return the sequence of such functions.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn compile-string
|
|
[string]
|
|
(map #(compile-rule % true) (remove comment? (split string #"\n"))))</pre></td></tr><tr><td class="docs"><p>Compile each non-comment line of the file indicated by this <code>filename</code> into
|
|
an executable anonymous function, and return the sequence of such functions.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn compile-file
|
|
[filename]
|
|
(compile-string (slurp filename)))</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="#mw-parser.utils" name="mw-parser.utils"><h1 class="project-name">mw-parser.utils</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>Utilities used in more than one namespace within the parser.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.utils)</pre></td></tr><tr><td class="docs"><p>mw-parser: a rule parser for MicroWorld.</p>
|
|
|
|
<p>This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.</p>
|
|
|
|
<p>This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.</p>
|
|
|
|
<p>You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
USA.</p>
|
|
|
|
<p>Copyright (C) 2014 Simon Brooke</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Return <code>true</code> if <code>tree-fragment</code> appears to be a tree fragment of the expected <code>type</code>.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn suitable-fragment?
|
|
[tree-fragment type]
|
|
(and (coll? tree-fragment)
|
|
(keyword? type)
|
|
(= (first tree-fragment) type)))</pre></td></tr><tr><td class="docs"><p>Return true if the argument appears to be a parsed rule tree, else false.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn rule?
|
|
[maybe-rule]
|
|
(suitable-fragment? maybe-rule :RULE))</pre></td></tr><tr><td class="docs"><p>Marker to indicate I'm not yet finished!</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn TODO
|
|
[message]
|
|
message)</pre></td></tr><tr><td class="docs"><p>If <code>tree-fragment</code> is not a tree fragment of the expected <code>type</code>, throw an exception.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn assert-type
|
|
[tree-fragment type]
|
|
(assert (suitable-fragment? tree-fragment type)
|
|
(throw (Exception. (format "Expected a %s fragment" type)))))</pre></td></tr><tr><td class="docs"><p>Return the first element of this tree which has this tag in a depth-first, left-to-right search</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn search-tree
|
|
[tree tag]
|
|
(cond
|
|
(= (first tree) tag) tree
|
|
:else (first
|
|
(remove nil?
|
|
(map
|
|
#(search-tree % tag)
|
|
(filter coll? (rest tree)))))))</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="#mw-parser.flow" name="mw-parser.flow"><h1 class="project-name">mw-parser.flow</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>A very simple parser which parses flow rules.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.flow
|
|
(:require [clojure.string :refer [join]]
|
|
[mw-parser.declarative :refer [build-parser]]
|
|
[mw-parser.simplify :refer [simplify-second-of-two]]))</pre></td></tr><tr><td class="docs"><p>Grammar for flow rules.</p>
|
|
|
|
<p> My initial conception of this would be that production rules
|
|
(if-then rules) and flow rules (flow-from-to rules) would be
|
|
entirely separate, presented to the parser as separate text
|
|
files, and parsed and compiled by different chains of functions.</p>
|
|
|
|
<p> This appears not to be necessary. Flow rules are easy to parse
|
|
with the same parser as production rules -- a lot of the grammar
|
|
is intentionally common -- and the rules are easily discriminated
|
|
at the compilation ('generate') stage.</p>
|
|
|
|
<p> The basic rule I want to be able to compile at this stage is the 'mutual
|
|
aid' rule:</p>
|
|
|
|
<p> <code>flow 1 food from house having food > 1 to house with least food within 2</code></p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def flow-grammar
|
|
(join "\n" ["FLOW-RULE := FLOW SPACE QUANTITY SPACE PROPERTY SPACE FROM SPACE SOURCE SPACE TO-HOW SPACE DESTINATION;"
|
|
"PERCENTAGE := NUMBER #'%';"
|
|
"QUANTITY := PERCENTAGE | NUMBER | EXPRESSION | SOME;"
|
|
"SOURCE := STATE | STATE SPACE WITH SPACE CONDITIONS;"
|
|
"DESTINATION := STATE | STATE SPACE WITH SPACE FLOW-CONDITIONS | STATE SPACE WITHIN SPACE VALUE SPACE WITH SPACE FLOW-CONDITIONS;"
|
|
"DETERMINER := MOST | LEAST;"
|
|
"DETERMINER-CONDITION := DETERMINER SPACE PROPERTY | DETERMINER SPACE PROPERTY;"
|
|
"FLOW-CONDITIONS := DETERMINER-CONDITION | CONDITIONS"
|
|
"STATE := SYMBOL;"
|
|
"TO-HOW := TO | TO-EACH | TO-FIRST;"
|
|
"TO-EACH := TO SPACE EACH | TO SPACE ALL;"
|
|
"TO-FIRST := TO SPACE FIRST"]))</pre></td></tr><tr><td class="docs"><p>Parse the argument, assumed to be a string in the correct syntax, and return a parse tree.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def parse-flow
|
|
(build-parser flow-grammar))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn simplify-flow
|
|
[tree]
|
|
(if (coll? tree)
|
|
(case (first tree)
|
|
:CONDITION (simplify-second-of-two tree)
|
|
:CONDITIONS (simplify-second-of-two tree)
|
|
:DETERMINER (simplify-second-of-two tree)
|
|
;; :DETERMINER-CONDITION (simplify-determiner-condition tree)
|
|
:EXPRESSION (simplify-second-of-two tree)
|
|
:FLOW nil
|
|
;; :FLOW-CONDITIONS (simplify-second-of-two tree)
|
|
:PROPERTY (simplify-second-of-two tree)
|
|
:PROPERTY-CONDITION-OR-EXPRESSION (simplify-second-of-two tree)
|
|
:SPACE nil
|
|
:QUANTITY (simplify-second-of-two tree)
|
|
:STATE (list :PROPERTY-CONDITION
|
|
(list :SYMBOL "state")
|
|
'(:QUALIFIER
|
|
(:EQUIVALENCE
|
|
(:IS "is")))
|
|
(list :EXPRESSION
|
|
(list :VALUE (second tree))))
|
|
(remove nil? (map simplify-flow tree)))
|
|
tree))</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="#mw-parser.core" name="mw-parser.core"><h1 class="project-name">mw-parser.core</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>A very simple parser which parses production rules.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.core
|
|
(:use mw-engine.utils
|
|
[clojure.string :only [split trim triml]])
|
|
(:gen-class))</pre></td></tr><tr><td class="docs"><p>mw-parser: a rule parser for MicroWorld.</p>
|
|
|
|
<p>This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.</p>
|
|
|
|
<p>This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.</p>
|
|
|
|
<p>You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
USA.</p>
|
|
|
|
<p>Copyright (C) 2014 Simon Brooke</p>
|
|
|
|
<p>A very simple parser which parses production rules of the following forms:</p>
|
|
|
|
<ul>
|
|
<li>"if altitude is less than 100 and state is forest then state should be climax and deer should be 3"</li>
|
|
<li>"if altitude is 100 or fertility is 25 then state should be heath and fertility should be 24.3"</li>
|
|
<li>"if altitude is 100 or fertility is 25 then state should be heath"</li>
|
|
<li>"if deer is more than 2 and wolves is 0 and fertility is more than 20 then deer should be deer + 2"</li>
|
|
<li>"if deer is more than 1 and wolves is more than 1 then deer should be deer - wolves"</li>
|
|
<li>"if state is grassland and 4 neighbours have state equal to water then state should be village"</li>
|
|
<li>"if state is forest and fertility is between 55 and 75 then state should be climax"</li>
|
|
<li>"if 6 neighbours have state equal to water then state should be village"</li>
|
|
<li>"if state is in grassland or pasture or heath and 4 neighbours are water then state should be village"</li>
|
|
<li>"if state is forest or state is climax and some neighbours have state equal to fire then 3 in 5 chance that state should be fire"</li>
|
|
<li>"if state is pasture and more than 3 neighbours have state equal to scrub then state should be scrub"
|
|
*</li>
|
|
</ul>
|
|
|
|
<p>it generates rules in the form expected by <code>mw-engine.core</code>, q.v.</p>
|
|
|
|
<p>It is, as I say, very simple; it generates a complete rule, or it fails completely, returning nil.
|
|
Very occasionally it generates a wrong rule - one which is not a correct translation of the rule
|
|
semantics - but that is buggy behaviour, which I'll try to fix over the next few weeks, not a
|
|
design fault.</p>
|
|
|
|
<p>More significantly it does not generate useful error messages on failure.</p>
|
|
|
|
<p>This parser is now obsolete, but is retained in the codebase for now in
|
|
case it is of use to anyone. Prefer the declarative.clj parser.</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(declare parse-conditions)
|
|
(declare parse-not-condition)
|
|
(declare parse-simple-condition)</pre></td></tr><tr><td class="docs"><p>a regular expression which matches string representation of positive numbers</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def re-number #"^[0-9.]*$")</pre></td></tr><tr><td class="docs"><p>error thrown when an attempt is made to set a reserved property</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def reserved-properties-error
|
|
"The properties 'x' and 'y' of a cell are reserved and should not be set in rule actions")</pre></td></tr><tr><td class="docs"><p>error thrown when a rule cannot be parsed</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def bad-parse-error "I did not understand '%s'")</pre></td></tr><tr><td class="docs"><p>If this token appears to represent an explicit number, return that number;
|
|
otherwise, make a keyword of it and return that.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- keyword-or-numeric
|
|
[token]
|
|
(cond
|
|
(re-matches re-number token) (read-string token)
|
|
(keyword? token) token
|
|
true (keyword token)))</pre></td></tr><tr><td class="docs"><p>Generally all functions in this file with names beginning 'parse-' take a
|
|
sequence of tokens (and in some cases other optional arguments) and return a
|
|
vector comprising</p>
|
|
|
|
<ol>
|
|
<li>A code fragment parsed from the front of the sequence of tokens, and</li>
|
|
<li>the remaining tokens which were not consumed in constructing that fragment.</li>
|
|
</ol>
|
|
|
|
<p>In every case if the function cannot parse the desired construct from the
|
|
front of the sequence of tokens it returns nil.</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Parse a number.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-numeric-value
|
|
[[value & remainder]]
|
|
(if (and value (re-matches re-number value)) [(read-string value) remainder]))</pre></td></tr><tr><td class="docs"><p>Parse a token assumed to be the name of a property of the current cell,
|
|
whose value is assumed to be an integer.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-property-int
|
|
[[value & remainder]]
|
|
(if value [(list 'get-int 'cell (keyword value)) remainder]))</pre></td></tr><tr><td class="docs"><p>Parse a token assumed to be the name of a property of the current cell.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-property-value
|
|
[[value & remainder]]
|
|
(if value [(list (keyword value) 'cell) remainder]))</pre></td></tr><tr><td class="docs"><p>Parse a token assumed to be a simple token value.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-token-value
|
|
[[value & remainder]]
|
|
(if value [(keyword value) remainder]))</pre></td></tr><tr><td class="docs"><p>Parse a value from the first of these <code>tokens</code>. If <code>expect-int</code> is true, return
|
|
an integer or something which will evaluate to an integer.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-simple-value
|
|
([tokens expect-int]
|
|
(or
|
|
(parse-numeric-value tokens)
|
|
(cond expect-int
|
|
(parse-property-int tokens)
|
|
true (parse-token-value tokens))))
|
|
([tokens]
|
|
(parse-simple-value tokens false)))</pre></td></tr><tr><td class="docs"><p>Parse a single value from this single token and return just the generated
|
|
code, not a pair.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn gen-token-value
|
|
[token expect-int]
|
|
(first (parse-simple-value (list token) expect-int)))</pre></td></tr><tr><td class="docs"><p>Parse a list of values from among these <code>tokens</code>. If <code>expect-int</code> is true, return
|
|
integers or things which will evaluate to integers.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-disjunct-value
|
|
[[OR token & tokens] expect-int]
|
|
(cond (member? OR '("or" "in"))
|
|
(let [value (first (parse-simple-value (list token) expect-int))
|
|
seek-others (= (first tokens) "or")]
|
|
(cond seek-others
|
|
(let [[others remainder] (parse-disjunct-value tokens expect-int)]
|
|
[(cons value others) remainder])
|
|
true
|
|
[(list value) tokens]))))</pre></td></tr><tr><td class="docs"><p>Parse a value from among these <code>tokens</code>. If <code>expect-int</code> is true, return
|
|
an integer or something which will evaluate to an integer.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-value
|
|
([tokens expect-int]
|
|
(or
|
|
(parse-disjunct-value tokens expect-int)
|
|
(parse-simple-value tokens expect-int)))
|
|
([tokens]
|
|
(parse-value tokens false)))</pre></td></tr><tr><td class="docs"><p>Parses a condition of the form '[property] in [value] or [value]...'</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-member-condition
|
|
[[property IS IN & rest]]
|
|
(if (and (member? IS '("is" "are")) (= IN "in"))
|
|
(let [[l remainder] (parse-disjunct-value (cons "in" rest) false)]
|
|
[(list 'member? (list (keyword property) 'cell) (list 'quote l)) remainder])))</pre></td></tr><tr><td class="docs"><p>Parse '[property] less than [value]'.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-less-condition
|
|
[[property IS LESS THAN & rest]]
|
|
(cond (and (member? IS '("is" "are")) (member? LESS '("less" "fewer")) (= THAN "than"))
|
|
(let [[value remainder] (parse-value rest true)]
|
|
[(list '< (list 'get-int 'cell (keyword property)) value) remainder])))</pre></td></tr><tr><td class="docs"><p>Parse '[property] more than [value]'.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-more-condition
|
|
[[property IS MORE THAN & rest]]
|
|
(cond (and (member? IS '("is" "are")) (member? MORE '("more" "greater")) (= THAN "than"))
|
|
(let [[value remainder] (parse-value rest true)]
|
|
[(list '> (list 'get-int 'cell (keyword property)) value) remainder])))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-between-condition
|
|
[[p IS BETWEEN v1 AND v2 & rest]]
|
|
(cond (and (member? IS '("is" "are")) (= BETWEEN "between") (= AND "and") (not (nil? v2)))
|
|
(let [property (first (parse-simple-value (list p) true))
|
|
value1 (first (parse-simple-value (list v1) true))
|
|
value2 (first (parse-simple-value (list v2) true))]
|
|
[(list 'or
|
|
(list '< value1 property value2)
|
|
(list '> value1 property value2)) rest])))</pre></td></tr><tr><td class="docs"><p>Parse clauses of the form 'x is y', 'x is in y or z...',
|
|
'x is between y and z', 'x is more than y' or 'x is less than y'.
|
|
It is necessary to disambiguate whether value is a numeric or keyword.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-is-condition
|
|
[[property IS value & rest]]
|
|
(cond
|
|
(member? IS '("is" "are"))
|
|
(let [tokens (cons property (cons value rest))]
|
|
(cond
|
|
(re-matches re-number value) [(list '= (list 'get-int 'cell (keyword property)) (read-string value)) rest]
|
|
value [(list '= (list (keyword property) 'cell) (keyword value)) rest]))))</pre></td></tr><tr><td class="docs"><p>Parse the negation of a simple condition.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-not-condition
|
|
[[property IS NOT & rest]]
|
|
(cond (and (member? IS '("is" "are")) (= NOT "not"))
|
|
(let [partial (parse-simple-condition (cons property (cons "is" rest)))]
|
|
(cond partial
|
|
(let [[condition remainder] partial]
|
|
[(list 'not condition) remainder])))))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- gen-neighbours-condition
|
|
([comp1 quantity property value remainder comp2 distance]
|
|
[(list comp1
|
|
(list 'count
|
|
(list 'get-neighbours-with-property-value 'world
|
|
'(cell :x) '(cell :y) distance
|
|
(keyword property) (keyword-or-numeric value) comp2))
|
|
quantity)
|
|
remainder])
|
|
([comp1 quantity property value remainder comp2]
|
|
(gen-neighbours-condition comp1 quantity property value remainder comp2 1)))</pre></td></tr><tr><td class="docs"><p>Parse conditions of the form '...more than 6 neighbours are [condition]'</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-comparator-neighbours-condition
|
|
[[MORE THAN n NEIGHBOURS WITHIN distance have-or-are & rest]]
|
|
(let [quantity (first (parse-numeric-value (list n)))
|
|
comparator (cond (= MORE "more") '>
|
|
(member? MORE '("fewer" "less")) '<)]
|
|
(cond
|
|
(not= WITHIN "within")
|
|
(parse-comparator-neighbours-condition
|
|
(flatten
|
|
;; two tokens were mis-parsed as 'within distance' that weren't
|
|
;; actually 'within' and a distance. Splice in 'within 1' and try
|
|
;; again.
|
|
(list MORE THAN n NEIGHBOURS "within" "1" WITHIN distance have-or-are rest)))
|
|
(and quantity
|
|
comparator
|
|
(= THAN "than")
|
|
(= NEIGHBOURS "neighbours"))
|
|
(cond
|
|
(= have-or-are "are")
|
|
(let [[value & remainder] rest
|
|
dist (gen-token-value distance true)]
|
|
(gen-neighbours-condition comparator quantity :state value remainder = dist))
|
|
(= have-or-are "have")
|
|
(let [[property comp1 comp2 value & remainder] rest
|
|
dist (gen-token-value distance true)]
|
|
(cond (and (= comp1 "equal") (= comp2 "to"))
|
|
(gen-neighbours-condition comparator quantity property
|
|
value remainder = dist)
|
|
(and (= comp1 "more") (= comp2 "than"))
|
|
(gen-neighbours-condition comparator quantity property
|
|
value remainder > dist)
|
|
(and (= comp1 "less") (= comp2 "than"))
|
|
(gen-neighbours-condition comparator quantity property
|
|
value remainder < dist)))))))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-some-neighbours-condition
|
|
[[SOME NEIGHBOURS & rest]]
|
|
(cond
|
|
(and (= SOME "some") (= NEIGHBOURS "neighbours"))
|
|
(parse-comparator-neighbours-condition (concat '("more" "than" "0" "neighbours") rest))))</pre></td></tr><tr><td class="docs"><p>Parse conditions of the form '...6 neighbours are [condition]'</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-simple-neighbours-condition
|
|
[[n NEIGHBOURS WITHIN distance have-or-are & rest]]
|
|
(let [quantity (first (parse-numeric-value (list n)))]
|
|
(cond
|
|
(and quantity (= NEIGHBOURS "neighbours"))
|
|
(cond
|
|
(not= WITHIN "within")
|
|
(parse-simple-neighbours-condition
|
|
(flatten
|
|
;; two tokens were mis-parsed as 'within distance' that weren't
|
|
;; actually 'within' and a distance. Splice in 'within 1' and try
|
|
;; again.
|
|
(list n NEIGHBOURS "within" "1" WITHIN distance have-or-are rest)))
|
|
(= have-or-are "are")
|
|
(let [[value & remainder] rest
|
|
dist (gen-token-value distance true)]
|
|
(gen-neighbours-condition '= quantity :state value remainder = dist))
|
|
(= have-or-are "have")
|
|
(let [[property comp1 comp2 value & remainder] rest
|
|
dist (gen-token-value distance true)]
|
|
(cond (and (= comp1 "equal") (= comp2 "to"))
|
|
(gen-neighbours-condition '= quantity property value remainder =
|
|
dist)
|
|
(and (= comp1 "more") (= comp2 "than"))
|
|
(gen-neighbours-condition '= quantity property value remainder >
|
|
dist)
|
|
(and (= comp1 "less") (= comp2 "than"))
|
|
(gen-neighbours-condition '= quantity property value remainder <
|
|
dist)))))))</pre></td></tr><tr><td class="docs"><p>Parse conditions referring to neighbours</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-neighbours-condition
|
|
[tokens]
|
|
(or
|
|
(parse-simple-neighbours-condition tokens)
|
|
(parse-comparator-neighbours-condition tokens)
|
|
(parse-some-neighbours-condition tokens)))</pre></td></tr><tr><td class="docs"><p>Parse conditions of the form '[property] [comparison] [value]'.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-simple-condition
|
|
[tokens]
|
|
(or
|
|
(parse-neighbours-condition tokens)
|
|
(parse-member-condition tokens)
|
|
(parse-not-condition tokens)
|
|
(parse-less-condition tokens)
|
|
(parse-more-condition tokens)
|
|
(parse-between-condition tokens)
|
|
(parse-is-condition tokens)))</pre></td></tr><tr><td class="docs"><p>Parse '... or [condition]' from <code>tokens</code>, where <code>left</code> is the already parsed first disjunct.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-disjunction-condition
|
|
[left tokens]
|
|
(let [partial (parse-conditions tokens)]
|
|
(if partial
|
|
(let [[right remainder] partial]
|
|
[(list 'or left right) remainder]))))</pre></td></tr><tr><td class="docs"><p>Parse '... and [condition]' from <code>tokens</code>, where <code>left</code> is the already parsed first conjunct.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-conjunction-condition
|
|
[left tokens]
|
|
(let [partial (parse-conditions tokens)]
|
|
(if partial
|
|
(let [[right remainder] partial]
|
|
[(list 'and left right) remainder]))))</pre></td></tr><tr><td class="docs"><p>Parse conditions from <code>tokens</code>, where conditions may be linked by either 'and' or 'or'.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-conditions
|
|
[tokens]
|
|
(let [partial (parse-simple-condition tokens)]
|
|
(if partial
|
|
(let [[left [next & remainder]] partial]
|
|
(cond
|
|
(= next "and") (parse-conjunction-condition left remainder)
|
|
(= next "or") (parse-disjunction-condition left remainder)
|
|
true partial)))))</pre></td></tr><tr><td class="docs"><p>Parse the left hand side ('if...') of a production rule.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-left-hand-side
|
|
[[IF & tokens]]
|
|
(if
|
|
(= IF "if")
|
|
(parse-conditions tokens)))</pre></td></tr><tr><td class="docs"><p>Parse actions of the form '[property] should be [property] [arithmetic-operator] [value]',
|
|
e.g. 'fertility should be fertility + 1', or 'deer should be deer - wolves'.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-arithmetic-action
|
|
[previous [prop1 SHOULD BE prop2 operator value & rest]]
|
|
(cond
|
|
(member? prop1 '("x" "y"))
|
|
(throw
|
|
(Exception. reserved-properties-error))
|
|
(and (= SHOULD "should")
|
|
(= BE "be")
|
|
(member? operator '("+" "-" "*" "/")))
|
|
[(list 'merge (or previous 'cell)
|
|
{(keyword prop1) (list 'int
|
|
(list (symbol operator) (list 'get-int 'cell (keyword prop2))
|
|
(cond
|
|
(re-matches re-number value) (read-string value)
|
|
true (list 'get-int 'cell (keyword value)))))}) rest]))</pre></td></tr><tr><td class="docs"><p>Parse actions of the form '[property] should be [value].'</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-set-action
|
|
[previous [property SHOULD BE value & rest]]
|
|
(cond
|
|
(member? property '("x" "y"))
|
|
(throw
|
|
(Exception. reserved-properties-error))
|
|
(and (= SHOULD "should") (= BE "be"))
|
|
[(list 'merge (or previous 'cell)
|
|
{(keyword property) (cond (re-matches re-number value) (read-string value) true (keyword value))}) rest]))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-simple-action [previous tokens]
|
|
(or (parse-arithmetic-action previous tokens)
|
|
(parse-set-action previous tokens)))</pre></td></tr><tr><td class="docs"><p>Parse actions from tokens.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-actions
|
|
[previous tokens]
|
|
(let [[left remainder] (parse-simple-action previous tokens)]
|
|
(cond left
|
|
(cond (= (first remainder) "and")
|
|
(parse-actions left (rest remainder))
|
|
true (list left)))))</pre></td></tr><tr><td class="docs"><p>Parse a probability of an action from this collection of tokens</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-probability
|
|
[previous [n CHANCE IN m & tokens]]
|
|
(cond
|
|
(and (= CHANCE "chance")(= IN "in"))
|
|
(let [[action remainder] (parse-actions previous tokens)]
|
|
(cond action
|
|
[(list 'cond
|
|
(list '<
|
|
(list 'rand
|
|
(first (parse-simple-value (list m) true)))
|
|
(first (parse-simple-value (list n) true)))
|
|
action) remainder]))))</pre></td></tr><tr><td class="docs"><p>Parse the right hand side ('then...') of a production rule.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parse-right-hand-side
|
|
[[THEN & tokens]]
|
|
(if (= THEN "then")
|
|
(or
|
|
(parse-probability nil tokens)
|
|
(parse-actions nil tokens))))</pre></td></tr><tr><td class="docs"><p>Parse a complete rule from this <code>line</code>, expected to be either a string or a
|
|
sequence of string tokens. Return the rule in the form of an S-expression.</p>
|
|
|
|
<p> Throws an exception if parsing fails.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn parse-rule
|
|
[line]
|
|
(cond
|
|
(string? line)
|
|
(let [rule (parse-rule (split (triml line) #"\s+"))]
|
|
(cond rule rule
|
|
true (throw (Exception. (format bad-parse-error line)))))
|
|
true
|
|
(let [[left remainder] (parse-left-hand-side line)
|
|
[right junk] (parse-right-hand-side remainder)]
|
|
(cond
|
|
;; there should be a valide left hand side and a valid right hand side
|
|
;; there shouldn't be anything left over (junk should be empty)
|
|
(and left right (empty? junk))
|
|
(list 'fn ['cell 'world] (list 'if left right))))))</pre></td></tr><tr><td class="docs"><p>Parse this <code>rule-text</code>, a string conforming to the grammar of MicroWorld rules,
|
|
into Clojure source, and then compile it into an anonymous
|
|
function object, getting round the problem of binding mw-engine.utils in
|
|
the compiling environment. If <code>return-tuple?</code> is present and true, return
|
|
a list comprising the anonymous function compiled, and the function from
|
|
which it was compiled.</p>
|
|
|
|
<p> Throws an exception if parsing fails.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn compile-rule
|
|
([rule-text return-tuple?]
|
|
(do
|
|
(use 'mw-engine.utils)
|
|
(let [afn (eval (parse-rule rule-text))]
|
|
(cond
|
|
(and afn return-tuple?)(list afn (trim rule-text))
|
|
true afn))))
|
|
([rule-text]
|
|
(compile-rule rule-text false)))</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="#mw-parser.errors" name="mw-parser.errors"><h1 class="project-name">mw-parser.errors</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>Display parse errors in a format which makes it easy for the user
|
|
to see where the error occurred.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.errors)</pre></td></tr><tr><td class="docs"><p>This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.</p>
|
|
|
|
<p>This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.</p>
|
|
|
|
<p>You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
USA.</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>error thrown when an attempt is made to set a reserved property</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def reserved-properties-error
|
|
"The properties 'x' and 'y' of a cell are reserved and should not be set in rule actions")</pre></td></tr><tr><td class="docs"><p>error thrown when a rule cannot be parsed. Slots are for
|
|
(1) rule text
|
|
(2) cursor showing where in the rule text the error occurred
|
|
(3) the reason for the error</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def bad-parse-error "I did not understand:\n '%s'\n %s\n %s")</pre></td></tr><tr><td class="docs"><p>Attempt to explain the reason for the parse error.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- explain-parse-error-reason
|
|
[reason]
|
|
(str "Expecting one of (" (apply str (map #(str (:expecting %) " ") reason)) ")"))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- parser-error-to-map
|
|
[parser-error]
|
|
(let [m (reduce (fn [map item](merge map {(first item)(second item)})) {} parser-error)
|
|
reason (map
|
|
#(reduce (fn [map item] (merge {(first item) (second item)} map)) {} %)
|
|
(:reason m))]
|
|
(merge m {:reason reason})))</pre></td></tr><tr><td class="docs"><p>Construct a helpful error message from this <code>parser-error</code>, and throw an exception with that message.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn throw-parse-exception
|
|
[parser-error]
|
|
(assert (coll? parser-error) "Expected a paser error structure?")
|
|
(let
|
|
[
|
|
;; the error structure is a list, such that each element is a list of two items, and
|
|
;; the first element in each sublist is a keyword. Easier to work with it as a map
|
|
error-map (parser-error-to-map parser-error)
|
|
text (:text error-map)
|
|
reason (explain-parse-error-reason (:reason error-map))
|
|
;; rules have only one line, by definition; we're interested in the column
|
|
column (if (:column error-map)(:column error-map) 0)
|
|
;; create a cursor to point to that column
|
|
cursor (apply str (reverse (conj (repeat column " ") "^")))
|
|
message (format bad-parse-error text cursor reason)
|
|
]
|
|
(throw (Exception. message))))</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="#mw-parser.generate" name="mw-parser.generate"><h1 class="project-name">mw-parser.generate</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>Generate Clojure source from simplified parse trees.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.generate
|
|
(:require [clojure.pprint :refer [pprint]]
|
|
[clojure.tools.trace :refer [deftrace]]
|
|
[mw-parser.utils :refer [assert-type TODO]]
|
|
[mw-parser.errors :as pe]))</pre></td></tr><tr><td class="docs"><p>This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.</p>
|
|
|
|
<p>This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.</p>
|
|
|
|
<p>You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
USA.</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(declare generate generate-action)</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct rule specification,
|
|
generate and return the appropriate rule as a function of two arguments.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-rule
|
|
[tree]
|
|
(assert-type tree :RULE)
|
|
(vary-meta
|
|
(list 'fn ['cell 'world] (list 'when (generate (nth tree 2)) (generate (nth tree 3))))
|
|
merge
|
|
{:rule-type
|
|
:production}))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct conditions clause,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-conditions
|
|
[tree]
|
|
(assert-type tree :CONDITIONS)
|
|
(generate (second tree)))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct condition clause,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-condition
|
|
[tree]
|
|
(assert-type tree :CONDITION)
|
|
(generate (second tree)))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically conjunct correct condition clause,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-conjunct-condition
|
|
[tree]
|
|
(assert-type tree :CONJUNCT-CONDITION)
|
|
(cons 'and (map generate (rest tree))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct disjunct condition clause,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-disjunct-condition
|
|
[tree]
|
|
(assert-type tree :DISJUNCT-CONDITION)
|
|
(cons 'or (map generate (rest tree))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically property condition clause for
|
|
this <code>property</code> where the <code>expression</code> is a numeric range, generate and return
|
|
the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-ranged-property-condition
|
|
[tree property expression]
|
|
(assert-type tree :PROPERTY-CONDITION)
|
|
(assert-type (nth tree 3) :RANGE-EXPRESSION)
|
|
(let [l1 (generate (nth expression 2))
|
|
l2 (generate (nth expression 4))
|
|
pv (list property 'cell)]
|
|
(list 'let ['lower (list 'min l1 l2)
|
|
'upper (list 'max l1 l2)]
|
|
(list 'and (list '>= pv 'lower) (list '<= pv 'upper)))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically property condition clause
|
|
where the expression is a a disjunction, generate and return
|
|
the appropriate clojure fragment.
|
|
TODO: this is definitely still wrong!</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-disjunct-property-condition
|
|
([tree]
|
|
(let [property (generate (second tree))
|
|
qualifier (generate (nth tree 2))
|
|
expression (generate (nth tree 3))]
|
|
(generate-disjunct-property-condition tree property qualifier expression)))
|
|
([_tree property qualifier expression]
|
|
(let [e (list expression (list property 'cell))]
|
|
(if (= qualifier '=) e
|
|
(list 'not e)))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically property condition clause,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-property-condition
|
|
([tree]
|
|
(assert-type tree :PROPERTY-CONDITION)
|
|
(if
|
|
(and (= (count tree) 2) (= (first (second tree)) :SYMBOL))
|
|
;; it's a shorthand for 'state equal to symbol'. This should probably have
|
|
;; been handled in simplify...
|
|
(generate-property-condition
|
|
(list
|
|
:PROPERTY-CONDITION
|
|
'(:SYMBOL "state")
|
|
'(:QUALIFIER (:EQUIVALENCE (:EQUAL "equal to")))
|
|
(second tree)))
|
|
;; otherwise...
|
|
(generate-property-condition tree (first (nth tree 3)))))
|
|
([tree expression-type]
|
|
(assert-type tree :PROPERTY-CONDITION)
|
|
(let [property (generate (second tree))
|
|
qualifier (generate (nth tree 2))
|
|
e (generate (nth tree 3))
|
|
expression (cond
|
|
(and (not (= qualifier '=)) (keyword? e)) (list 'or (list e 'cell) e)
|
|
(and (not (= qualifier 'not=)) (keyword? e)) (list 'or (list e 'cell) e)
|
|
:else e)]
|
|
(case expression-type
|
|
:DISJUNCT-EXPRESSION (generate-disjunct-property-condition tree property qualifier expression)
|
|
:RANGE-EXPRESSION (generate-ranged-property-condition tree property expression)
|
|
(list qualifier (list property 'cell) expression)))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct qualifier,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-qualifier
|
|
[tree]
|
|
(if
|
|
(= (count tree) 2)
|
|
(generate (second tree))
|
|
;; else
|
|
(generate (nth tree 2))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct simple action,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-simple-action
|
|
([tree]
|
|
(assert-type tree :SIMPLE-ACTION)
|
|
(generate-simple-action tree []))
|
|
([tree others]
|
|
(assert-type tree :SIMPLE-ACTION)
|
|
(let [property (generate (second tree))
|
|
expression (generate (nth tree 3))]
|
|
(if (or (= property :x) (= property :y))
|
|
(throw (Exception. pe/reserved-properties-error))
|
|
(list 'merge
|
|
(if (empty? others) 'cell
|
|
;; else
|
|
(generate others))
|
|
{property expression})))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct probable action,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-probable-action
|
|
([tree]
|
|
(assert-type tree :PROBABLE-ACTION)
|
|
(generate-probable-action tree []))
|
|
([tree others]
|
|
(assert-type tree :PROBABLE-ACTION)
|
|
(let
|
|
[chances (generate (nth tree 1))
|
|
total (generate (nth tree 2))
|
|
action (generate-action (nth tree 3) others)]
|
|
;; TODO: could almost certainly be done better with macro syntax
|
|
(list 'if
|
|
(list '< (list 'rand total) chances)
|
|
action))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct action,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-action
|
|
[tree others]
|
|
(case (first tree)
|
|
:ACTIONS (generate-action (first tree) others)
|
|
:SIMPLE-ACTION (generate-simple-action tree others)
|
|
:PROBABLE-ACTION (generate-probable-action tree others)
|
|
(throw (Exception. (str "Not a known action type: " (first tree))))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be one or more syntactically correct actions,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-multiple-actions
|
|
[tree]
|
|
(assert-type tree :ACTIONS)
|
|
(generate-action (first (rest tree)) (second (rest tree))))</pre></td></tr><tr><td class="docs"><p>Generate a disjunct value. Essentially what we need here is to generate a
|
|
flat list of values, since the <code>member</code> has already been taken care of.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-disjunct-value
|
|
[tree]
|
|
(assert-type tree :DISJUNCT-VALUE)
|
|
(if (= (count tree) 4)
|
|
(cons (generate (second tree)) (generate (nth tree 3)))
|
|
(list (generate (second tree)))))</pre></td></tr><tr><td class="docs"><p>From this <code>tree</code>, assumed to be a syntactically correct numeric expression,
|
|
generate and return the appropriate clojure fragment.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-numeric-expression
|
|
[tree]
|
|
(assert-type tree :NUMERIC-EXPRESSION)
|
|
(case (count tree)
|
|
4 (let [[p operator expression] (rest tree)
|
|
property (if (number? p) p (list p 'cell))]
|
|
(list (generate operator) (generate property) (generate expression)))
|
|
(case (first (second tree))
|
|
:SYMBOL (list (keyword (second (second tree))) 'cell)
|
|
(generate (second tree)))))</pre></td></tr><tr><td class="docs"><p>Generate code for a condition which refers to neighbours.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-neighbours-condition
|
|
([tree]
|
|
(assert-type tree :NEIGHBOURS-CONDITION)
|
|
(case (first (second tree))
|
|
:NUMBER (read-string (second (second tree)))
|
|
:QUANTIFIER (generate-neighbours-condition tree (first (second (second tree))))
|
|
:QUALIFIER (cons (generate (second tree)) (rest (generate (nth tree 2))))))
|
|
([tree quantifier-type]
|
|
(let [quantifier (second tree)
|
|
pc (generate (nth tree 4))]
|
|
(case quantifier-type
|
|
:NUMBER (generate-neighbours-condition '= (read-string (second (second quantifier))) pc 1)
|
|
:SOME (generate-neighbours-condition '> 0 pc 1)
|
|
:MORE (let [value (generate (nth quantifier 3))]
|
|
(generate-neighbours-condition '> value pc 1))
|
|
:LESS (let [value (generate (nth quantifier 3))]
|
|
(generate-neighbours-condition '< value pc 1)))))
|
|
([comp1 quantity property-condition distance]
|
|
(list comp1
|
|
(list 'count
|
|
(list 'remove 'false?
|
|
(list 'map (list 'fn ['cell] property-condition)
|
|
(list 'mw-engine.utils/get-neighbours 'world 'cell distance)))) quantity))
|
|
([comp1 quantity property-condition]
|
|
(generate-neighbours-condition comp1 quantity property-condition 1)))</pre></td></tr><tr><td class="docs"><p>Generate code for a condition which refers to neighbours within a specified distance.
|
|
NOTE THAT there's clearly masses of commonality between this and
|
|
<code>generate-neighbours-condition</code>, and that some refactoring is almost certainly
|
|
desirable. It may be that it's better to simplify a <code>NEIGHBOURS-CONDITION</code>
|
|
into a <code>WITHIN-CONDITION</code> in the simplification stage.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-within-condition
|
|
([tree]
|
|
(assert-type tree :WITHIN-CONDITION)
|
|
(case (first (second tree))
|
|
:QUANTIFIER (generate-within-condition tree (first (second (second tree))))
|
|
:QUALIFIER (TODO "qualified within... help!")))
|
|
([tree quantifier-type]
|
|
(let [quantifier (second tree)
|
|
distance (generate (nth tree 4))
|
|
pc (generate (nth tree 6))]
|
|
(case quantifier-type
|
|
:NUMBER (generate-neighbours-condition '= (read-string (second (second quantifier))) pc distance)
|
|
:SOME (generate-neighbours-condition '> 0 pc distance)
|
|
:MORE (let [value (generate (nth quantifier 3))]
|
|
(generate-neighbours-condition '> value pc distance))
|
|
:LESS (let [value (generate (nth quantifier 3))]
|
|
(generate-neighbours-condition '< value pc distance))))))</pre></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn- generate-disjunct-expression
|
|
[tree]
|
|
(assert-type tree :DISJUNCT-EXPRESSION)
|
|
(try
|
|
(set (map generate (rest tree)))
|
|
(catch Exception x
|
|
(throw
|
|
(ex-info
|
|
"Failed to compile :DISJUNCT-EXPRESSION"
|
|
{:tree tree}
|
|
x)))))</pre></td></tr><tr><td class="docs"><p>Flow rules. A flow rule DOES NOT return a modified world; instead, it
|
|
returns a PLAN to modify the world, in the form of a sequence of <code>flows</code>.
|
|
It is only when the plan is executed that the world is modified.</p>
|
|
|
|
<p>so we're looking at something like
|
|
(fn [cell world])
|
|
(if (= (:state cell) (or (:house cell) :house))</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs">
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate-flow
|
|
[tree]
|
|
(assert-type tree :FLOW-RULE))</pre></td></tr><tr><td class="docs"><p>Top level; only function anything outside this file (except tests) should
|
|
really call.</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Generate code for this (fragment of a) parse tree</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn generate
|
|
[tree]
|
|
(if
|
|
(coll? tree)
|
|
(case (first tree)
|
|
:ACTIONS (generate-multiple-actions tree)
|
|
:COMPARATIVE (generate (second tree))
|
|
:COMPARATIVE-QUALIFIER (generate (second tree))
|
|
:CONDITION (generate-condition tree)
|
|
:CONDITIONS (generate-conditions tree)
|
|
:CONJUNCT-CONDITION (generate-conjunct-condition tree)
|
|
:DISJUNCT-CONDITION (generate-disjunct-condition tree)
|
|
:DISJUNCT-EXPRESSION (generate-disjunct-expression tree)
|
|
:DISJUNCT-VALUE (generate-disjunct-value tree)
|
|
:EQUIVALENCE '=
|
|
:EXPRESSION (generate (second tree))
|
|
:FLOW-RULE (generate-flow tree)
|
|
:LESS '<
|
|
:MORE '>
|
|
:NEGATED-QUALIFIER (case (generate (second tree))
|
|
= 'not=
|
|
> '<
|
|
< '>)
|
|
:NEIGHBOURS-CONDITION (generate-neighbours-condition tree)
|
|
:NUMERIC-EXPRESSION (generate-numeric-expression tree)
|
|
:NUMBER (read-string (second tree))
|
|
:OPERATOR (symbol (second tree))
|
|
:PROBABLE-ACTION (generate-probable-action tree)
|
|
:PROPERTY (list (generate (second tree)) 'cell) ;; dubious - may not be right
|
|
:PROPERTY-CONDITION (generate-property-condition tree)
|
|
:QUALIFIER (generate-qualifier tree)
|
|
:RULE (generate-rule tree)
|
|
:SIMPLE-ACTION (generate-simple-action tree)
|
|
:SYMBOL (keyword (second tree))
|
|
:VALUE (generate (second tree))
|
|
:WITHIN-CONDITION (generate-within-condition tree)
|
|
(map generate tree))
|
|
tree))</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="#mw-parser.declarative" name="mw-parser.declarative"><h1 class="project-name">mw-parser.declarative</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>A very simple parser which parses production rules.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(ns ^{:doc
|
|
:author "Simon Brooke"}
|
|
mw-parser.declarative
|
|
(:require [instaparse.core :refer [parser]]
|
|
[clojure.string :refer [join trim]]
|
|
[mw-parser.errors :refer [throw-parse-exception]]
|
|
[mw-parser.generate :refer [generate]]
|
|
[mw-parser.simplify :refer [simplify]]
|
|
[mw-parser.utils :refer [rule?]]
|
|
[trptr.java-wrapper.locale :refer [get-default]])
|
|
(:import [java.util Locale]))</pre></td></tr><tr><td class="docs"><p>mw-parser: a rule parser for MicroWorld.</p>
|
|
|
|
<p>This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.</p>
|
|
|
|
<p>This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.</p>
|
|
|
|
<p>You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
USA.</p>
|
|
|
|
<p>Copyright (C) 2014 Simon Brooke</p>
|
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Basic rule language grammar.</p>
|
|
|
|
<p> in order to simplify translation into other natural languages, all
|
|
TOKENS within the parser should be unambiguou.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def rule-grammar
|
|
(join "\n" ["RULE := IF SPACE CONDITIONS SPACE THEN SPACE ACTIONS;"
|
|
"ACTIONS := ACTION | ACTION SPACE AND SPACE ACTIONS"
|
|
"ACTION := SIMPLE-ACTION | PROBABLE-ACTION;"
|
|
"PROBABLE-ACTION := VALUE SPACE CHANCE-IN SPACE VALUE SPACE SIMPLE-ACTION;"
|
|
"SIMPLE-ACTION := SYMBOL SPACE BECOMES SPACE EXPRESSION;"]))</pre></td></tr><tr><td class="docs"><p>Grammar rules used both in the rule grammar and in the flow grammar</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def common-grammar
|
|
(join "\n" ["COMPARATIVE := MORE | LESS;"
|
|
"COMPARATIVE-QUALIFIER := IS SPACE COMPARATIVE SPACE THAN | COMPARATIVE SPACE THAN;"
|
|
"CONDITION := WITHIN-CONDITION | NEIGHBOURS-CONDITION | PROPERTY-CONDITION;"
|
|
"CONDITIONS := DISJUNCT-CONDITION | CONJUNCT-CONDITION | CONDITION ;"
|
|
"CONJUNCT-CONDITION := CONDITION SPACE AND SPACE CONDITIONS;"
|
|
"DISJUNCT-CONDITION := CONDITION SPACE OR SPACE CONDITIONS;"
|
|
"DISJUNCT-EXPRESSION := IN SPACE DISJUNCT-VALUE;"
|
|
"DISJUNCT-VALUE := VALUE | VALUE SPACE OR SPACE DISJUNCT-VALUE;"
|
|
"EQUIVALENCE := IS SPACE EQUAL | EQUAL | IS ;"
|
|
"EXPRESSION := SIMPLE-EXPRESSION | RANGE-EXPRESSION | NUMERIC-EXPRESSION | DISJUNCT-EXPRESSION | VALUE;"
|
|
"NEGATED-QUALIFIER := QUALIFIER SPACE NOT | NOT SPACE QUALIFIER;"
|
|
"NEIGHBOURS-CONDITION := QUANTIFIER SPACE NEIGHBOURS SPACE IS SPACE PROPERTY-CONDITION | QUALIFIER SPACE NEIGHBOURS-CONDITION;"
|
|
"NUMBER := #'[0-9]+' | #'[0-9]+.[0-9]+';"
|
|
"NUMERIC-EXPRESSION := VALUE | VALUE SPACE OPERATOR SPACE NUMERIC-EXPRESSION;"
|
|
"OPERATOR := '+' | '-' | '*' | '/';"
|
|
"PROPERTY := SYMBOL;"
|
|
"PROPERTY-CONDITION := PROPERTY SPACE QUALIFIER SPACE EXPRESSION | VALUE;"
|
|
"PROPERTY-CONDITION-OR-EXPRESSION := PROPERTY-CONDITION | EXPRESSION;"
|
|
"QUALIFIER := COMPARATIVE-QUALIFIER | NEGATED-QUALIFIER | EQUIVALENCE | IS SPACE QUALIFIER;"
|
|
"QUANTIFIER := NUMBER | SOME | NONE | ALL | COMPARATIVE SPACE THAN SPACE NUMBER;"
|
|
"RANGE-EXPRESSION := BETWEEN SPACE NUMERIC-EXPRESSION SPACE AND SPACE NUMERIC-EXPRESSION;"
|
|
"SIMPLE-EXPRESSION := QUALIFIER SPACE EXPRESSION | VALUE;"
|
|
"SPACE := #'\\s+';"
|
|
"VALUE := SYMBOL | NUMBER;"
|
|
"VALUE := SYMBOL | NUMBER;"
|
|
"WITHIN-CONDITION := QUANTIFIER SPACE NEIGHBOURS SPACE WITHIN SPACE NUMBER SPACE IS SPACE PROPERTY-CONDITION-OR-EXPRESSION;"
|
|
]))</pre></td></tr><tr><td class="docs"><p>English language keyword literals used in rules - both in production
|
|
rules (this namespace) and in flow rules (see mw-parser.flow).</p>
|
|
|
|
<pre><code> It's a long term aim that the rule language should be easy to
|
|
internationalise; this isn't a full solution but it's a step towards
|
|
a solution.
|
|
</code></pre>
|
|
</td><td class="codes"><pre class="brush: clojure">(def keywords-en
|
|
(join "\n" ["ALL := 'all'"
|
|
"AND := 'and';"
|
|
"BECOMES := 'should be' | 'becomes';"
|
|
"BETWEEN := 'between';"
|
|
"CHANCE-IN := 'chance in';"
|
|
"EACH := 'each' | 'every' | 'all';"
|
|
"EQUAL := 'equal to';"
|
|
"FIRST := 'first';"
|
|
"FLOW := 'flow' | 'move';"
|
|
"FROM := 'from';"
|
|
"IF := 'if';"
|
|
"IN := 'in';"
|
|
"IS := 'is' | 'are' | 'have' | 'has';"
|
|
"LEAST := 'least';"
|
|
"LESS := 'less' | 'fewer';"
|
|
"MORE := 'more' | 'greater';"
|
|
"MOST := 'most';"
|
|
"NEIGHBOURS := 'neighbour' | 'neighbor' | 'neighbours' | 'neighbors';"
|
|
"NONE := 'no';"
|
|
"NOT := 'not';"
|
|
"OR := 'or';"
|
|
"SOME := 'some';"
|
|
;; SYMBOL is in the per-language file so that languages that use
|
|
;; (e.g.) Cyrillic characters can change the definition.
|
|
"SYMBOL := #'[a-z]+';"
|
|
"THAN := 'than';"
|
|
"THEN := 'then';"
|
|
"TO := 'to';"
|
|
"WITH := 'with' | 'where' | 'having';"
|
|
"WITHIN := 'within';"]))</pre></td></tr><tr><td class="docs"><p>For now, just return <code>keywords-en</code>; plan is to have resource files of
|
|
keywords for different languages in a resource directory, but that isn't
|
|
done yet. It's probably not going to work easily for languages that use
|
|
non-latin alphabets, anyway.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn keywords-for-locale
|
|
([]
|
|
(keywords-for-locale (get-default)))
|
|
([^Locale _locale]
|
|
keywords-en))</pre></td></tr><tr><td class="docs"><p>Compose this grammar fragment <code>g</code> with the common grammar fragments to
|
|
make a complete grammar, and return a parser for that complete grammar.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defmacro build-parser
|
|
[g]
|
|
`(parser (join "\n" [~g common-grammar (keywords-for-locale)])))</pre></td></tr><tr><td class="docs"><p>Parse the argument, assumed to be a string in the correct syntax, and return a parse tree.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(def parse-rule
|
|
(build-parser rule-grammar))</pre></td></tr><tr><td class="docs"><p>Parse this <code>rule-text</code>, a string conforming to the grammar of MicroWorld rules,
|
|
into Clojure source, and then compile it into an anonymous
|
|
function object, getting round the problem of binding mw-engine.utils in
|
|
the compiling environment. If <code>return-tuple?</code> is present and true, return
|
|
a list comprising the anonymous function compiled, and the function from
|
|
which it was compiled.</p>
|
|
|
|
<p> Throws an exception if parsing fails.</p>
|
|
</td><td class="codes"><pre class="brush: clojure">(defn compile-rule
|
|
([rule-text return-tuple?]
|
|
(assert (string? rule-text))
|
|
(let [rule (trim rule-text)
|
|
tree (simplify (parse-rule rule))
|
|
afn (if (rule? tree) (eval (generate tree))
|
|
;; else
|
|
(throw-parse-exception tree))]
|
|
(if return-tuple?
|
|
(list afn rule)
|
|
;; else
|
|
afn)))
|
|
([rule-text]
|
|
(compile-rule rule-text false)))</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_mw-parser.simplify">mw-parser.simplify</li><li class="floating-toc-li" id="floating-toc_mw-parser.bulk">mw-parser.bulk</li><li class="floating-toc-li" id="floating-toc_mw-parser.utils">mw-parser.utils</li><li class="floating-toc-li" id="floating-toc_mw-parser.flow">mw-parser.flow</li><li class="floating-toc-li" id="floating-toc_mw-parser.core">mw-parser.core</li><li class="floating-toc-li" id="floating-toc_mw-parser.errors">mw-parser.errors</li><li class="floating-toc-li" id="floating-toc_mw-parser.generate">mw-parser.generate</li><li class="floating-toc-li" id="floating-toc_mw-parser.declarative">mw-parser.declarative</li></ul></div></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false;
|
|
SyntaxHighlighter.all();
|
|
|
|
// hackity hack
|
|
$(window).load(function() {
|
|
var ft = $("#floating-toc");
|
|
var ul = ft.find('ul');
|
|
var lis = ft.find('li');
|
|
var liHeight = $(lis.first()).height();
|
|
|
|
ul.css('margin', '0px');
|
|
ft.css('height', liHeight + 'px');
|
|
|
|
showNs = function(ns) {
|
|
var index = 0;
|
|
|
|
for(i in nsPositions.nss) {
|
|
if(ns == nsPositions.nss[i]) index = i;
|
|
}
|
|
|
|
if(index != lastNsIndex) {
|
|
lastNsIndex = index;
|
|
ul.animate({marginTop: (-1 * liHeight * index) + 'px'},
|
|
300);
|
|
}
|
|
|
|
}
|
|
|
|
var calcNsPositions = function() {
|
|
var hheight = $('.docs-header').first().height();
|
|
var nss = [];
|
|
var anchors = [];
|
|
var positions = [];
|
|
$.each(lis, function(i, el) {
|
|
var ns = $(el).attr('id').split('_')[1];
|
|
nss.push(ns);
|
|
var a = $("a[name='"+ns+"']");
|
|
anchors.push(a);
|
|
positions.push(a.offset().top - hheight);
|
|
// console.log(a.offset().top)
|
|
});
|
|
|
|
return {nss: nss, positions: positions};
|
|
}
|
|
|
|
var nsPositions = calcNsPositions();
|
|
// console.log(nsPositions)
|
|
var lastNsIndex = -1;
|
|
var $window = $(window);
|
|
|
|
var currentSection = function(nsp) {
|
|
var ps = nsp.positions;
|
|
var scroll = $window.scrollTop();
|
|
var nsIndex = -1;
|
|
|
|
for(var i = 0, length = ps.length; i < length; i++) {
|
|
if(ps[i] >= scroll) {
|
|
nsIndex = i-1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(nsIndex == -1) {
|
|
if(scroll >= ps[0]) {
|
|
nsIndex = ps.length - 1;
|
|
} else {
|
|
nsIndex = 0;
|
|
}
|
|
}
|
|
|
|
return nsp.nss[nsIndex];
|
|
}
|
|
|
|
$(window).scroll(function(e) {
|
|
showNs(currentSection(nsPositions));
|
|
});
|
|
});
|
|
</script></body></html> |