3219 lines
199 KiB
HTML
3219 lines
199 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html><head><meta charset="utf-8" content="text/html" http-equiv="Content-Type" /><meta content="Periodically send metrics" 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{padding:0;margin:0;}h1{padding:0;margin:0;}h2{padding:0;margin:0;}h3{padding:0;margin:0;}h4{padding:0;margin: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-left:10px;margin-top:0;display:inline;}.toc-link{color:#252519;font-size:12px;margin-left:10px;text-decoration:none;}.toc-link:hover{color:#5050A6;}.toc h1{font-size:34px;margin:0;}.docs-header{padding-bottom:10px;margin-bottom:25px;border-bottom:dotted #aaa 1px;}.toc h1{font-size:24px;}.toc{margin-bottom:40px;border-bottom:solid #bbb 1px;}.toc ul{margin-left:20px;margin-top:0;padding-top:0;padding-left:0px;}.toc li{list-style-type:none;padding-left:0;}.dependencies{}.dependencies table{font-size:16px;margin-left:20px;width:99.99%;border:none;}.dependencies td{white-space:nowrap;padding-right:20px;;}.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;margin-top:0;padding-top:0;padding-left:0px;}.plugins li{list-style-type:none;padding-left:0;}.header p{margin-left:20px;}</style><style type="text/css">#floating-toc{text-align:right;top:10px;overflow:hidden;right:20px;position:fixed;height:20px;}#floating-toc li{list-style-type:none;padding:0;margin:0;}</style><style type="text/css">body{color:#252519;font-size:16px;background-color:#F5F5FF;padding:0;font-family:'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;;margin:0;}h1{font-size:20px;margin-top:0;}h2{font-size:18px;}h3{font-size:16px;}a.anchor{color:#252519;text-decoration:none;}a.anchor:hover{color:#5050A6;}table{border-spacing:0;margin-bottom:10px;border-bottom:solid #ddd 1px;;}code{display:inline;}p{margin-top:8px;}tr{padding:0px;margin:0px;}td.docs{vertical-align:top;background-color:#FFF;width:410px;max-width:410px;padding-right:20px;padding-left:55px;border:none;margin:0px;}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{padding:4px;display:block;}code{font-size:14px;background-color:ghostWhite;padding-right:3px;padding-left:3px;border:solid #DEDEDE 1px;}.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.ou
|
||
|
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.
|
||
|
{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.leng
|
||
|
</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"
|
||
|
</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>bigbrother -- Marginalia</title></head><body><table><tr><td class="docs"><div class="header"><h1 class="project-name"><a href="http://github.com/yogsototh/bigbrother">bigbrother</a></h1><h2 class="project-version">0.1.0-SNAPSHOT</h2><br /><p>Periodically send metrics</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.6.0</td></tr><tr><td class="dep-name">org.clojure/data.json</td><td class="dotted"><hr /></td><td class="dep-version">0.2.5</td></tr><tr><td class="dep-name">org.clojure/tools.logging</td><td class="dotted"><hr /></td><td class="dep-version">0.3.1</td></tr><tr><td class="dep-name">org.clojure/algo.generic</td><td class="dotted"><hr /></td><td class="dep-version">0.1.2</td></tr><tr><td class="dep-name">org.clojure/test.check</td><td class="dotted"><hr /></td><td class="dep-version">0.7.0</td></tr><tr><td class="dep-name">riemann-clojure-client</td><td class="dotted"><hr /></td><td class="dep-version">0.3.2</td></tr><tr><td class="dep-name">overtone/at-at</td><td class="dotted"><hr /></td><td class="dep-version">1.2.0</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="#bigbrother.core">bigbrother.core</a></li><li><a href="#bigbrother.counter">bigbrother.counter</a></li><li><a href="#bigbrother.max-metrics">bigbrother.max-metrics</a></li><li><a href="#bigbrother.metrics">bigbrother.metrics</a></li><li><a href="#bigbrother.timer">bigbrother.timer</a></li></ul></div></td><td class="codes"> </td></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#bigbrother.core" name="bigbrother.core"><h1 class="project-name">bigbrother.core</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>This file provide helpers to manage time spend in functions</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(ns bigbrother.core
|
||
|
(:require [clojure.tools.logging :as log]
|
||
|
[clojure.data.json :as json]
|
||
|
[overtone.at-at :refer [every mk-pool]]
|
||
|
[riemann.client :as r]
|
||
|
[clojure.algo.generic.functor :refer [fmap]]
|
||
|
[bigbrother.timer :as timer]
|
||
|
[bigbrother.counter :as counter]
|
||
|
[bigbrother.metrics :as metrics]
|
||
|
[bigbrother.max-metrics :as max-metrics]))</pre></td></tr><tr><td class="docs"><p>Atoms</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def pool (atom nil)) ;; pool for async</pre></td></tr><tr><td class="docs"><p>pool for async</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def default-map (atom #{}))
|
||
|
(def riemann-conn (atom nil))
|
||
|
(def riemann-service (atom "supercell"))
|
||
|
(def level-by-key (atom nil))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def n (atom 0)) ;; a number</pre></td></tr><tr><td class="docs"><p>a number</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def log-time timer/log-time)
|
||
|
(def log-counter counter/log-counter)
|
||
|
(def log-metric metrics/log-metric)
|
||
|
(def log-mmetric max-metrics/log-mmetric)</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn timer-loop-finished []
|
||
|
;; increment the number of loop
|
||
|
(swap! n inc)
|
||
|
(timer/finish-timer-loop)
|
||
|
(max-metrics/loop-finished)
|
||
|
(metrics/loop-finished)
|
||
|
(counter/loop-finished))</pre></td></tr><tr><td class="docs"><p>Starting the timer</p>
|
||
|
|
||
|
<p>---- aliases</p>
|
||
|
|
||
|
<p>Starting the timer</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn big-brother-is-watching-you []
|
||
|
(timer/log-time :start))
|
||
|
(def telescreen-on big-brother-is-watching-you)</pre></td></tr><tr><td class="docs"><p>End the timer chrono</p>
|
||
|
|
||
|
<p>End the timer chrono</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def welcome-in-miniluv timer-loop-finished)
|
||
|
(def telescreen-off timer-loop-finished)</pre></td></tr><tr><td class="docs"><p><hr />
|
||
|
Riemann Warn Level</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>warn level between two numbers</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn warn-level
|
||
|
[warn crit]
|
||
|
(fn [v] (cond (neg? v) "critical"
|
||
|
(>= v crit) "critical"
|
||
|
(>= v warn) "warning"
|
||
|
:else "ok")))
|
||
|
(defn rev-warn-level
|
||
|
[warn crit]
|
||
|
(fn [v] (cond (<= v crit) "critical"
|
||
|
(<= v warn) "warning"
|
||
|
:else "ok")))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn ok [] (fn [_] "ok"))
|
||
|
(defn warning [] (fn [_] "warning"))
|
||
|
(defn critical [] (fn [_] "critical"))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn- to-riemann-event [[k v]]
|
||
|
(when (number? v)
|
||
|
(let [lvl-fn (get @level-by-key k)
|
||
|
level (if lvl-fn (lvl-fn v) "ok")]
|
||
|
{:service (str @riemann-service " " (name k) (subs (str k) 1))
|
||
|
:state level
|
||
|
:metric v})))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn send-to-riemann [m]
|
||
|
(let [result-map (into @default-map m)
|
||
|
metric-data {:service @riemann-service
|
||
|
:state "ok"}
|
||
|
events (remove nil? (map to-riemann-event result-map))
|
||
|
]
|
||
|
(when @riemann-conn
|
||
|
(r/send-events @riemann-conn events))))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn reset-accumulators! []
|
||
|
(counter/reset-acc!)
|
||
|
(metrics/reset-acc!)
|
||
|
(max-metrics/reset-acc!)
|
||
|
(timer/reset-acc!)
|
||
|
(reset! n 0))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn reset-all-atoms! []
|
||
|
(reset! timer/times [])
|
||
|
(reset! metrics/metrics {})
|
||
|
(reset! max-metrics/mmetrics {})
|
||
|
(reset! counter/counters {})
|
||
|
(reset-accumulators!))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn resume-map [nb-ms]
|
||
|
(let [n-by-sec (float (/ @n (/ nb-ms 1000)))
|
||
|
basic {:nb n-by-sec}]
|
||
|
(reduce into basic [(metrics/resume @n)
|
||
|
(max-metrics/resume)
|
||
|
(timer/resume)
|
||
|
(counter/resume nb-ms)])))</pre></td></tr><tr><td class="docs"><p>display the time at most every 10s</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn display-time
|
||
|
[nb-ms]
|
||
|
(let [result (resume-map nb-ms)]
|
||
|
(log/info (json/write-str result))
|
||
|
(send-to-riemann result)
|
||
|
(reset-accumulators!)))</pre></td></tr><tr><td class="docs"><h2>init-metrics</h2>
|
||
|
|
||
|
<pre><code>init-map :: Map Keyword (v -> ERROR_LEVEL)
|
||
|
</code></pre>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn init-metrics
|
||
|
[init-map nb-ms-metrics riemann-host riemann-service-name]
|
||
|
(reset! default-map (reduce into {}
|
||
|
(map (fn [k] {k -1} )
|
||
|
(conj (keys init-map) :total))))
|
||
|
(reset! level-by-key init-map)
|
||
|
(reset! pool (mk-pool))
|
||
|
(reset! riemann-service riemann-service-name)
|
||
|
(when riemann-host
|
||
|
(reset! riemann-conn (r/tcp-client {:host riemann-host})))
|
||
|
(every nb-ms-metrics (fn [] (display-time nb-ms-metrics)) @pool))</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="#bigbrother.counter" name="bigbrother.counter"><h1 class="project-name">bigbrother.counter</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(ns bigbrother.counter
|
||
|
(:require
|
||
|
[clojure.algo.generic.functor :refer [fmap]]))</pre></td></tr><tr><td class="docs"><p><hr />
|
||
|
COUNTERS</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><h2>Monoid instance of `sumcounter`</h2>
|
||
|
|
||
|
<p>a sum time is a list of couple <code>{name nb}</code></p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def empty-sumcounter {})
|
||
|
(defn add-sumcounter [st st2]
|
||
|
(merge-with + st st2))</pre></td></tr><tr><td class="docs"><p>Counters atoms</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def counters (atom {}))
|
||
|
(def sumcounters (atom empty-sumcounter))</pre></td></tr><tr><td class="docs"><p>Counters (the mean is given by default)</p>
|
||
|
|
||
|
<p>declare a specific counters (not time)</p>
|
||
|
|
||
|
<p>declare a specific counters (not time) and returns the first parameter</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn- set-counter! [k v] (swap! counters add-sumcounter {k v}))
|
||
|
(defn log-counter
|
||
|
([k] (set-counter! k 1))
|
||
|
([k v] (set-counter! k v)))
|
||
|
(defn log-counter->
|
||
|
[x k v]
|
||
|
(log-counter k v)
|
||
|
x)</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn loop-finished []
|
||
|
;; aggreate sumcounter
|
||
|
(swap! sumcounters add-sumcounter @counters)
|
||
|
(reset! counters {}))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn reset-acc! []
|
||
|
(reset! sumcounters empty-sumcounter))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn resume [nb-ms]
|
||
|
(fmap #(float (/ % (/ nb-ms 1000))) @sumcounters))</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="#bigbrother.max-metrics" name="bigbrother.max-metrics"><h1 class="project-name">bigbrother.max-metrics</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(ns bigbrother.max-metrics)</pre></td></tr><tr><td class="docs"><p><hr />
|
||
|
Max Metrics</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><h2>Monoid instance of `maxmetrics`</h2>
|
||
|
|
||
|
<p>a sum time is a list of couple <code>{name metric-value}</code></p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def empty-maxmetric {})
|
||
|
(defn add-maxmetrics [st st2]
|
||
|
(merge-with max st st2))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def mmetrics (atom {})) ;; timestamps</pre></td></tr><tr><td class="docs"><p>timestamps</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def maxmetrics (atom empty-maxmetric)) ;; time spent by type</pre></td></tr><tr><td class="docs"><p>time spent by type</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Max Metrics (metrics to do a max between them instead of a mean)</p>
|
||
|
|
||
|
<p>declare a specific max metrics (not time)</p>
|
||
|
|
||
|
<p>declare a specific max metrics (not time) and returns the first parameter</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn- set-mmetric! [k v] (swap! mmetrics add-maxmetrics {k v}))
|
||
|
(defn log-mmetric
|
||
|
[k v]
|
||
|
(set-mmetric! k v))
|
||
|
(defn log-mmetric->
|
||
|
[x k v]
|
||
|
(log-mmetric k v)
|
||
|
x)</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn loop-finished []
|
||
|
;; aggreate maxmetrics
|
||
|
(swap! maxmetrics add-maxmetrics @mmetrics)
|
||
|
(reset! mmetrics {}))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn reset-acc! []
|
||
|
(reset! maxmetrics empty-maxmetric))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn resume [] @maxmetrics)</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="#bigbrother.metrics" name="bigbrother.metrics"><h1 class="project-name">bigbrother.metrics</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(ns bigbrother.metrics
|
||
|
(:require [clojure.algo.generic.functor :refer [fmap]]))</pre></td></tr><tr><td class="docs"><p><hr />
|
||
|
Sum Metrics</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><h2>Monoid instance of `summetrics`</h2>
|
||
|
|
||
|
<p>a sum time is a list of couple <code>{name metric-value}</code></p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def empty-summetric {})
|
||
|
(defn add-summetrics [st st2]
|
||
|
(merge-with + st st2))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def metrics (atom {})) ;; timestamps</pre></td></tr><tr><td class="docs"><p>timestamps</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def summetrics (atom empty-summetric)) ;; time spent by type</pre></td></tr><tr><td class="docs"><p>time spent by type</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Metrics (the mean is given by default)</p>
|
||
|
|
||
|
<p>declare a specific metrics (not time)</p>
|
||
|
|
||
|
<p>declare a specific metrics (not time) and returns the first parameter</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn- set-metric! [k v] (swap! metrics add-summetrics {k v}))
|
||
|
(defn log-metric
|
||
|
[k v]
|
||
|
(set-metric! k v))
|
||
|
(defn log-metric->
|
||
|
[x k v]
|
||
|
(log-metric k v)
|
||
|
x)</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn loop-finished []
|
||
|
;; aggreate summetrics
|
||
|
(swap! summetrics add-summetrics @metrics)
|
||
|
(reset! metrics {}))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn reset-acc! []
|
||
|
(reset! summetrics empty-summetric))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn resume [n]
|
||
|
(fmap #(float (/ % n)) @summetrics))</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="#bigbrother.timer" name="bigbrother.timer"><h1 class="project-name">bigbrother.timer</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(ns bigbrother.timer)</pre></td></tr><tr><td class="docs"><p><hr />
|
||
|
TIMERS</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><h2>Monoid instance of `sumtimes`</h2>
|
||
|
|
||
|
<p>a sum time is a list of couple <code>[name [timespent nb]]</code></p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn ts-name [x] (first x))
|
||
|
(defn ts-timespent [x] (first (second x)))
|
||
|
(defn ts-nb [x] (second (second x)))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def empty-sumtime [])
|
||
|
(defn- add-one-sumtime [st st2]
|
||
|
[(ts-name st) [(+ (ts-timespent st) (ts-timespent st2))
|
||
|
(+ (ts-nb st) (ts-nb st2))]])
|
||
|
(defn add-sumtimes [st st2]
|
||
|
(cond (empty? st) st2
|
||
|
(empty? st2) st
|
||
|
:else (map add-one-sumtime st st2)))
|
||
|
(defn fmap-sumtimes [f st]
|
||
|
(map (fn [v] [(first v) [(f (ts-timespent v))
|
||
|
(ts-nb v)]]) st))</pre></td></tr><tr><td class="docs"><p>Given a <code>sumtimes</code> returns a map <code>{key timespent}</code>'</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn normalized-map-from-sumtimes
|
||
|
[st]
|
||
|
(reduce #(merge-with + %1 %2) {}
|
||
|
(map (fn [v] {(ts-name v)
|
||
|
(/ (ts-timespent v)
|
||
|
(ts-nb v))}) st)))</pre></td></tr><tr><td class="docs"><p>timers atoms</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def times (atom [])) ;; timestamps</pre></td></tr><tr><td class="docs"><p>timestamps</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(def sumtimes (atom empty-sumtime)) ;; time spent by type</pre></td></tr><tr><td class="docs"><p>time spent by type</p>
|
||
|
</td><td class="codes"></td></tr><tr><td class="docs"><p>Timer</p>
|
||
|
|
||
|
<p>declare the action named <code>k</code> finished</p>
|
||
|
|
||
|
<p>declare the action named <code>k</code> finished and returned object <code>x</code></p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn- set-value! [k v] (swap! times conj [k v]))
|
||
|
(defn log-time
|
||
|
[k]
|
||
|
(set-value! k (System/nanoTime)))
|
||
|
(defn log-time->
|
||
|
[x k]
|
||
|
(log-time k)
|
||
|
x)</pre></td></tr><tr><td class="docs"><p>get time spent during one step</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn- show-one-step
|
||
|
[x]
|
||
|
(if (< (count x) 2)
|
||
|
{:nothing 0}
|
||
|
(let [from (second (first x))
|
||
|
k (first (second x))
|
||
|
to (second (second x))]
|
||
|
[k [(- to from) 1]])))</pre></td></tr><tr><td class="docs"><p>from a list of timestamp generate a sumtime</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn timespent
|
||
|
[times-array]
|
||
|
(map show-one-step (partition 2 1 times-array)))</pre></td></tr><tr><td class="docs"><p>from a list of timestamp generate the total time spent</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn total-time
|
||
|
[times-array]
|
||
|
(- (second (last times-array))
|
||
|
(second (first times-array))))</pre></td></tr><tr><td class="docs"><p>convert from nanoseconds to milliseconds</p>
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn to-milliseconds
|
||
|
[times-array]
|
||
|
(fmap-sumtimes #(float (/ % 1000000)) times-array))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn finish-timer-loop []
|
||
|
;; Convert actual timestamps to sumtimes and aggregate them
|
||
|
(if (> (count @times) 1)
|
||
|
(let [difftime (timespent @times)
|
||
|
total (total-time @times)
|
||
|
res (to-milliseconds (conj difftime [:total [total 1]]))]
|
||
|
(swap! sumtimes add-sumtimes res)))
|
||
|
(reset! times []))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn reset-acc! []
|
||
|
(reset! sumtimes empty-sumtime))</pre></td></tr><tr><td class="docs">
|
||
|
</td><td class="codes"><pre class="brush: clojure">(defn resume []
|
||
|
(normalized-map-from-sumtimes @sumtimes))</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_bigbrother.core">bigbrother.core</li><li class="floating-toc-li" id="floating-toc_bigbrother.counter">bigbrother.counter</li><li class="floating-toc-li" id="floating-toc_bigbrother.max-metrics">bigbrother.max-metrics</li><li class="floating-toc-li" id="floating-toc_bigbrother.metrics">bigbrother.metrics</li><li class="floating-toc-li" id="floating-toc_bigbrother.timer">bigbrother.timer</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>
|