├── .gitignore ├── README.md ├── autocomplete.rkt ├── info.rkt ├── main.rkt ├── static ├── css │ ├── gh-fork-ribbon.css │ └── tryrkt.css ├── img │ └── logo.png └── js │ ├── jquery-1.4.2.min.js │ ├── jquery.console.js │ └── tryrkt.js └── templates ├── about.html ├── home.html ├── links.html └── tutorial ├── binding.html ├── definitions.html ├── end.html ├── functions.html ├── go.html ├── intro.html ├── lists.html ├── macros.html ├── modules.html ├── objects.html ├── scope.html └── where.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *~ 3 | try-racket-serve-log.txt 4 | *.bak 5 | compiled/* 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | try-racket 2 | ========== 3 | 4 | **NOTE: This repo is no longer maintained** 5 | 6 | A web-based Racket REPL and tutorial. 7 | 8 | Try Racket is written in Racket and JavaScript with Chris Done's [jquery-console](https://github.com/chrisdone/jquery-console). 9 | 10 | It borrows a lot of code and content from [Try Clojure](http://www.tryclj.com/) and [paste.rkt](https://github.com/samth/paste.rkt). 11 | 12 | Slight additional modifications have since been made to remove dependencies on X11 by John Berry, with help from many others in the Racket community. Please note that the REPL and its server are still to some extent a work in progress, and community contribution is vigorously encouraged. Pull requests will likely be met with cheer, though we ask that you try to give it a little bit of testing before submitting (and we will do same as well before pushing to the live server). 13 | 14 | ## How to run it locally 15 | 16 | $ racket main.rkt 17 | 18 | Open http://localhost:8080 in your browser 19 | 20 | *NOTE:* Currently try-racket does not work properly on Windows/Mac platforms. It should run, but hosting is not recommended as surprising behaviors continue to be discovered. 21 | 22 | ## Online host 23 | 24 | try-racket is no longer hosted online due to server maintenance issues. 25 | 26 | ## License 27 | 28 | Copyright (c) 2013-2014 Emmanuel Delaborde 29 | 30 | try-racket is distributed under the [GNU Lesser General Public License 31 | (LGPL)](http://www.gnu.org/licenses/lgpl-3.0.html). 32 | 33 | You can modify it; if you distribute a modified version, you must 34 | distribute it under the terms of the LGPL, which in particular means 35 | that you must release the source code for the modified software. 36 | -------------------------------------------------------------------------------- /autocomplete.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | 3 | (require racket/list) 4 | (provide namespace-completion) 5 | 6 | ;;------------------------------------------------------------------ 7 | ;; Auto-completion 8 | ;;------------------------------------------------------------------ 9 | 10 | ;; efficiently convert symbols to byte strings 11 | (define symbol->bstring 12 | (let ([t (make-weak-hash)]) 13 | (lambda (sym) 14 | (or (hash-ref t sym #f) 15 | (let ([bstr (string->bytes/utf-8 (symbol->string sym))]) 16 | (hash-set! t sym bstr) 17 | bstr))))) 18 | 19 | ;; get a list of byte strings for current bindings, cache last result 20 | (define get-namespace-bstrings 21 | (let ([last-syms #f] [last-bstrs #f]) 22 | (lambda () 23 | (define syms (namespace-mapped-symbols)) 24 | (unless (equal? syms last-syms) 25 | (set! last-syms syms) 26 | (set! last-bstrs (sort (map symbol->bstring syms) bytesbytes/utf-8 pat) pat)] 34 | [pat (regexp-quote pat)] 35 | [pat (regexp-replace* #px#"(\\w)\\b" pat #"\\1\\\\w*")] 36 | [pat (byte-pregexp (bytes-append #"^" pat))]) 37 | (map bytes->string/utf-8 (filter (lambda (bstr) 38 | (regexp-match pat bstr)) 39 | (get-namespace-bstrings)))))) 40 | 41 | -------------------------------------------------------------------------------- /info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | (define collection "try-racket") 3 | -------------------------------------------------------------------------------- /main.rkt: -------------------------------------------------------------------------------- 1 | #lang racket/base 2 | (require web-server/servlet 3 | web-server/servlet-env 4 | web-server/templates 5 | web-server/dispatch 6 | web-server/http 7 | racket/sandbox 8 | json 9 | racket/format 10 | racket/dict 11 | racket/match 12 | racket/local 13 | racket/runtime-path 14 | web-server/managers/lru 15 | web-server/managers/manager 16 | file/convertible 17 | net/base64 18 | setup/dirs 19 | ; racket/gui/base ; ensures that `make-ev` does not try to instantiate it multiple times 20 | "autocomplete.rkt" 21 | ) 22 | 23 | (define APPLICATION/JSON-MIME-TYPE #"application/json;charset=utf-8") 24 | 25 | (module+ test (require rackunit)) 26 | 27 | ;; Force a check for the DLL dirs; work around for Windows and Mac compatibility 28 | (find-dll-dir) 29 | 30 | ;; Paths 31 | (define autocomplete 32 | (build-path (current-directory) "autocomplete.rkt")) 33 | 34 | ;;------------------------------------------------------------------ 35 | ;; sandbox 36 | ;;------------------------------------------------------------------ 37 | ;; make-ev : -> evaluator 38 | 39 | 40 | (define (make-ev) 41 | (parameterize ([sandbox-output 'string] 42 | [sandbox-error-output 'string] 43 | [sandbox-propagate-exceptions #f] 44 | [sandbox-memory-limit 30] 45 | [sandbox-eval-limits (list 5 30)] 46 | [sandbox-namespace-specs 47 | (append (sandbox-namespace-specs) 48 | `(file/convertible 49 | json 50 | setup/dirs))] 51 | [sandbox-path-permissions '((read #rx#"racket-prefs.rktd"))]) 52 | ((lambda () 53 | (make-evaluator 'racket/base 54 | #:requires `(pict 55 | pict/flash 56 | pict/code 57 | file/convertible 58 | json 59 | ,autocomplete 60 | (planet schematics/random:1:0/random))))))) 61 | 62 | 63 | (define (run-code ev str) 64 | (define reses ; Gather results into a list 65 | (call-with-values (λ () (ev str)) (λ xs xs))) 66 | (define out (get-output ev)) 67 | (define err (get-error-output ev)) 68 | (for/list ([res reses]) 69 | (cond [(convertible? res) 70 | (define res-convert (ev `(convert ',res 'png-bytes))) 71 | ;; run 'convert' in the sandbox for safety reasons 72 | (list (~v (bytes-append #"data:image/png;base64," 73 | (base64-encode res-convert #""))) 74 | #f #f)] 75 | [else (list (if (void? res) "" (format "~v" res)) 76 | (and (not (equal? out "")) out) 77 | (and (not (equal? err "")) err))]))) 78 | 79 | (define (complete-code ev str) 80 | (define res (ev `(jsexpr->string (namespace-completion ,str)))) 81 | (define out (get-output ev)) 82 | (define err (get-error-output ev)) 83 | (list (list (if (void? res) "" res) 84 | (and (not (equal? out "")) out) 85 | (and (not (equal? err "")) err)))) 86 | 87 | ;;------------------------------------------------------------------ 88 | ;; Routes 89 | ;;------------------------------------------------------------------ 90 | (define-values (dispatch urls) 91 | (dispatch-rules 92 | [("") home] 93 | [("home") home] 94 | [("links") links] 95 | [("about") about] 96 | [("tutorial") #:method "post" tutorial])) 97 | 98 | ;;------------------------------------------------------------------ 99 | ;; Responses 100 | ;;------------------------------------------------------------------ 101 | ;; make-response : ... string -> response 102 | (define (make-response 103 | #:code [code 200] 104 | #:message [message #"OK"] 105 | #:seconds [seconds (current-seconds)] 106 | #:mime-type [mime-type TEXT/HTML-MIME-TYPE] 107 | #:headers [headers (list (make-header #"Cache-Control" #"no-cache"))] 108 | content) 109 | (response/full code message seconds mime-type headers 110 | (list (string->bytes/utf-8 content)))) 111 | 112 | ;;------------------------------------------------------------------ 113 | ;; Request Handlers 114 | ;;------------------------------------------------------------------ 115 | ;; Tutorial pages 116 | (define (tutorial request) 117 | (define page (dict-ref (request-bindings request) 'page #f)) 118 | (make-response 119 | (match page 120 | ("intro" (include-template "templates/tutorial/intro.html")) 121 | ("go" (include-template "templates/tutorial/go.html")) 122 | ("definitions" (include-template "templates/tutorial/definitions.html")) 123 | ("binding" (include-template "templates/tutorial/binding.html")) 124 | ("functions" (include-template "templates/tutorial/functions.html")) 125 | ("scope" (include-template "templates/tutorial/scope.html")) 126 | ("lists" (include-template "templates/tutorial/lists.html")) 127 | ("modules" (include-template "templates/tutorial/modules.html")) 128 | ("macros" (include-template "templates/tutorial/macros.html")) 129 | ;("objects" (include-template "templates/tutorial/objects.html")) 130 | ("where" (include-template "templates/tutorial/where.html")) 131 | ("end" (include-template "templates/tutorial/end.html"))))) 132 | 133 | 134 | 135 | 136 | ;; Links page 137 | (define (links request) 138 | (make-response 139 | (include-template "templates/links.html"))) 140 | 141 | ;; About page 142 | (define (about request) 143 | (make-response 144 | (include-template "templates/about.html"))) 145 | 146 | ;; Home page 147 | (define (home request) 148 | (home-with (make-ev) request)) 149 | 150 | (define (home-with ev request) 151 | (local [(define (response-generator embed/url) 152 | (let ([url (embed/url next-eval)] 153 | ;[complete-url (embed/url next-complete)] 154 | ) 155 | (make-response 156 | (include-template "templates/home.html")))) 157 | (define (next-eval request) 158 | (eval-with ev request)) 159 | ;(define (next-complete request)(complete-with ev request)) 160 | ] 161 | (send/suspend/dispatch response-generator))) 162 | 163 | ;; string string -> jsexpr 164 | (define (json-error expr msg) 165 | (hasheq 'expr expr 'error #true 'message msg)) 166 | 167 | ;; string string -> jsexpr 168 | (define (json-result expr res) 169 | (hasheq 'expr expr 'result res)) 170 | 171 | ;; string (listof eval-result) -> (listof jsexpr) 172 | (define (result-json expr lsts) 173 | (for/list ([lst lsts]) 174 | (match lst 175 | [(list res #f #f) 176 | (json-result expr res)] 177 | [(list res out #f) 178 | (json-result expr (string-append out res))] 179 | [(list _ _ err) 180 | (json-error expr err)]))) 181 | 182 | 183 | (module+ test 184 | (define ev (make-ev)) 185 | ;; String -> (Listof String) 186 | ;; e.g. (values (+ 1 2) 4) ~> '("3" "4"), (modulo quotes) 187 | (define (eval-result-to-json expr) 188 | (for/list ([res (result-json "" (run-code ev expr))]) 189 | (jsexpr->string (hash-ref res 'result)))) 190 | ;; String -> String 191 | (define (eval-error-to-json expr) 192 | (match-define (list res) (result-json "" (run-code ev expr))) 193 | (jsexpr->string (hash-ref res 'message))) 194 | 195 | (check-equal? 196 | (eval-result-to-json "(+ 3 3)") (list "\"6\"")) 197 | (check-equal? 198 | (eval-result-to-json "(display \"6\")") (list "\"6\"")) 199 | (check-equal? 200 | (eval-result-to-json "(write \"6\")") (list "\"\\\"6\\\"\"")) 201 | (check-equal? 202 | (eval-result-to-json "(begin (display \"6 + \") \"6\")") (list "\"6 + \\\"6\\\"\"")) 203 | ) 204 | 205 | ;; Eval handler 206 | (define (eval-with ev request) 207 | (define bindings (request-bindings request)) 208 | (cond [(exists-binding? 'expr bindings) 209 | (let ([expr (extract-binding/single 'expr bindings)]) 210 | (make-response 211 | #:mime-type APPLICATION/JSON-MIME-TYPE 212 | (jsexpr->string (result-json expr (run-code ev expr)))))] 213 | [(exists-binding? 'complete bindings) 214 | (let ([str (extract-binding/single 'complete bindings)]) 215 | (make-response 216 | #:mime-type APPLICATION/JSON-MIME-TYPE 217 | (jsexpr->string 218 | (car (result-json "" (complete-code ev str))))))] 219 | [else (make-response #:code 400 #:message #"Bad Request" "")])) 220 | 221 | 222 | 223 | ;;------------------------------------------------------------------ 224 | ;; Server 225 | ;;------------------------------------------------------------------ 226 | (define (ajax? req) 227 | (string=? (dict-ref (request-headers req) 'x-requested-with "") 228 | "XMLHttpRequest")) 229 | 230 | (define (expiration-handler req) 231 | (if (ajax? req) 232 | (make-response 233 | #:mime-type APPLICATION/JSON-MIME-TYPE 234 | (jsexpr->string 235 | (json-error "" "Sorry, your session has expired. Please reload the page."))) 236 | (response/xexpr 237 | `(html (head (title "Page Has Expired.")) 238 | (body (p "Sorry, this page has expired. Please reload the page.")))))) 239 | 240 | 241 | (define-runtime-path static "./static") 242 | 243 | (define mgr 244 | (make-threshold-LRU-manager expiration-handler (* 256 1024 1024))) 245 | ; (create-LRU-manager expiration-handler 5 60 246 | ; (lambda () 247 | ; (define memory-use (current-memory-use)) 248 | ; (define collect? 249 | ; (or (>= memory-use (* 256 1024 1024)) (< memory-use 0))) 250 | ; collect?) 251 | ; #:initial-count 15 252 | ; #:inform-p (lambda args (void)))) 253 | 254 | (module+ main 255 | (serve/servlet 256 | dispatch 257 | #:stateless? #f 258 | #:launch-browser? #f 259 | #:connection-close? #t 260 | #:quit? #f 261 | #:listen-ip #f 262 | #:port 8080 263 | #:servlet-regexp #rx"" 264 | #:extra-files-paths (list static) 265 | #:servlet-path "/" 266 | #:manager mgr 267 | #:log-file "try-racket-serve-log.txt")) 268 | 269 | 270 | 271 | -------------------------------------------------------------------------------- /static/css/gh-fork-ribbon.css: -------------------------------------------------------------------------------- 1 | /* From https://github.com/simonwhitaker/github-fork-ribbon-css */ 2 | 3 | /* Left will inherit from right (so we don't need to duplicate code */ 4 | .github-fork-ribbon { 5 | /* The right and left lasses determine the side we attach our banner to */ 6 | position: absolute; 7 | 8 | /* Add a bit of padding to give some substance outside the "stitching" */ 9 | padding: 2px 0; 10 | 11 | /* Set the base colour */ 12 | background-color: #5881d8; 13 | 14 | /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */ 15 | background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.00)), to(rgba(0, 0, 0, 0.15))); 16 | background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 17 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 18 | background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 19 | background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 20 | background-image: linear-gradient(top, rgba(0, 0, 0, 0.00), rgba(0, 0, 0, 0.15)); 21 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#000000', EndColorStr='#000000'); 22 | 23 | /* Add a drop shadow */ 24 | -webkit-box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5); 25 | box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5); 26 | } 27 | .github-fork-ribbon a { 28 | /* Set the font */ 29 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 30 | font-size: 13px; 31 | font-weight: 700; 32 | color: white; 33 | 34 | /* Set the text properties */ 35 | text-decoration: none; 36 | text-shadow: 0 -1px rgba(0,0,0,0.5); 37 | text-align: center; 38 | 39 | /* Set the geometry. If you fiddle with these you'll also need to tweak the top and right values in #github-fork-ribbon. */ 40 | width: 200px; 41 | line-height: 20px; 42 | 43 | /* Set the layout properties */ 44 | display: inline-block; 45 | padding: 2px 0; 46 | 47 | /* Add "stitching" effect */ 48 | border-width: 1px 0; 49 | border-style: dotted; 50 | border-color: rgba(255,255,255,0.7); 51 | } 52 | 53 | .github-fork-ribbon-wrapper { 54 | width: 150px; 55 | height: 150px; 56 | position: absolute; 57 | overflow: hidden; 58 | top: 0; 59 | } 60 | 61 | .github-fork-ribbon-wrapper.right { 62 | right: 0; 63 | } 64 | 65 | .github-fork-ribbon-wrapper.right .github-fork-ribbon { 66 | top: 42px; 67 | right: -43px; 68 | 69 | /* Rotate the banner 45 degrees */ 70 | -webkit-transform: rotate(45deg); 71 | -moz-transform: rotate(45deg); 72 | -o-transform: rotate(45deg); 73 | transform: rotate(45deg); 74 | } 75 | -------------------------------------------------------------------------------- /static/css/tryrkt.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #fff; 3 | text-align: center; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | #wrapper { 9 | text-align: left; 10 | width: 1000px; 11 | margin: 0 auto; 12 | } 13 | 14 | #header { 15 | background: #000; 16 | font-family: Optima, Arial, sans-serif; 17 | font-weight: bold; 18 | padding: 0 0 5px 0; 19 | color: #fff; 20 | } 21 | 22 | #header h1 { 23 | height: 147px; 24 | line-height: 147px; 25 | margin: 0; 26 | padding: 0; 27 | padding-left: 85px; 28 | } 29 | 30 | #header h1 span{ 31 | display:inline; 32 | } 33 | 34 | #header h1 a { 35 | text-decoration:none; 36 | color:#fff; 37 | outline:none; 38 | } 39 | 40 | #console { 41 | float:right; 42 | width:500px; 43 | 44 | background: #eee; 45 | margin: 10px; 46 | } 47 | 48 | #console div.jquery-console-inner { 49 | width:100%; 50 | height:400px; 51 | margin: 10px 10px; 52 | overflow:auto; 53 | text-align:left; 54 | line-height: 1.2em; 55 | } 56 | #console div.jquery-console-message-value { 57 | color:#0066FF; 58 | font-family:monospace; 59 | padding:0.1em; 60 | } 61 | #console div.jquery-console-welcome 62 | { 63 | font-family:monospace; 64 | padding:0.1em; 65 | } 66 | #console div.jquery-console-prompt-box { 67 | color:#333; font-family:monospace; 68 | } 69 | #console div.jquery-console-focus span.jquery-console-cursor { 70 | background:#333; color:#eee; font-weight:bold; 71 | } 72 | #console div.jquery-console-message-error { 73 | color:#ef0505; font-family:monospace; 74 | padding:0.1em; 75 | white-space: pre; 76 | } 77 | #console div.jquery-console-message-success { 78 | color:#187718; font-family:monospace; 79 | padding:0.1em; 80 | } 81 | #console span.jquery-console-prompt-label { 82 | font-weight:bold; 83 | } 84 | 85 | 86 | #buttons { 87 | text-align: left; 88 | width: 620px; 89 | margin: 0 auto; 90 | } 91 | #buttons a { 92 | color: #fff; 93 | font-family: Optima, Arial, sans-serif; 94 | padding: 0em 1em; 95 | font-weight:normal; 96 | } 97 | 98 | #buttons a.last { 99 | margin-right: 0; 100 | } 101 | 102 | #buttons a:hover { 103 | color: #fff; 104 | cursor: pointer; 105 | background-color: #888888; 106 | } 107 | 108 | #changer { 109 | float:left; 110 | width:440px; 111 | margin: 10px; 112 | padding: 0.25em 0.5em 0.25em 0.5em; 113 | background: #E8E8FF; 114 | } 115 | 116 | #changer h3 { 117 | color: #555; 118 | } 119 | 120 | #changer p { 121 | background: transparent 122 | font-family: serif; 123 | color: #262680; 124 | } 125 | 126 | #changer code { 127 | background-color: #fff; 128 | white-space: pre; 129 | color: #444; 130 | font-family: monospace; 131 | padding: 0.1em 0.25em 0.2em 0.25em; 132 | } 133 | 134 | #changer code.expr { 135 | 136 | } 137 | 138 | div.continue { 139 | width: 100%; 140 | text-align: center; 141 | padding-top: 0.5em; 142 | } 143 | 144 | div.footer { 145 | text-align: center; 146 | } 147 | 148 | -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jarcane/try-racket/5037f8532f9add4bf9250211995b70a89e763e66/static/img/logo.png -------------------------------------------------------------------------------- /static/js/jquery-1.4.2.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery JavaScript Library v1.4.2 3 | * http://jquery.com/ 4 | * 5 | * Copyright 2010, John Resig 6 | * Dual licensed under the MIT or GPL Version 2 licenses. 7 | * http://jquery.org/license 8 | * 9 | * Includes Sizzle.js 10 | * http://sizzlejs.com/ 11 | * Copyright 2010, The Dojo Foundation 12 | * Released under the MIT, BSD, and GPL Licenses. 13 | * 14 | * Date: Sat Feb 13 22:33:48 2010 -0500 15 | */ 16 | (function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, 21 | Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& 22 | (d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, 23 | a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== 24 | "find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, 25 | function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; 34 | var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, 35 | parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= 36 | false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= 37 | s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, 38 | applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; 39 | else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, 40 | a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== 41 | w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, 42 | cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= 47 | c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); 48 | a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, 49 | function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); 50 | k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), 51 | C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= 53 | e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& 54 | f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; 55 | if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", 63 | e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, 64 | "_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, 65 | d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, 71 | e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); 72 | t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| 73 | g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, 80 | CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, 81 | g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, 82 | text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, 83 | setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= 84 | h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== 86 | "="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, 87 | h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& 90 | q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; 91 | if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); 92 | (function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: 93 | function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= 96 | {},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== 97 | "string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", 98 | d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? 99 | a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== 100 | 1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= 102 | c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, 103 | wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, 104 | prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, 105 | this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); 106 | return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, 107 | ""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); 111 | return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", 112 | ""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= 113 | c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? 114 | c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= 115 | function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= 116 | Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, 117 | "border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= 118 | a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= 119 | a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== 120 | "string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, 121 | serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), 122 | function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, 123 | global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& 124 | e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? 125 | "&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== 126 | false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= 127 | false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", 128 | c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| 129 | d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); 130 | g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== 131 | 1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== 132 | "json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; 133 | if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== 139 | "number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| 140 | c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; 141 | this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= 142 | this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, 143 | e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; 149 | a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); 150 | c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, 151 | d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- 152 | f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": 153 | "pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in 154 | e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); 155 | -------------------------------------------------------------------------------- /static/js/jquery.console.js: -------------------------------------------------------------------------------- 1 | // JQuery Console 1.0 2 | // Sun Feb 21 20:28:47 GMT 2010 3 | // 4 | // Copyright 2010 Chris Done, Simon David Pratt. All rights reserved. 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions 8 | // are met: 9 | // 10 | // 1. Redistributions of source code must retain the above 11 | // copyright notice, this list of conditions and the following 12 | // disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following 16 | // disclaimer in the documentation and/or other materials 17 | // provided with the distribution. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 | // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 | // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | // POSSIBILITY OF SUCH DAMAGE. 31 | 32 | // TESTED ON 33 | // Internet Explorer 6 34 | // Opera 10.01 35 | // Chromium 4.0.237.0 (Ubuntu build 31094) 36 | // Firefox 3.5.8, 3.6.2 (Mac) 37 | // Safari 4.0.5 (6531.22.7) (Mac) 38 | // Google Chrome 5.0.375.55 (Mac) 39 | 40 | (function($){ 41 | $.fn.console = function(config){ 42 | //////////////////////////////////////////////////////////////////////// 43 | // Constants 44 | // Some are enums, data types, others just for optimisation 45 | var keyCodes = { 46 | // left 47 | 37: moveBackward, 48 | // right 49 | 39: moveForward, 50 | // up 51 | 38: previousHistory, 52 | // down 53 | 40: nextHistory, 54 | // backspace 55 | 8: backDelete, 56 | // delete 57 | 46: forwardDelete, 58 | // end 59 | 35: moveToEnd, 60 | // start 61 | 36: moveToStart, 62 | // return 63 | 13: commandTrigger, 64 | // tab 65 | 18: doNothing, 66 | // tab 67 | 9: doComplete 68 | }; 69 | var ctrlCodes = { 70 | // C-a 71 | 65: moveToStart, 72 | // C-e 73 | 69: moveToEnd, 74 | // C-d 75 | 68: forwardDelete, 76 | // C-n 77 | 78: nextHistory, 78 | // C-p 79 | 80: previousHistory, 80 | // C-b 81 | 66: moveBackward, 82 | // C-f 83 | 70: moveForward, 84 | // C-k 85 | 75: deleteUntilEnd 86 | }; 87 | var altCodes = { 88 | // M-f 89 | 70: moveToNextWord, 90 | // M-b 91 | 66: moveToPreviousWord, 92 | // M-d 93 | 68: deleteNextWord 94 | }; 95 | var cursor = ' '; 96 | 97 | //////////////////////////////////////////////////////////////////////// 98 | // Globals 99 | var container = $(this); 100 | var inner = $('
'); 101 | // erjiang: changed this from a text input to a textarea so we 102 | // can get pasted newlines 103 | var typer = $(''); 104 | // Prompt 105 | var promptBox; 106 | var prompt; 107 | var promptLabel = config && config.promptLabel? config.promptLabel : "> "; 108 | var continuedPromptLabel = config && config.continuedPromptLabel? 109 | config.continuedPromptLabel : "> "; 110 | var promptIndent = " ".substring(15-promptLabel.length); // a string of spaces 111 | var column = 0; 112 | var promptText = ''; 113 | var restoreText = ''; 114 | var continuedText = ''; 115 | // Prompt history stack 116 | var history = []; 117 | var ringn = 0; 118 | // For reasons unknown to The Sword of Michael himself, Opera 119 | // triggers and sends a key character when you hit various 120 | // keys like PgUp, End, etc. So there is no way of knowing 121 | // when a user has typed '#' or End. My solution is in the 122 | // typer.keydown and typer.keypress functions; I use the 123 | // variable below to ignore the keypress event if the keydown 124 | // event succeeds. 125 | var cancelKeyPress = 0; 126 | // When this value is false, the prompt will not respond to input 127 | var acceptInput = true; 128 | // When this value is true, the command has been canceled 129 | var cancelCommand = false; 130 | 131 | // External exports object 132 | var extern = {}; 133 | 134 | //////////////////////////////////////////////////////////////////////// 135 | // Main entry point 136 | (function(){ 137 | container.append(inner); 138 | inner.append(typer); 139 | typer.css({position:'absolute',top:0,left:'-9999px'}); 140 | if (config.welcomeMessage) 141 | message(config.welcomeMessage,'jquery-console-welcome'); 142 | newPromptBox(); 143 | if (config.autofocus) { 144 | inner.addClass('jquery-console-focus'); 145 | typer.focus(); 146 | setTimeout(function(){ 147 | inner.addClass('jquery-console-focus'); 148 | typer.focus(); 149 | },100); 150 | } 151 | extern.inner = inner; 152 | extern.typer = typer; 153 | extern.scrollToBottom = scrollToBottom; 154 | })(); 155 | 156 | //////////////////////////////////////////////////////////////////////// 157 | // Reset terminal 158 | extern.reset = function(){ 159 | var welcome = (typeof config.welcomeMessage != 'undefined'); 160 | inner.parent().fadeOut(function(){ 161 | inner.find('div').each(function(){ 162 | if (!welcome) { 163 | $(this).remove(); 164 | } else { 165 | welcome = false; 166 | } 167 | }); 168 | newPromptBox(); 169 | inner.parent().fadeIn(function(){ 170 | inner.addClass('jquery-console-focus'); 171 | typer.focus(); 172 | }); 173 | }); 174 | }; 175 | 176 | //////////////////////////////////////////////////////////////////////// 177 | // Reset terminal 178 | extern.notice = function(msg,style){ 179 | var n = $('
').append($('
').text(msg)) 180 | .css({visibility:'hidden'}); 181 | container.append(n); 182 | var focused = true; 183 | if (style=='fadeout') 184 | setTimeout(function(){ 185 | n.fadeOut(function(){ 186 | n.remove(); 187 | }); 188 | },4000); 189 | else if (style=='prompt') { 190 | var a = $('
'); 191 | n.append(a); 192 | focused = false; 193 | a.click(function(){ n.fadeOut(function(){ n.remove();inner.css({opacity:1}) }); }); 194 | } 195 | var h = n.height(); 196 | n.css({height:'0px',visibility:'visible'}) 197 | .animate({height:h+'px'},function(){ 198 | if (!focused) inner.css({opacity:0.5}); 199 | }); 200 | n.css('cursor','default'); 201 | return n; 202 | }; 203 | 204 | //////////////////////////////////////////////////////////////////////// 205 | // Make a new prompt box 206 | function newPromptBox() { 207 | column = 0; 208 | promptText = ''; 209 | ringn = 0; // Reset the position of the history ring 210 | enableInput(); 211 | promptBox = $('
'); 212 | var label = $(''); 213 | var labelText = extern.continuedPrompt? continuedPromptLabel : promptLabel; 214 | promptBox.append(label.text(labelText).show()); 215 | label.html(label.html().replace(' ',' ')); 216 | prompt = $(''); 217 | promptBox.append(prompt); 218 | inner.append(promptBox); 219 | updatePromptDisplay(); 220 | }; 221 | 222 | //////////////////////////////////////////////////////////////////////// 223 | // Handle setting focus 224 | container.click(function(){ 225 | inner.addClass('jquery-console-focus'); 226 | inner.removeClass('jquery-console-nofocus'); 227 | if ($.browser.webkit) { 228 | typer.focusWithoutScrolling(); 229 | } else { 230 | typer.css('position', 'fixed').focus(); 231 | } 232 | scrollToBottom(); 233 | return false; 234 | }); 235 | 236 | //////////////////////////////////////////////////////////////////////// 237 | // Handle losing focus 238 | typer.blur(function(){ 239 | inner.removeClass('jquery-console-focus'); 240 | inner.addClass('jquery-console-nofocus'); 241 | }); 242 | 243 | //////////////////////////////////////////////////////////////////////// 244 | // Bind to the paste event of the input box so we know when we 245 | // get pasted data 246 | typer.bind('paste', function(e) { 247 | // wipe typer input clean just in case 248 | typer.val(""); 249 | // this timeout is required because the onpaste event is 250 | // fired *before* the text is actually pasted 251 | setTimeout(function() { 252 | typer.consoleInsert(indentNextLines(typer.val())); 253 | typer.val(""); 254 | }, 0); 255 | }); 256 | 257 | //////////////////////////////////////////////////////////////////////// 258 | // Handle key hit before translation 259 | // For picking up control characters like up/left/down/right 260 | 261 | typer.keydown(function(e){ 262 | cancelKeyPress = 0; 263 | var keyCode = e.keyCode; 264 | // C-c: cancel the execution 265 | if(e.ctrlKey && keyCode == 67) { 266 | cancelKeyPress = keyCode; 267 | cancelExecution(); 268 | return false; 269 | } 270 | 271 | // Shit-Enter: soft return 272 | if(e.shiftKey && keyCode == 13) { 273 | cancelKeyPress = keyCode; 274 | cancelExecution(); 275 | 276 | return false; 277 | 278 | } 279 | if (acceptInput) { 280 | if (keyCode in keyCodes) { 281 | cancelKeyPress = keyCode; 282 | (keyCodes[keyCode])(); 283 | return false; 284 | } else if (e.ctrlKey && keyCode in ctrlCodes) { 285 | cancelKeyPress = keyCode; 286 | (ctrlCodes[keyCode])(); 287 | return false; 288 | } else if (e.altKey && keyCode in altCodes) { 289 | cancelKeyPress = keyCode; 290 | (altCodes[keyCode])(); 291 | return false; 292 | } 293 | } 294 | }); 295 | 296 | //////////////////////////////////////////////////////////////////////// 297 | // Handle key press 298 | typer.keypress(function(e){ 299 | var keyCode = e.keyCode || e.which; 300 | if (isIgnorableKey(e)) { 301 | return false; 302 | } 303 | // // C-v: don't insert on paste event 304 | if ((e.ctrlKey || e.metaKey) && String.fromCharCode(keyCode).toLowerCase() == 'v') { 305 | return true; 306 | } 307 | if (acceptInput && cancelKeyPress != keyCode && keyCode >= 32){ 308 | if (cancelKeyPress) return false; 309 | if (typeof config.charInsertTrigger == 'undefined' || 310 | (typeof config.charInsertTrigger == 'function' && 311 | config.charInsertTrigger(keyCode,promptText))) 312 | typer.consoleInsert(keyCode); 313 | } 314 | if ($.browser.webkit) return false; 315 | }); 316 | 317 | function isIgnorableKey(e) { 318 | // for now just filter alt+tab that we receive on some platforms when 319 | // user switches windows (goes away from the browser) 320 | return ((e.keyCode == keyCodes.tab || e.keyCode == 192) && e.altKey); 321 | }; 322 | 323 | //////////////////////////////////////////////////////////////////////// 324 | // Rotate through the command history 325 | function rotateHistory(n){ 326 | if (history.length == 0) return; 327 | ringn += n; 328 | if (ringn < 0) ringn = history.length; 329 | else if (ringn > history.length) ringn = 0; 330 | var prevText = promptText; 331 | if (ringn == 0) { 332 | promptText = restoreText; 333 | } else { 334 | promptText = history[ringn - 1]; 335 | } 336 | if (config.historyPreserveColumn) { 337 | if (promptText.length < column + 1) { 338 | column = promptText.length; 339 | } else if (column == 0) { 340 | column = promptText.length; 341 | } 342 | } else { 343 | column = promptText.length; 344 | } 345 | updatePromptDisplay(); 346 | }; 347 | 348 | function previousHistory() { 349 | rotateHistory(-1); 350 | }; 351 | 352 | function nextHistory() { 353 | rotateHistory(1); 354 | }; 355 | 356 | // Add something to the history ring 357 | function addToHistory(line){ 358 | history.push(line); 359 | restoreText = ''; 360 | }; 361 | 362 | // Delete the character at the current position 363 | function deleteCharAtPos(){ 364 | if (column < promptText.length){ 365 | promptText = 366 | promptText.substring(0,column) + 367 | promptText.substring(column+1); 368 | restoreText = promptText; 369 | return true; 370 | } else return false; 371 | }; 372 | 373 | function backDelete() { 374 | if (moveColumn(-1)){ 375 | deleteCharAtPos(); 376 | updatePromptDisplay(); 377 | } 378 | }; 379 | 380 | function forwardDelete() { 381 | if (deleteCharAtPos()) 382 | updatePromptDisplay(); 383 | }; 384 | 385 | function deleteUntilEnd() { 386 | while(deleteCharAtPos()) { 387 | updatePromptDisplay(); 388 | } 389 | }; 390 | 391 | function deleteNextWord() { 392 | // A word is defined within this context as a series of alphanumeric 393 | // characters. 394 | // Delete up to the next alphanumeric character 395 | while(column < promptText.length && 396 | !isCharAlphanumeric(promptText[column])) { 397 | deleteCharAtPos(); 398 | updatePromptDisplay(); 399 | } 400 | // Then, delete until the next non-alphanumeric character 401 | while(column < promptText.length && 402 | isCharAlphanumeric(promptText[column])) { 403 | deleteCharAtPos(); 404 | updatePromptDisplay(); 405 | } 406 | }; 407 | 408 | //////////////////////////////////////////////////////////////////////// 409 | // Validate command and trigger it if valid, or show a validation error 410 | function commandTrigger() { 411 | var line = promptText; 412 | if (typeof config.commandValidate == 'function') { 413 | var ret = config.commandValidate(line); 414 | if (ret == true || ret == false) { 415 | if (ret) { 416 | handleCommand(); 417 | } 418 | } else { 419 | commandResult(ret,"jquery-console-message-error"); 420 | } 421 | } else { 422 | handleCommand(); 423 | } 424 | }; 425 | 426 | // Scroll to the bottom of the view 427 | function scrollToBottom() { 428 | if (jQuery.fn.jquery > "1.6") { 429 | inner.prop({ scrollTop: inner.prop("scrollHeight") }); 430 | } 431 | else { 432 | inner.attr({ scrollTop: inner.attr("scrollHeight") }); 433 | } 434 | }; 435 | 436 | function cancelExecution() { 437 | if(typeof config.cancelHandle == 'function') { 438 | config.cancelHandle(); 439 | } 440 | } 441 | 442 | //////////////////////////////////////////////////////////////////////// 443 | // Handle a command 444 | function handleCommand(){ 445 | if (typeof config.commandHandle == 'function') { 446 | disableInput(); 447 | addToHistory(promptText); 448 | var text = promptText; 449 | if (extern.continuedPrompt) { 450 | if (continuedText) 451 | continuedText += '\n' + promptText; 452 | else continuedText = promptText; 453 | } else continuedText = undefined; 454 | if (continuedText) text = continuedText; 455 | var ret = config.commandHandle(text,function(msgs){ 456 | commandResult(msgs); 457 | }); 458 | if (extern.continuedPrompt && !continuedText) 459 | continuedText = promptText; 460 | if (typeof ret == 'boolean') { 461 | if (ret) { 462 | // Command succeeded without a result. 463 | commandResult(); 464 | } else { 465 | commandResult('Command failed.', 466 | "jquery-console-message-error"); 467 | } 468 | } else if (typeof ret == "string") { 469 | commandResult(ret,"jquery-console-message-success"); 470 | } else if (typeof ret == 'object' && ret.length) { 471 | commandResult(ret); 472 | } else if (extern.continuedPrompt) { 473 | commandResult(); 474 | } 475 | } 476 | }; 477 | 478 | //////////////////////////////////////////////////////////////////////// 479 | // Disable input 480 | function disableInput() { 481 | acceptInput = false; 482 | }; 483 | 484 | // Enable input 485 | function enableInput() { 486 | acceptInput = true; 487 | } 488 | 489 | //////////////////////////////////////////////////////////////////////// 490 | // Reset the prompt in invalid command 491 | extern.commandResult = commandResult; 492 | function commandResult(msg,className) { 493 | column = -1; 494 | updatePromptDisplay(); 495 | if (typeof msg == 'string') { 496 | message(msg,className); 497 | } else if ($.isArray(msg)) { 498 | for (var x in msg) { 499 | var ret = msg[x]; 500 | message(ret.msg,ret.className); 501 | } 502 | } else { // Assume it's a DOM node or jQuery object. 503 | inner.append(msg); 504 | } 505 | newPromptBox(); 506 | }; 507 | 508 | //////////////////////////////////////////////////////////////////////// 509 | // Display a message 510 | function message(msg,className) { 511 | var mesg = $('
'); 512 | if (className) mesg.addClass(className); 513 | mesg.filledText(msg).hide(); 514 | inner.append(mesg); 515 | mesg.show(); 516 | }; 517 | 518 | //////////////////////////////////////////////////////////////////////// 519 | // Handle normal character insertion 520 | // data can either be a number, which will be interpreted as the 521 | // numeric value of a single character, or a string 522 | typer.consoleInsert = function(data){ 523 | // TODO: remove redundant indirection 524 | var text = isNaN(data) ? data : String.fromCharCode(data); 525 | var before = promptText.substring(0,column); 526 | var after = promptText.substring(column); 527 | promptText = before + text + after; 528 | moveColumn(text.length); 529 | restoreText = promptText; 530 | updatePromptDisplay(); 531 | }; 532 | 533 | //////////////////////////////////////////////////////////////////////// 534 | // Move to another column relative to this one 535 | // Negative means go back, positive means go forward. 536 | function moveColumn(n){ 537 | if (column + n >= 0 && column + n <= promptText.length){ 538 | column += n; 539 | return true; 540 | } else return false; 541 | }; 542 | 543 | function moveForward() { 544 | if(moveColumn(1)) { 545 | updatePromptDisplay(); 546 | return true; 547 | } 548 | return false; 549 | }; 550 | 551 | function moveBackward() { 552 | if(moveColumn(-1)) { 553 | updatePromptDisplay(); 554 | return true; 555 | } 556 | return false; 557 | }; 558 | 559 | function moveToStart() { 560 | if (moveColumn(-column)) 561 | updatePromptDisplay(); 562 | }; 563 | 564 | function moveToEnd() { 565 | if (moveColumn(promptText.length-column)) 566 | updatePromptDisplay(); 567 | }; 568 | 569 | function moveToNextWord() { 570 | while(column < promptText.length && 571 | !isCharAlphanumeric(promptText[column]) && 572 | moveForward()) { 573 | } 574 | while(column < promptText.length && 575 | isCharAlphanumeric(promptText[column]) && 576 | moveForward()) { 577 | } 578 | }; 579 | 580 | function moveToPreviousWord() { 581 | // Move backward until we find the first alphanumeric 582 | while(column -1 >= 0 && 583 | !isCharAlphanumeric(promptText[column-1]) && 584 | moveBackward()) { 585 | } 586 | // Move until we find the first non-alphanumeric 587 | while(column -1 >= 0 && 588 | isCharAlphanumeric(promptText[column-1]) && 589 | moveBackward()) { 590 | } 591 | }; 592 | 593 | function isCharAlphanumeric(charToTest) { 594 | if(typeof charToTest == 'string') { 595 | var code = charToTest.charCodeAt(); 596 | return (code >= 'A'.charCodeAt() && code <= 'Z'.charCodeAt()) || 597 | (code >= 'a'.charCodeAt() && code <= 'z'.charCodeAt()) || 598 | (code >= '0'.charCodeAt() && code <= '9'.charCodeAt()); 599 | } 600 | return false; 601 | }; 602 | 603 | function doComplete() { 604 | if(typeof config.completeHandle == 'function') { 605 | var completions = config.completeHandle(promptText); 606 | var len = completions.length; 607 | if (len === 1) { 608 | extern.promptText(/* promptText + */ completions[0]); 609 | } else if (len > 1 && config.cols) { 610 | var prompt = promptText; 611 | // Compute the number of rows that will fit in the width 612 | var max = 0; 613 | for (var i = 0;i < len;i++) { 614 | max = Math.max(max, completions[i].length); 615 | } 616 | max += 2; 617 | var n = Math.floor(config.cols / max); 618 | var buffer = ""; 619 | var col = 0; 620 | for (i = 0;i < len;i++) { 621 | var completion = completions[i]; 622 | buffer += completions[i]; 623 | for (var j = completion.length;j < max;j++) { 624 | buffer += " "; 625 | } 626 | if (++col >= n) { 627 | buffer += "\n"; 628 | col = 0; 629 | } 630 | } 631 | commandResult(buffer,"jquery-console-message-value"); 632 | extern.promptText(prompt); 633 | } 634 | } 635 | }; 636 | 637 | function doNothing() {}; 638 | 639 | // extra spaces to line-up subsequent lines with the 'prompt-line' 640 | function indentNextLines(text){ return text.replace(/\n/g, '\n' + promptIndent) }; 641 | extern.promptText = function(text){ 642 | if (text) { 643 | text = indentNextLines(text); 644 | promptText = text; 645 | column = promptText.length; 646 | updatePromptDisplay(); 647 | } 648 | return promptText; 649 | }; 650 | 651 | //////////////////////////////////////////////////////////////////////// 652 | // Update the prompt display 653 | function updatePromptDisplay(){ 654 | var line = promptText; 655 | var html = ''; 656 | if (column > 0 && line == ''){ 657 | // When we have an empty line just display a cursor. 658 | html = cursor; 659 | } else if (column == promptText.length){ 660 | // We're at the end of the line, so we need to display 661 | // the text *and* cursor. 662 | html = htmlEncode(line) + cursor; 663 | } else { 664 | // Grab the current character, if there is one, and 665 | // make it the current cursor. 666 | var before = line.substring(0, column); 667 | var current = line.substring(column,column+1); 668 | if (current){ 669 | current = 670 | '' + 671 | htmlEncode(current) + 672 | ''; 673 | } 674 | var after = line.substring(column+1); 675 | html = htmlEncode(before) + current + htmlEncode(after); 676 | } 677 | prompt.html(html); 678 | scrollToBottom(); 679 | }; 680 | 681 | // Simple HTML encoding 682 | // Simply replace '<', '>' and '&' 683 | // TODO: Use jQuery's .html() trick, or grab a proper, fast 684 | // HTML encoder. 685 | function htmlEncode(text){ 686 | return ( 687 | text.replace(/&/g,'&') 688 | .replace(/') 692 | ); 693 | }; 694 | 695 | return extern; 696 | }; 697 | // Simple utility for printing messages 698 | $.fn.filledText = function(txt){ 699 | $(this).text(txt); 700 | $(this).html($(this).html().replace(/\n/g,'
')); 701 | return this; 702 | }; 703 | 704 | // Alternative method for focus without scrolling 705 | $.fn.focusWithoutScrolling = function(){ 706 | var x = window.scrollX, y = window.scrollY; 707 | $(this).focus(); 708 | window.scrollTo(x, y); 709 | }; 710 | })(jQuery); 711 | -------------------------------------------------------------------------------- /static/js/tryrkt.js: -------------------------------------------------------------------------------- 1 | var currentPage = -1; 2 | var pages = [ 3 | "intro", 4 | "go", 5 | "definitions", 6 | "binding", 7 | "functions", 8 | "scope", 9 | "lists", 10 | "modules", 11 | "macros", 12 | //"objects", 13 | "where", 14 | "end" 15 | ]; 16 | var pageExitConditions = [ 17 | { 18 | verify: function(data) { return false; } 19 | }, 20 | { 21 | verify: function(data) { return data.expr == "(hc-append (circle 10) (rectangle 10 20))"; } 22 | }, 23 | { 24 | verify: function(data) { return data.expr == "(square 10)"; } 25 | }, 26 | { 27 | verify: function(data) { return data.expr == "(checkerboard (square 10))"; } 28 | }, 29 | { 30 | verify: function(data) { return false; } 31 | }, 32 | { 33 | verify: function (data) { return false; } 34 | }, 35 | { 36 | verify: function (data) { return false; } 37 | }, 38 | { 39 | verify: function (data) { return false;} 40 | }, 41 | { 42 | verify: function (data) { return false; } 43 | }, 44 | { 45 | verify: function (data) { return false; } 46 | }, 47 | { 48 | verify: function (data) { return false; } 49 | }, 50 | { 51 | verify: function (data) { return false; } 52 | } 53 | ]; 54 | 55 | function goToPage(pageNumber) { 56 | if (pageNumber == currentPage || pageNumber < 0 || pageNumber >= pages.length) { 57 | return; 58 | } 59 | 60 | currentPage = pageNumber; 61 | 62 | var block = $("#changer"); 63 | block.fadeOut(function(e) { 64 | block.load("/tutorial", { 'page' : pages[pageNumber] }, function() { 65 | block.fadeIn(); 66 | changerUpdated(); 67 | }); 68 | }); 69 | } 70 | 71 | function setupLink(url) { 72 | return function(e) { $("#changer").load(url, function(data) { $("#changer").html(data); }); } 73 | } 74 | 75 | function setupExamples(controller) { 76 | $(".code").click(function(e) { 77 | controller.promptText($(this).text()); 78 | }); 79 | } 80 | 81 | function getStep(n, controller) { 82 | $("#tuttext").load("tutorial", { step: n }, function() { setupExamples(controller); }); 83 | } 84 | 85 | 86 | function eval_racket(code) { 87 | var data; 88 | $.ajax({ 89 | url: evalUrl, 90 | data: { expr : code }, 91 | async: false, 92 | success: function(res) { data = res; }, 93 | }); 94 | return data; 95 | } 96 | 97 | function complete_racket(str){ 98 | var data; 99 | $.ajax({ 100 | url: evalUrl, 101 | data: { complete : str }, 102 | async: false, 103 | success: function(res) { data = res; }, 104 | }); 105 | return data; 106 | } 107 | 108 | function doCommand(input) { 109 | if (input.match(/^gopage /)) { 110 | goToPage(parseInt(input.substring("gopage ".length))); 111 | return true; 112 | } 113 | 114 | switch (input) { 115 | case 'next': 116 | case 'forward': 117 | goToPage(currentPage + 1); 118 | return true; 119 | case 'previous': 120 | case 'prev': 121 | case 'back': 122 | goToPage(currentPage - 1); 123 | return true; 124 | case 'restart': 125 | case 'reset': 126 | case 'home': 127 | case 'quit': 128 | goToPage(0); 129 | return true; 130 | default: 131 | return false; 132 | } 133 | } 134 | 135 | function onValidate(input) { 136 | return (input != ""); 137 | } 138 | 139 | function onComplete(line) { 140 | var input = $.trim(line); 141 | // get the prefix that won't be completed 142 | var prefix = line.replace(RegExp("(\\w|[-])*$"), ""); 143 | var data = complete_racket(input); 144 | 145 | // handle error 146 | if (data.error) { 147 | controller.commandResult(data.message, "jquery-console-message-error"); 148 | return []; 149 | } 150 | else { 151 | var res = JSON.parse(data.result); 152 | for (var i = 0; i= 0 && pageExitConditions[currentPage].verify(data)) { 178 | goToPage(currentPage + 1); 179 | } 180 | // display expr results 181 | if(/#\"data:image\/png;base64,/.test(data.result)){ 182 | $('.jquery-console-inner').append('
"); 183 | controller.scrollToBottom(); 184 | results.push({msg: "", className: "jquery-console-message-value"}); 185 | } else { 186 | results.push({msg: data.result, className: "jquery-console-message-value"}); 187 | } 188 | } 189 | return results; 190 | } 191 | 192 | /** 193 | * This should be called anytime the changer div is updated so it can rebind event listeners. 194 | * Currently this is just to make the code elements clickable. 195 | */ 196 | function changerUpdated() { 197 | $("#changer code.expr").each(function() { 198 | $(this).css("cursor", "pointer"); 199 | $(this).attr("title", "Click to insert '" + $(this).text() + "' into the console."); 200 | $(this).click(function(e) { 201 | controller.promptText($(this).text()); 202 | controller.inner.click(); 203 | // trigger Enter 204 | var e = jQuery.Event("keydown"); 205 | e.keyCode = 13; 206 | controller.typer.trigger(e); 207 | }); 208 | }); 209 | } 210 | 211 | var controller; 212 | $(document).ready(function() { 213 | controller = $("#console").console({ 214 | welcomeMessage:'Make some Racket!', 215 | promptLabel: '> ', 216 | commandValidate: onValidate, 217 | commandHandle: onHandle, 218 | completeHandle: onComplete, 219 | autofocus:true, 220 | animateScroll:true, 221 | promptHistory:true, 222 | cols:1 223 | }); 224 | $("#about").click(setupLink("about")); 225 | $("#links").click(setupLink("links")); 226 | changerUpdated(); 227 | }); 228 | -------------------------------------------------------------------------------- /templates/about.html: -------------------------------------------------------------------------------- 1 |

2 | Welcome to Try Racket - a quick tour of Racket for absolute beginners. 3 |

4 |

5 | Here is our only disclaimer: this site is an introduction to Racket, not a Racket REPL. 6 | You won't be able to do everything in it that you could do in your local interpreter. 7 | 8 |

9 |

10 | "Try Racket" is written in Racket and JavaScript with 11 | Chris Done's jquery-console. 12 | It borrows a lot of code and content from Try Clojure and paste.rkt. 13 | Hosting is provided by John Berry, who is also the current maintainer of the project. 14 |

15 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Try Racket 4 | 5 | 6 | 7 | 8 | 28 | 29 |
30 |
31 |
32 | Fork me on GitHub 33 |
34 |
35 |
36 |
37 |
38 | 39 |
40 |

Welcome to Racket! You can see a Racket interpreter on the right - we call it a REPL.

41 |

Type next in the REPL to begin the tutorial.

42 |
43 |
44 | 45 |
46 |
47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /templates/links.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /templates/tutorial/binding.html: -------------------------------------------------------------------------------- 1 |

Local Binding

2 | 3 |

The define form can be used in some places to create local bindings. For example, it can be used inside a function body:

4 | 5 |

(define (four p) 6 | (define two-p (hc-append p p)) 7 | (vc-append two-p two-p))

8 | 9 |

(four (circle 10))

10 | 11 |

More typically, Racketeers use the let or let* form for local binding. An advantage of let is that it can be used in any expression position. Also, it binds many identifiers at once, instead of requiring a separate define for each identifier:

12 | 13 |

(define (checker p1 p2) 14 | (let ([p12 (hc-append p1 p2)] 15 | [p21 (hc-append p2 p1)]) 16 | (vc-append p12 p21)))

17 | 18 |

(checker (colorize (square 10) "red") 19 | (colorize (square 10) "black"))

20 | 21 |

A let form binds many identifiers at the same time, so the bindings cannot refer to each other. The let* form, in contrast, allows later bindings to use earlier bindings:

22 | 23 |

(define (checkerboard p) 24 | (let* ([rp (colorize p "red")] 25 | [bp (colorize p "black")] 26 | [c (checker rp bp)] 27 | [c4 (four c)]) 28 | (four c4)))

29 | 30 |

(checkerboard (square 10))

31 | -------------------------------------------------------------------------------- /templates/tutorial/definitions.html: -------------------------------------------------------------------------------- 1 |

Definitions

2 | 3 |

To use a particular circle and rectangle picture many times, it’s simpler to give them names. Let's add two definitions:

4 | 5 |

(define c (circle 10))

6 |

(define r (rectangle 10 20))

7 | 8 |

Then click Enter again. Now, you can just type c or r:

9 | 10 |

r

11 | 12 |

(hc-append c r)

13 | 14 |

(hc-append 20 c r c)

15 | 16 |

As you can see, the hc-append function accepts an optional number argument before the picture arguments, and it accepts any number of picture arguments. When a number is provided, it specifies the amount of space to add between pictures.

17 | 18 |

Let’s add a function definition to the program. A function definition uses define, just like our shape definitions, but with an open parenthesis before the function name, and names for the function arguments before the matching close parenthesis:

19 | 20 |

(define (square n) 21 | ; A semi-colon starts a line comment. 22 | ; The expression below is the function body. 23 | (filled-rectangle n n))

24 | 25 |

The syntax of the definition mirrors the syntax of a function call:

26 | 27 |

(square 10)

28 | -------------------------------------------------------------------------------- /templates/tutorial/end.html: -------------------------------------------------------------------------------- 1 |

2 | Glad to know you're eager for more, but unfortunately this tutorial is over. 3 |

4 | 5 |

6 | Maybe you can click the 'links' button above for more resources? 7 |

8 | -------------------------------------------------------------------------------- /templates/tutorial/functions.html: -------------------------------------------------------------------------------- 1 |

Functions are Values

2 | 3 |

Instead of calling circle as a function, try evaluating just circle as an expression:

4 | 5 | circle 6 | 7 |

The identifier circle is bound to a function (a.k.a. “procedure”), just like c is bound to a circle. Unlike a circle picture, there’s not a simple way of completely printing the function, so Racket just prints #.

8 | 9 |

This example shows that functions are values, just like numbers and pictures (even if they don’t print as nicely). Since functions are values, you can define functions that expect other functions as arguments:

10 | 11 |

(define (series mk) 12 | (hc-append 4 (mk 5) (mk 10) (mk 20)))

13 | 14 |

(series circle)

15 | 16 |

(series square)

17 | 18 |

When calling a function that accepts a function argument, the argument function often isn’t needed anywhere else. Having to write down the function via define would be a hassle, because you have to make up a name and find a place to put the function definition. The alternative is to use lambda, which creates an anonymous function:

19 | 20 |

(series (lambda (size) (checkerboard (square size))))

21 | 22 |

The parenthesized names after a lambda are the arguments to the function, and the expression after the argument names is the function body. Using the word “lambda” instead of “function” or “procedure” is part of Racket’s history and culture.

23 | 24 |

A define form for a function is really a shorthand for a simple define using lambda as the value. For example, the series definition could be written as:

25 | 26 |

(define series 27 | (lambda (mk) 28 | (hc-append 4 (mk 5) (mk 10) (mk 20))))

29 | 30 |

Most Racketeers prefer to use the shorthand function form with define instead of expanding to lambda.

31 | 32 |

Type next

-------------------------------------------------------------------------------- /templates/tutorial/go.html: -------------------------------------------------------------------------------- 1 |

Go!

2 | 3 |

When you type an expression after the > in the REPL and hit Enter, the expression is evaluated and its result is printed. An expression can be just a value, such as the number 5 or the string "art gallery":

4 | 5 |

6 | Try typing 5 or "art gallery" in the REPL. 7 |

8 | 9 | 10 |

An expression can also be a function call. To call a function, put an open parenthesis before the function name, then expressions for the function arguments, and then a close parenthesis, like this:

11 | 12 |

(circle 10)

13 | 14 |

A result from the circle function is a picture value, which prints as an expression result in much the same way that numbers or strings print. The argument to circle determines the circle’s size in pixels. As you might guess, there’s a rectangle function that takes two arguments instead of one:

15 | 16 |

(rectangle 10 20)

17 | 18 |

Try giving circle the wrong number of arguments, just to see what happens:

19 | 20 |

(circle 10 20)

21 | 22 | 23 |

In addition to basic picture constructors like circle and rectangle, there’s a hc-append function that combines pictures. When you start composing function calls in Racket, it looks like this:

24 | 25 |

(hc-append (circle 10) (rectangle 10 20))

26 | 27 | -------------------------------------------------------------------------------- /templates/tutorial/intro.html: -------------------------------------------------------------------------------- 1 |

Quick: An Introduction to Racket with Pictures

2 | 3 |

4 | This tutorial provides a brief introduction to the Racket programming language by using one of its picture-drawing libraries (see the original tutorial). 5 |

6 | 7 |

8 | You can type next to skip forward, back to return to the previous step, and restart to get back to the beginning. Let's get started: type next. 9 |

-------------------------------------------------------------------------------- /templates/tutorial/lists.html: -------------------------------------------------------------------------------- 1 |

Lists

2 | 3 |

Racket inherits much of its style from the language Lisp, whose name originally stood for “LISt Processor,” 4 | and lists remain an important part of Racket.

5 | 6 |

The list function takes any number of arguments and returns a list containing the given values:

7 | 8 |

(list "red" "green" "blue")

9 | 10 | 17 | 18 |

If you have a list, then you’ll eventually want to do something with each of the elements. 19 | The map function takes a list and a function to apply to each element of the list; 20 | it returns a new list to combine the function’s results:

21 | 22 |

(map (lambda (n) 23 | (* 2 n)) 24 | (list 0 1 2 3 4 5 6 7 8 9))

25 | 26 | 27 |

Another function that works with lists is apply. Like map, 28 | it takes a function and a list, but a function given to apply should take all of 29 | the arguments at once, instead of each one individually. 30 | The apply function is especially useful with functions that take any number of arguments, such as vc-append:

31 | 32 |

(define (rainbow p) 33 | (map (lambda (color) 34 | (colorize p color)) 35 | (list "red" "orange" "yellow" "green" "blue" 36 | "purple")))

37 | 38 |

(apply vc-append (rainbow (square 5)))

39 | 40 |

Note that (vc-append (rainbow (square 5))) would not work, 41 | because vc-append does not want a list as an argument; 42 | it wants a picture as an argument, and it is willing to accept any number of them. 43 | The apply function bridges the gap between a function that wants many arguments and a list of those arguments as a single value.

44 | 45 |

Type next

-------------------------------------------------------------------------------- /templates/tutorial/macros.html: -------------------------------------------------------------------------------- 1 |

Macros

2 | 3 |

Here’s another library to try:

4 | 5 |

(require pict/code)

6 | 7 |

(code (circle 10))

8 | 9 |

Instead of a circle, the result is a picture of the code that, if it were used as an expression, would produce a circle. In other words, code is not a function, but instead a new syntactic form for creating pictures; the bit between the opening parenthesis with code is not an expression, but instead manipulated by the code syntactic form.

10 | 11 |

Libraries are not restricted to exporting values, such as functions; they can also define new syntactic forms. In this sense, Racket isn’t exactly a language at all; it’s more of an idea for how to structure a language so that you can extend it or create entirely new languages.

12 | 13 |

One way to introduce a new syntactic form is through define-syntax with syntax-rules:

14 | 15 |

(define-syntax pict+code 16 | (syntax-rules () 17 | [(pict+code expr) 18 | (hc-append 10 19 | expr 20 | (code expr))]))

21 | 22 |

(pict+code (circle 10))

23 | 24 |

This kind of definition is a macro. The (pict+code expr) part is a pattern for uses of the macro; instances of the pattern in a program are replaced by instances of the corresponding template, which is (hc-append 10 expr (code expr)). In particular, (pict+code (circle 10)) matches the pattern with (circle 10) as expr, so it is replaced with (hc-append 10 (circle 10) (code (circle 10))).

25 | 26 |

Of course, this sort of syntactic extension cuts both ways: inventing a new language can make it easier to say what you want, but harder for others to understand.

27 | 28 |

Type next

29 | -------------------------------------------------------------------------------- /templates/tutorial/modules.html: -------------------------------------------------------------------------------- 1 |

Modules

2 | 3 | 4 | 5 |

To import additional libraries, use the require form. For example, the library slideshow/flash provides a filled-flash function:

6 | 7 |

(require pict/flash)

8 | 9 |

(filled-flash 40 30)

10 | 11 |

Modules are named and distributed in various ways:

12 | 13 |

Some modules are packaged in the Racket distribution or otherwise installed into a hierarchy of collections. For example, the module name pict/flash means “the module implemented in the file "flash.rkt" that is located in the "pict" collection.” When a module name includes no slash, then it refers to a "main.rkt" file.

14 | 15 |

Some modules are distributed through the PLaneT server, and they can be downloaded automatically on demand. For example, the first time that you evaluate the following fragment:

16 | 17 |

(require (planet schematics/random:1:0/random))

18 | 19 |

(random-gaussian)

20 | 21 |

DrRacket automatically downloads version 1.0 of the "random.plt" library by "schematics" and then imports the "random.rkt" module.

22 | 23 | 35 | 36 | 37 |

Racketeers typically write new programs and libraries as modules that import each other through relative paths, and that use existing libraries from collections and planet. When a program or library developed this way seems useful to others, it can be uploaded as a PLaneT package or distributed in the more old-fashioned way as an installable collection archive (in either case without modifying the internal relative references among modules).

38 | 39 |

Type next

40 | -------------------------------------------------------------------------------- /templates/tutorial/objects.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | (lambda (x) (* x x)) 4 | 5 |

Objects

6 | 7 |

An object system is another example of a sophisticated language extension that is worth learning and using for Racket users. Objects are sometimes better than functions, even when you have lambda, and objects work especially well for graphical user interfaces. The API for Racket’s GUI and graphics system is expressed in terms of objects and classes.

8 | 9 |

The class system itself is implemented by the racket/class library, and the racket/gui/base library provides the GUI and drawing classes. By convention, the classes are given names that end with %:

10 | 11 | (require racket/class) 12 | (define f (new frame% [label "My Art"] 13 | [width 300] 14 | [height 300] 15 | [alignment '(center center)])) 16 | 17 | (send f show #t) 18 | 19 |

The new form creates an instance of a class, where initialization arguments like label and width are provided by name. The send form calls a method of the object, such as show, with arguments after the method name; the argument #t in this case is the boolean constant “true.”

20 | 21 |

Pictures generated with slideshow encapsulate a function that uses the graphics toolbox’s drawing commands to render the picture to a drawing context, such as a canvas in a frame. The make-pict-drawer function from slideshow exposes a picture’s drawing function. We can use make-pict-drawer in a canvas-painting callback to draw a picture into a canvas:

22 | 23 | (define (add-drawing p) 24 | (let ([drawer (make-pict-drawer p)]) 25 | (new canvas% [parent f] 26 | [style '(border)] 27 | [paint-callback (lambda (self dc) 28 | (drawer dc 0 0))]))) 29 | 30 | (add-drawing (pict+code (circle 10))) 31 | 32 | 33 | (add-drawing (colorize (filled-flash 50 30) "yellow")) 34 | 35 | 36 | -------------------------------------------------------------------------------- /templates/tutorial/scope.html: -------------------------------------------------------------------------------- 1 |

Lexical Scope

2 | 3 |

Racket is a lexically scoped language, which means that whenever an identifier is used as an expression, something in the textual environment of the expression determines the identifier’s binding. This rule applies to identifiers in a lambda body as well as anywhere else.

4 | 5 |

In the following rgb-series function, the uses of mk in each lambda form refer to the argument of rgb-series, since that’s the binding that is textually in scope:

6 | 7 |

(define (rgb-series mk) 8 | (vc-append 9 | (series (lambda (sz) (colorize (mk sz) "red"))) 10 | (series (lambda (sz) (colorize (mk sz) "green"))) 11 | (series (lambda (sz) (colorize (mk sz) "blue")))))

12 | 13 |

(rgb-series circle)

14 | 15 |

(rgb-series square)

16 | 17 |

Here’s another example, where rgb-maker takes a function and returns a new one that remembers and uses the original function.

18 | 19 |

(define (rgb-maker mk) 20 | (lambda (sz) 21 | (vc-append (colorize (mk sz) "red") 22 | (colorize (mk sz) "green") 23 | (colorize (mk sz) "blue"))))

24 | 25 |

(series (rgb-maker circle))

26 | 27 |

(series (rgb-maker square))

28 | 29 |

Note how composing functions via rgb-maker creates a different alignment of objects within the picture compared to using rgb-series.

30 | 31 |

Type next

-------------------------------------------------------------------------------- /templates/tutorial/where.html: -------------------------------------------------------------------------------- 1 |

Where to Go From Here

2 | 3 | 8 | 9 |

If you are new to programming or if you have the patience to work through a textbook, we recommend reading How to Design Programs. If you have already read it, or if you want to see where the book will take you, then see Continue: Web Applications in Racket.

10 | 11 |

For experienced programmers, to continue touring Racket from a systems-oriented perspective instead of pictures, your next stop is More: Systems Programming with Racket.

12 | 13 |

To instead start learning about the full Racket language and tools in depth, move on to The Racket Guide.

--------------------------------------------------------------------------------