├── .gitignore ├── .gitmodules ├── .htaccess ├── LICENSE ├── README ├── TODO ├── config.js.php ├── cpp_visualizer.txt ├── embed ├── README ├── css │ ├── jquery.qtip.css │ ├── opt-frontend.css │ ├── pytutor.css │ └── ui-lightness │ │ ├── images │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ ├── ui-bg_flat_10_000000_40x100.png │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_228ef1_256x240.png │ │ ├── ui-icons_ef8c08_256x240.png │ │ ├── ui-icons_ffd27a_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ │ └── jquery-ui-1.8.24.custom.css └── js │ ├── d3.v2.min.js │ ├── iframe-embed.js │ ├── jquery-1.8.2.min.js │ ├── jquery-ui-1.8.24.custom.min.js │ ├── jquery.ba-bbq.min.js │ ├── jquery.jsPlumb-1.3.10-all-min.js │ ├── jquery.qtip.min.js │ ├── opt-frontend-common.js │ ├── opt-frontend.js │ └── pytutor.js ├── example-code ├── (Default).java ├── .dir-locals.el ├── .gitignore ├── .htaccess ├── Casting.java ├── CmdLineArgs.java ├── Complex.java ├── ControlFlow.java ├── Exception.java ├── ExceptionFlow.java ├── ExecLimit.java ├── Forest.java ├── Knapsack.java ├── LambdaExample.java ├── LinkedList.java ├── PassByValue.java ├── Person.java ├── Postfix.java ├── Recursion.java ├── Reflect.java ├── Rolex.java ├── Sqrt.java ├── StackOverflow.java ├── StackQueue.java ├── StaticInitializer.java ├── StdIn.java ├── Strings.java ├── SymbolTable.java ├── Synthetic.java ├── ToString.java ├── TwoClasses.java └── Variables.java ├── iframe-embed.html ├── img ├── README ├── jv.svg ├── jv128.png ├── jv256.png ├── jv32.png └── jv64.png ├── index.html ├── java_safe_ram_maketrace.php ├── jv-config.example.json ├── jv-frontend.js ├── pytutor-customizations.css └── pytutor-customizations.js /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | # hide this file 3 | # also things like jv-config.json~ and #jv-config.json# 4 | *jv-config.json* 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "CodeMirror"] 2 | path = CodeMirror 3 | url = https://github.com/marijnh/CodeMirror.git 4 | [submodule "OnlinePythonTutor"] 5 | path = OnlinePythonTutor 6 | url = https://github.com/pgbovine/OnlinePythonTutor.git 7 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | # hide this file 2 | # also things like jv-config.json~ and #jv-config.json# 3 | 4 | Order Allow,Deny 5 | Deny from all 6 | 7 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | java_visualize: visualization for java 2 | David Pritchard (daveagp@gmail.com), created May 2013 3 | 4 | This is the frontend for a Java visualizer. It is based on "Online Python Tutor", 5 | a Python visualizer by Philip Guo. Try it at these mirrors (as of time of writing): 6 | 7 | http://cscircles.cemc.uwaterloo.ca/java_visualize/ (Java 8) 8 | http://www.cs.princeton.edu/~cos126/java_visualize/ (Java 7) 9 | 10 | The Online Python Tutor repo contains both a frontend and backend. 11 | For Java wre readapt the frontend (so this repo contains OnlinePythonTutor 12 | as a subrepo) and replace the backend (it is in the java_jail repo mentioned 13 | below, since it runs in a sandbox). 14 | 15 | INSTALLATION 16 | 17 | Install these on your server first: 18 | https://github.com/cemc/safeexec 19 | https://github.com/daveagp/java_jail 20 | This requires root access. See the instructions therein for details. It is best to 21 | install these in locations that are not served to users by your web server. 22 | 23 | Next, in some folder accessible to your web server, run 24 | 25 | git clone --recursive https://github.com/daveagp/java_visualize 26 | 27 | It's recursive because it includes two submodules. Because of this, 28 | to update, use the pair of commands 29 | git pull; git submodule update 30 | 31 | At this point, visiting 32 | http://your.website/url/to/java_visualize/ 33 | should give you a beautiful (but non-working) frontend, and 34 | http://your.website/url/to/java_visualize/java_safe_ram_maketrace.php 35 | should give you a "Couldn't find jv-config.json" error. 36 | 37 | Next, copy jv-config.example.json to jv-config.json. Now visiting 38 | http://your.website/url/to/java_visualize/java_safe_ram_maketrace.php 39 | should give you a "http mangling" error. 40 | 41 | Finally, edit jv-config.json to indicate where you installed safeexec 42 | and java_jail. (Just those first two entries need to be changed right now.) 43 | 44 | Now, try the visualizer out! 45 | 46 | THE "C++ VISUALIZER" 47 | See cpp_visualizer.txt. 48 | 49 | FAQ 50 | -- click on "Click for FAQ" on the visualizer page 51 | 52 | MORE INFO 53 | -- index.html is a modified version of visualize.html 54 | -- jv-frontend.js is a modified version of opt-frontend.js 55 | -- java_safe_ram_maketrace.php connects the frontend to the backend 56 | -- config.* is used for configuration stuff specific to your server 57 | -- pytutor-customizations.{js,css} overrides some behaviour of OPT 58 | -- example-code is a directory full of example Java files to visualize 59 | 60 | Note that in the entire frontend, only the two .php files are 61 | written in a server-side language. Everything else we use is static, 62 | although OnlinePythonTutor has some server-side files that this Java 63 | version does not use. 64 | 65 | If you use a database, you'll be putting a DB password in jv-config.json. 66 | Please check that 67 | http://your.website/url/to/java_visualize/jv-config.json 68 | is inaccessible; .htaccess tries to do this, but you should confirm it works. 69 | 70 | ==== 71 | 72 | The modified files (index.html, jv-frontend.js) retain the MIT license 73 | under which they were published in the OnlinePythonTutor repo. 74 | 75 | The other files are released under 76 | the GNU Affero General Public License, versions 3 or later. See LICENSE 77 | or visit: http://www.gnu.org/licenses/agpl.html 78 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | graphics! either encode primitive operations as text, or send frames 2 | 3 | short hashes for urls 4 | 5 | caches for past visualizations (probably don't cache 10 times to see if randomized/time-dependent) 6 | 7 | figure out suspend/resume (e.g. for exception handling, data structures) 8 | 9 | allow selective visualization of contents of some built-in classes 10 | 11 | (suggested by Jeff Kang) 12 | When the slider has focus, press "j" (for jump), or another key, and follow that with a number. 13 | That would teleport you to the line of code that corresponds to that number. 14 | The difficulty is that multiple Frames-Objects pair images can belong to 1 line of code. 15 | If it's possible, perhaps show a list of all the pairs. 16 | The pairs could be shortened, compacted, and/or summarized to fit on the screen. 17 | Maybe it just lists the step numbers that correspond to that line number. 18 | Then, a person would be allowed to choose the Frames-Objects pair to skip to. 19 | Or, just pick the earliest Frames-Objects pair that will appear from the current step. 20 | That is, "what's the next step that will take me to this line of code?". 21 | 22 | 23 | (suggested by James Vanderhyde) 24 | improve flow when a return statement is followed by an assignment of that value: 25 | the value disappears and then comes back 26 | 27 | (suggested by Brad Vander Zanden) 28 | If a statement modifies the value of a variable/object, it would be helpful to highlight that value/object so that the student can instantly see what has been modified. 29 | 30 | inner classes, local classes, anonymous classes, lambdas, captured final variables, this$ ... 31 | - right now we show things exactly from JDWP, like Eclipse or NetBeans 32 | - no way to recover all lambda arg names given current bytecode 33 | - could desugar 2 frames into one and pass "this" to nicen a bit 34 | - here's a class that throws a JWDP exception in both java 7 and 8 35 | 36 | public class JWDP32 { 37 | public static void main(String[] args) { 38 | // x needs to be final, but not a compile-time constant 39 | final int x = Math.random() < 2 ? 42 : -42; 40 | Object anon = new Object(){int f(){return x;}}; 41 | class Local{int g(){return x;}} 42 | Local loc = new Local(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config.js.php: -------------------------------------------------------------------------------- 1 | < as follows: 13 | {real Java code to visualize} //>< {fake C++ code to show to the student} 14 | For instance, go to http://cscircles.cemc.uwaterloo.ca/java_visualize/ 15 | and type in the following: 16 | 17 | public class C { public static void main(String[] args) { //>< cout << x+y << endl; 21 | }} //><} 22 | 23 | So you're basically writing 2 parallel programs, though lines that are 24 | identical in Java and C++ only need to be typed in once (e.g. "int x = 2;"). 25 | 26 | At the moment, I've only deployed these fake visualizations with the embedded 27 | iframe version of the Python Tutor/Java Visualizer, which sort of makes sense 28 | because in this interface it's not editable, but also because our use case 29 | was embedding in course notes. The notes are here: 30 | http://bits.usc.edu/cs103-s15/schedule/ 31 | E.g., see this lecture's notes: 32 | http://bits.usc.edu/cs103-s15/control/ 33 | 34 | USAGE GUIDE 35 | 36 | You can either do this with your own server, or use a pre-existing one. 37 | 38 | Installing the Java Visualizer (see the README) automatically gives you 39 | the ability to do fake C++ visualizations. 40 | 41 | There is a configuration variable called "faking_cpp" in 42 | pytutor-customizations.js that eases the workflow for creating fake C++ 43 | visualizations and makes some superficial changes to some labels. 44 | 45 | For instance, you can use this mirror where it's enabled by default: 46 | http://bits.usc.edu/java_visualize/ 47 | 48 | You also can override it by setting the http query variable faking_cpp, 49 | so here is another server you can use: 50 | http://cscircles.cemc.uwaterloo.ca/java_visualize/?faking_cpp=true 51 | 52 | Once there, enter your fake visualization. Once you're happy with it, 53 | copy the "Embeddable iframe:" field into whatever html you like. 54 | 55 | The ugly part of the workflow at the moment is editing a previously-created 56 | animation, which at this point requires editing or converting the URL-encoded 57 | version of the code. If you find this a big hassle, feel free to get in 58 | touch, or please send a pull request if you create a easy solution. 59 | 60 | NOTES 61 | 62 | Right now, the backend is agnostic as to whether it's visualizing true 63 | Java or faking C++. It would be better to fix this, e.g. so main returns 0 64 | and not VOID when we're faking C++. 65 | 66 | To see how this is implemented, search for 'fakify' in the java_jail repo. 67 | 68 | There's nothing special about C++ aside from the semantics and code flow 69 | being similar to Java; you could use this to fake-visualize any 70 | other language depending on how much work you're willing to put into writing 71 | 2 parallel versions of the code. 72 | 73 | The Java/C++ embedded visualizer is using a modification of an old version 74 | of the embedded visualizer code. See embed/README for details. It would 75 | be nice to bring it up to date. 76 | 77 | A few educators and students that I have talked to have ideas and partial 78 | implementations of a "real" C++ visualizer, either by piping through gdb, 79 | or by using LLDB's API, or by doing something like valgrind. Please email 80 | me if you have made progress in this direction or if you want to touch 81 | base with others who are interested. 82 | -------------------------------------------------------------------------------- /embed/README: -------------------------------------------------------------------------------- 1 | Note! This repository is using a crufty old version of the visualizer 2 | for embedding. 3 | 4 | The reason for this is laziness, but specifically because there are 5 | features of the Java Visualizer not yet supported on the main branch and 6 | at pythontutor.com (as of the date of writing), in particular 7 | command-line arguments and standard input. 8 | 9 | As a result, this subdirectory has out-of-date copies from an old 10 | version of the Python Tutor, which were then manually changed to be 11 | Java-friendly. 12 | 13 | For reference, the files in this directry were taken from 14 | https://github.com/cemc/cscircles-wp-content 15 | in the directory pybox/OnlinePythonTutor3-cemc 16 | and then modified. 17 | 18 | -------------------------------------------------------------------------------- /embed/css/jquery.qtip.css: -------------------------------------------------------------------------------- 1 | /*! qTip2 - Pretty powerful tooltips - v2.0.0 - 2012-09-10 2 | * http://craigsworks.com/projects/qtip2/ 3 | * Copyright (c) 2012 Craig Michael Thompson; Licensed MIT, GPL */ 4 | 5 | /* Fluid class for determining actual width in IE */ 6 | #qtip-rcontainer{ 7 | position: absolute; 8 | left: -28000px; 9 | top: -28000px; 10 | display: block; 11 | visibility: hidden; 12 | } 13 | 14 | /* Fluid class for determining actual width in IE */ 15 | #qtip-rcontainer .ui-tooltip{ 16 | display: block !important; 17 | visibility: hidden !important; 18 | position: static !important; 19 | float: left !important; 20 | } 21 | 22 | /* Core qTip styles */ 23 | .ui-tooltip, .qtip{ 24 | position: absolute; 25 | left: -28000px; 26 | top: -28000px; 27 | display: none; 28 | 29 | max-width: 280px; 30 | min-width: 50px; 31 | 32 | font-size: 10.5px; 33 | line-height: 12px; 34 | } 35 | 36 | .ui-tooltip-content{ 37 | position: relative; 38 | padding: 5px 9px; 39 | overflow: hidden; 40 | 41 | text-align: left; 42 | word-wrap: break-word; 43 | } 44 | 45 | .ui-tooltip-titlebar{ 46 | position: relative; 47 | min-height: 14px; 48 | padding: 5px 35px 5px 10px; 49 | overflow: hidden; 50 | 51 | border-width: 0 0 1px; 52 | font-weight: bold; 53 | } 54 | 55 | .ui-tooltip-titlebar + .ui-tooltip-content{ border-top-width: 0 !important; } 56 | 57 | /* Default close button class */ 58 | .ui-tooltip-titlebar .ui-state-default{ 59 | position: absolute; 60 | right: 4px; 61 | top: 50%; 62 | margin-top: -9px; 63 | 64 | cursor: pointer; 65 | outline: medium none; 66 | 67 | border-width: 1px; 68 | border-style: solid; 69 | } 70 | 71 | * html .ui-tooltip-titlebar .ui-state-default{ top: 16px; } /* IE fix */ 72 | 73 | .ui-tooltip-titlebar .ui-icon, 74 | .ui-tooltip-icon .ui-icon{ 75 | display: block; 76 | text-indent: -1000em; 77 | direction: ltr; 78 | } 79 | 80 | .ui-tooltip-icon, .ui-tooltip-icon .ui-icon{ 81 | -moz-border-radius: 3px; 82 | -webkit-border-radius: 3px; 83 | border-radius: 3px; 84 | text-decoration: none; 85 | } 86 | 87 | .ui-tooltip-icon .ui-icon{ 88 | width: 18px; 89 | height: 14px; 90 | 91 | text-align: center; 92 | text-indent: 0; 93 | font: normal bold 10px/13px Tahoma,sans-serif; 94 | 95 | color: inherit; 96 | background: transparent none no-repeat -100em -100em; 97 | } 98 | 99 | 100 | /* Applied to 'focused' tooltips e.g. most recently displayed/interacted with */ 101 | .ui-tooltip-focus{} 102 | 103 | /* Applied on hover of tooltips i.e. added/removed on mouseenter/mouseleave respectively */ 104 | .ui-tooltip-hover{} 105 | 106 | /* Default tooltip style */ 107 | .ui-tooltip-default{ 108 | border-width: 1px; 109 | border-style: solid; 110 | border-color: #F1D031; 111 | 112 | background-color: #FFFFA3; 113 | color: #555; 114 | } 115 | 116 | .ui-tooltip-default .ui-tooltip-titlebar{ 117 | background-color: #FFEF93; 118 | } 119 | 120 | .ui-tooltip-default .ui-tooltip-icon{ 121 | border-color: #CCC; 122 | background: #F1F1F1; 123 | color: #777; 124 | } 125 | 126 | .ui-tooltip-default .ui-tooltip-titlebar .ui-state-hover{ 127 | border-color: #AAA; 128 | color: #111; 129 | } 130 | 131 | 132 | /*! Light tooltip style */ 133 | .ui-tooltip-light{ 134 | background-color: white; 135 | border-color: #E2E2E2; 136 | color: #454545; 137 | } 138 | 139 | .ui-tooltip-light .ui-tooltip-titlebar{ 140 | background-color: #f1f1f1; 141 | } 142 | 143 | 144 | /*! Dark tooltip style */ 145 | .ui-tooltip-dark{ 146 | background-color: #505050; 147 | border-color: #303030; 148 | color: #f3f3f3; 149 | } 150 | 151 | .ui-tooltip-dark .ui-tooltip-titlebar{ 152 | background-color: #404040; 153 | } 154 | 155 | .ui-tooltip-dark .ui-tooltip-icon{ 156 | border-color: #444; 157 | } 158 | 159 | .ui-tooltip-dark .ui-tooltip-titlebar .ui-state-hover{ 160 | border-color: #303030; 161 | } 162 | 163 | 164 | /*! Cream tooltip style */ 165 | .ui-tooltip-cream{ 166 | background-color: #FBF7AA; 167 | border-color: #F9E98E; 168 | color: #A27D35; 169 | } 170 | 171 | .ui-tooltip-cream .ui-tooltip-titlebar{ 172 | background-color: #F0DE7D; 173 | } 174 | 175 | .ui-tooltip-cream .ui-state-default .ui-tooltip-icon{ 176 | background-position: -82px 0; 177 | } 178 | 179 | 180 | /*! Red tooltip style */ 181 | .ui-tooltip-red{ 182 | background-color: #F78B83; 183 | border-color: #D95252; 184 | color: #912323; 185 | } 186 | 187 | .ui-tooltip-red .ui-tooltip-titlebar{ 188 | background-color: #F06D65; 189 | } 190 | 191 | .ui-tooltip-red .ui-state-default .ui-tooltip-icon{ 192 | background-position: -102px 0; 193 | } 194 | 195 | .ui-tooltip-red .ui-tooltip-icon{ 196 | border-color: #D95252; 197 | } 198 | 199 | .ui-tooltip-red .ui-tooltip-titlebar .ui-state-hover{ 200 | border-color: #D95252; 201 | } 202 | 203 | 204 | /*! Green tooltip style */ 205 | .ui-tooltip-green{ 206 | background-color: #CAED9E; 207 | border-color: #90D93F; 208 | color: #3F6219; 209 | } 210 | 211 | .ui-tooltip-green .ui-tooltip-titlebar{ 212 | background-color: #B0DE78; 213 | } 214 | 215 | .ui-tooltip-green .ui-state-default .ui-tooltip-icon{ 216 | background-position: -42px 0; 217 | } 218 | 219 | 220 | /*! Blue tooltip style */ 221 | .ui-tooltip-blue{ 222 | background-color: #E5F6FE; 223 | border-color: #ADD9ED; 224 | color: #5E99BD; 225 | } 226 | 227 | .ui-tooltip-blue .ui-tooltip-titlebar{ 228 | background-color: #D0E9F5; 229 | } 230 | 231 | .ui-tooltip-blue .ui-state-default .ui-tooltip-icon{ 232 | background-position: -2px 0; 233 | } 234 | 235 | 236 | /* Add shadows to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE9+, Safari 2+ */ 237 | .ui-tooltip-shadow{ 238 | -webkit-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); 239 | -moz-box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); 240 | box-shadow: 1px 1px 3px 1px rgba(0, 0, 0, 0.15); 241 | } 242 | 243 | /* Add rounded corners to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE9+, Safari 2+ */ 244 | .ui-tooltip-rounded, 245 | .ui-tooltip-tipsy, 246 | .ui-tooltip-bootstrap{ 247 | -moz-border-radius: 5px; 248 | -webkit-border-radius: 5px; 249 | border-radius: 5px; 250 | } 251 | 252 | /* Youtube tooltip style */ 253 | .ui-tooltip-youtube{ 254 | -moz-border-radius: 2px; 255 | -webkit-border-radius: 2px; 256 | border-radius: 2px; 257 | 258 | -webkit-box-shadow: 0 0 3px #333; 259 | -moz-box-shadow: 0 0 3px #333; 260 | box-shadow: 0 0 3px #333; 261 | 262 | color: white; 263 | border-width: 0; 264 | 265 | background: #4A4A4A; 266 | background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,black)); 267 | background-image: -webkit-linear-gradient(top,#4A4A4A 0,black 100%); 268 | background-image: -moz-linear-gradient(top,#4A4A4A 0,black 100%); 269 | background-image: -ms-linear-gradient(top,#4A4A4A 0,black 100%); 270 | background-image: -o-linear-gradient(top,#4A4A4A 0,black 100%); 271 | } 272 | 273 | .ui-tooltip-youtube .ui-tooltip-titlebar{ 274 | background-color: #4A4A4A; 275 | background-color: rgba(0,0,0,0); 276 | } 277 | 278 | .ui-tooltip-youtube .ui-tooltip-content{ 279 | padding: .75em; 280 | font: 12px arial,sans-serif; 281 | 282 | filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#4a4a4a,EndColorStr=#000000); 283 | -ms-filter: "progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#4a4a4a,EndColorStr=#000000);"; 284 | } 285 | 286 | .ui-tooltip-youtube .ui-tooltip-icon{ 287 | border-color: #222; 288 | } 289 | 290 | .ui-tooltip-youtube .ui-tooltip-titlebar .ui-state-hover{ 291 | border-color: #303030; 292 | } 293 | 294 | 295 | /* jQuery TOOLS Tooltip style */ 296 | .ui-tooltip-jtools{ 297 | background: #232323; 298 | background: rgba(0, 0, 0, 0.7); 299 | background-image: -webkit-gradient(linear, left top, left bottom, from(#717171), to(#232323)); 300 | background-image: -moz-linear-gradient(top, #717171, #232323); 301 | background-image: -webkit-linear-gradient(top, #717171, #232323); 302 | background-image: -ms-linear-gradient(top, #717171, #232323); 303 | background-image: -o-linear-gradient(top, #717171, #232323); 304 | 305 | border: 2px solid #ddd; 306 | border: 2px solid rgba(241,241,241,1); 307 | 308 | -moz-border-radius: 2px; 309 | -webkit-border-radius: 2px; 310 | border-radius: 2px; 311 | 312 | -webkit-box-shadow: 0 0 12px #333; 313 | -moz-box-shadow: 0 0 12px #333; 314 | box-shadow: 0 0 12px #333; 315 | } 316 | 317 | /* IE Specific */ 318 | .ui-tooltip-jtools .ui-tooltip-titlebar{ 319 | background-color: transparent; 320 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A); 321 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)"; 322 | } 323 | .ui-tooltip-jtools .ui-tooltip-content{ 324 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323); 325 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)"; 326 | } 327 | 328 | .ui-tooltip-jtools .ui-tooltip-titlebar, 329 | .ui-tooltip-jtools .ui-tooltip-content{ 330 | background: transparent; 331 | color: white; 332 | border: 0 dashed transparent; 333 | } 334 | 335 | .ui-tooltip-jtools .ui-tooltip-icon{ 336 | border-color: #555; 337 | } 338 | 339 | .ui-tooltip-jtools .ui-tooltip-titlebar .ui-state-hover{ 340 | border-color: #333; 341 | } 342 | 343 | 344 | /* Cluetip style */ 345 | .ui-tooltip-cluetip{ 346 | -webkit-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); 347 | -moz-box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); 348 | box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4); 349 | 350 | background-color: #D9D9C2; 351 | color: #111; 352 | border: 0 dashed transparent; 353 | } 354 | 355 | .ui-tooltip-cluetip .ui-tooltip-titlebar{ 356 | background-color: #87876A; 357 | color: white; 358 | border: 0 dashed transparent; 359 | } 360 | 361 | .ui-tooltip-cluetip .ui-tooltip-icon{ 362 | border-color: #808064; 363 | } 364 | 365 | .ui-tooltip-cluetip .ui-tooltip-titlebar .ui-state-hover{ 366 | border-color: #696952; 367 | color: #696952; 368 | } 369 | 370 | 371 | /* Tipsy style */ 372 | .ui-tooltip-tipsy{ 373 | background: black; 374 | background: rgba(0, 0, 0, .87); 375 | 376 | color: white; 377 | border: 0 solid transparent; 378 | 379 | font-size: 11px; 380 | font-family: 'Lucida Grande', sans-serif; 381 | font-weight: bold; 382 | line-height: 16px; 383 | text-shadow: 0 1px black; 384 | } 385 | 386 | .ui-tooltip-tipsy .ui-tooltip-titlebar{ 387 | padding: 6px 35px 0 10; 388 | background-color: transparent; 389 | } 390 | 391 | .ui-tooltip-tipsy .ui-tooltip-content{ 392 | padding: 6px 10; 393 | } 394 | 395 | .ui-tooltip-tipsy .ui-tooltip-icon{ 396 | border-color: #222; 397 | text-shadow: none; 398 | } 399 | 400 | .ui-tooltip-tipsy .ui-tooltip-titlebar .ui-state-hover{ 401 | border-color: #303030; 402 | } 403 | 404 | 405 | /* Tipped style */ 406 | .ui-tooltip-tipped{ 407 | border: 3px solid #959FA9; 408 | 409 | -moz-border-radius: 3px; 410 | -webkit-border-radius: 3px; 411 | border-radius: 3px; 412 | 413 | background-color: #F9F9F9; 414 | color: #454545; 415 | 416 | font-weight: normal; 417 | font-family: serif; 418 | } 419 | 420 | .ui-tooltip-tipped .ui-tooltip-titlebar{ 421 | border-bottom-width: 0; 422 | 423 | color: white; 424 | background: #3A79B8; 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3A79B8), to(#2E629D)); 426 | background-image: -webkit-linear-gradient(top, #3A79B8, #2E629D); 427 | background-image: -moz-linear-gradient(top, #3A79B8, #2E629D); 428 | background-image: -ms-linear-gradient(top, #3A79B8, #2E629D); 429 | background-image: -o-linear-gradient(top, #3A79B8, #2E629D); 430 | filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D); 431 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)"; 432 | } 433 | 434 | .ui-tooltip-tipped .ui-tooltip-icon{ 435 | border: 2px solid #285589; 436 | background: #285589; 437 | } 438 | 439 | .ui-tooltip-tipped .ui-tooltip-icon .ui-icon{ 440 | background-color: #FBFBFB; 441 | color: #555; 442 | } 443 | 444 | 445 | /** 446 | * Twitter Bootstrap style. 447 | * 448 | * Tested with IE 8, IE 9, Chrome 18, Firefox 9, Opera 11. 449 | * Does not work with IE 7. 450 | */ 451 | .ui-tooltip-bootstrap{ 452 | font-size: 13px; 453 | line-height: 18px; 454 | 455 | color: #333333; 456 | background-color: #ffffff; 457 | 458 | 459 | border: 1px solid #ccc; 460 | border: 1px solid rgba(0, 0, 0, 0.2); 461 | 462 | *border-right-width: 2px; 463 | *border-bottom-width: 2px; 464 | 465 | -webkit-border-radius: 5px; 466 | -moz-border-radius: 5px; 467 | border-radius: 5px; 468 | 469 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 470 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 471 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 472 | 473 | -webkit-background-clip: padding-box; 474 | -moz-background-clip: padding; 475 | background-clip: padding-box; 476 | } 477 | 478 | .ui-tooltip-bootstrap .ui-tooltip-titlebar{ 479 | font-size: 18px; 480 | line-height: 22px; 481 | 482 | border-bottom: 1px solid #ccc; 483 | background-color: transparent; 484 | } 485 | 486 | .ui-tooltip-bootstrap .ui-tooltip-titlebar .ui-state-default{ 487 | right: 9px; top: 49%; 488 | border-style: none; 489 | } 490 | 491 | .ui-tooltip-bootstrap .ui-tooltip-icon{ 492 | background: white; 493 | } 494 | 495 | .ui-tooltip-bootstrap .ui-tooltip-icon .ui-icon{ 496 | width: auto; 497 | height: auto; 498 | float: right; 499 | font-size: 20px; 500 | font-weight: bold; 501 | line-height: 18px; 502 | color: #000000; 503 | text-shadow: 0 1px 0 #ffffff; 504 | opacity: 0.2; 505 | filter: alpha(opacity=20); 506 | } 507 | 508 | .ui-tooltip-bootstrap .ui-tooltip-icon .ui-icon:hover{ 509 | color: #000000; 510 | text-decoration: none; 511 | cursor: pointer; 512 | opacity: 0.4; 513 | filter: alpha(opacity=40); 514 | } 515 | 516 | 517 | /* IE9 fix - removes all filters */ 518 | .ui-tooltip:not(.ie9haxors) div.ui-tooltip-content, 519 | .ui-tooltip:not(.ie9haxors) div.ui-tooltip-titlebar{ 520 | filter: none; 521 | -ms-filter: none; 522 | } 523 | 524 | 525 | /* Tips plugin */ 526 | .ui-tooltip .ui-tooltip-tip{ 527 | margin: 0 auto; 528 | overflow: hidden; 529 | z-index: 10; 530 | } 531 | 532 | .ui-tooltip .ui-tooltip-tip, 533 | .ui-tooltip .ui-tooltip-tip .qtip-vml{ 534 | position: absolute; 535 | 536 | line-height: 0.1px !important; 537 | font-size: 0.1px !important; 538 | color: #123456; 539 | 540 | background: transparent; 541 | border: 0 dashed transparent; 542 | } 543 | 544 | .ui-tooltip .ui-tooltip-tip canvas{ top: 0; left: 0; } 545 | 546 | .ui-tooltip .ui-tooltip-tip .qtip-vml{ 547 | behavior: url(#default#VML); 548 | display: inline-block; 549 | visibility: visible; 550 | } 551 | /* Modal plugin */ 552 | #qtip-overlay{ 553 | position: fixed; 554 | left: -10000em; 555 | top: -10000em; 556 | } 557 | 558 | /* Applied to modals with show.modal.blur set to true */ 559 | #qtip-overlay.blurs{ cursor: pointer; } 560 | 561 | /* Change opacity of overlay here */ 562 | #qtip-overlay div{ 563 | position: absolute; 564 | left: 0; top: 0; 565 | width: 100%; height: 100%; 566 | 567 | background-color: black; 568 | 569 | opacity: 0.7; 570 | filter:alpha(opacity=70); 571 | -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; 572 | } 573 | 574 | -------------------------------------------------------------------------------- /embed/css/opt-frontend.css: -------------------------------------------------------------------------------- 1 | /* CSS accompanying ../visualize.html */ 2 | 3 | h1 { 4 | font-weight: normal; 5 | font-size: 20pt; 6 | font-family: georgia, serif; 7 | line-height: 1em; /* enforce single spacing so that Georgia works */ 8 | 9 | margin-top: 0px; 10 | margin-bottom: 8px; 11 | } 12 | 13 | h2 { 14 | font-size: 12pt; 15 | font-weight: normal; 16 | font-family: georgia, serif; 17 | line-height: 1.1em; /* enforce single spacing so that Georgia works */ 18 | 19 | margin-top: 2px; 20 | margin-bottom: 20px; 21 | } 22 | 23 | 24 | body { 25 | background-color: white; 26 | font-family: verdana, arial, helvetica, sans-serif; 27 | font-size: 10pt; 28 | } 29 | 30 | a, 31 | a:visited, 32 | a:hover { 33 | color: #3D58A2; 34 | } 35 | 36 | span { 37 | padding: 0px; 38 | } 39 | 40 | table#pyOutputPane { 41 | padding: 10px; 42 | } 43 | 44 | #pyInputPane { 45 | margin-top: 20px; 46 | margin-bottom: 20px; 47 | 48 | max-width: 700px; 49 | /* center align */ 50 | margin-left: auto; 51 | margin-right: auto; 52 | } 53 | 54 | #codeInputPane { 55 | margin-top: 5px; 56 | font-size: 12pt; 57 | border: 1px solid #ddd; 58 | } 59 | 60 | button.smallBtn { 61 | font-size: 10pt; 62 | padding: 3px; 63 | } 64 | 65 | button.bigBtn { 66 | font-size: 13pt; 67 | padding: 6px; 68 | margin-top: 6px; 69 | } 70 | 71 | #footer { 72 | color: #666666; 73 | font-size: 9pt; 74 | border-top: 1px solid #bbbbbb; 75 | padding-top: 5px; 76 | margin-top: 5px; 77 | 78 | max-width: 700px; 79 | /* center align */ 80 | margin-left: auto; 81 | margin-right: auto; 82 | } 83 | 84 | 85 | /* necessary for CodeMirror error line highlighting to work! */ 86 | .CodeMirror .errorLine { background: #ffff3f !important; } 87 | -------------------------------------------------------------------------------- /embed/css/pytutor.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Online Python Tutor 4 | https://github.com/pgbovine/OnlinePythonTutor/ 5 | 6 | Copyright (C) 2010-2012 Philip J. Guo (philip@pgbovine.net) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a 9 | copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included 17 | in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | */ 28 | 29 | /* Most recent color scheme redesign on 2012-08-19 */ 30 | 31 | /* To prevent CSS namespace clashes, prefix all rules with: 32 | div.ExecutionVisualizer 33 | */ 34 | 35 | 36 | /* reset some styles to nullify effects of existing stylesheets 37 | e.g., http://meyerweb.com/eric/tools/css/reset/ 38 | */ 39 | div.ExecutionVisualizer { 40 | /* none for now */ 41 | } 42 | 43 | div.ExecutionVisualizer table.visualizer { 44 | font-family: verdana, arial, helvetica, sans-serif; 45 | font-size: 10pt; 46 | margin-bottom: 10px; 47 | } 48 | 49 | div.ExecutionVisualizer table.visualizer td.vizLayoutTd { 50 | vertical-align: top; 51 | } 52 | 53 | div.ExecutionVisualizer td#stack_td, 54 | div.ExecutionVisualizer td#heap_td { 55 | vertical-align:top; 56 | font-size: 10pt; /* don't make fonts in the heap so big! */ 57 | } 58 | 59 | div.ExecutionVisualizer #dataViz { 60 | margin-left: 25px; 61 | } 62 | 63 | div.ExecutionVisualizer div#codeDisplayDiv { 64 | /* set this as default unless user specifies a custom size */ 65 | /*width: 550px;*/ 66 | } 67 | 68 | div.ExecutionVisualizer div#pyCodeOutputDiv { 69 | /*max-width: 550px;*/ 70 | max-height: 450px; 71 | /*max-height: 620px;*/ 72 | overflow: auto; 73 | /*margin-bottom: 4px;*/ 74 | 75 | margin-left: auto; 76 | margin-right: auto; 77 | } 78 | 79 | div.ExecutionVisualizer table#pyCodeOutput { 80 | font-family: Andale mono, monospace; 81 | font-size:12pt; 82 | line-height:1.1em; 83 | 84 | border-collapse: separate; /* some crazy CSS voodoo that needs to be 85 | there so that SVG arrows to the left 86 | of the code line up vertically in Chrome */ 87 | border-spacing: 0px; 88 | border-top: 1px solid #bbb; 89 | padding-top: 3px; 90 | border-bottom: 1px solid #bbb; 91 | /*margin-top: 6px;*/ 92 | margin: 6px auto; /* Center code in its pane */ 93 | } 94 | 95 | /* don't wrap lines within code output ... FORCE scrollbars to appear */ 96 | div.ExecutionVisualizer table#pyCodeOutput td { 97 | white-space: nowrap; 98 | vertical-align: middle; /* explicitly force, to override external CSS conflicts */ 99 | } 100 | 101 | div.ExecutionVisualizer #leftCodeGutterSVG { 102 | width: 18px; 103 | min-width: 18px; /* make sure it doesn't squash too thin */ 104 | height: 0px; /* programmatically set this later ... IE needs this to 105 | be 0 or it defaults to something arbitrary and gross */ 106 | } 107 | 108 | div.ExecutionVisualizer #prevLegendArrowSVG, 109 | div.ExecutionVisualizer #curLegendArrowSVG { 110 | width: 18px; 111 | height: 10px; 112 | } 113 | 114 | div.ExecutionVisualizer .arrow { 115 | font-size: 16pt; 116 | } 117 | 118 | div.ExecutionVisualizer table#pyCodeOutput .lineNo { 119 | color: #aaa; 120 | padding: 0.2em; 121 | padding-left: 0.3em; 122 | padding-right: 0.5em; 123 | text-align: right; 124 | } 125 | 126 | div.ExecutionVisualizer table#pyCodeOutput .cod { 127 | /*font-weight: bold;*/ 128 | margin-left: 3px; 129 | padding-left: 7px; 130 | text-align: left; /* necessary or else doesn't work properly in IE */ 131 | } 132 | 133 | div.ExecutionVisualizer div#progOutputs { 134 | margin-top: 8px; 135 | } 136 | 137 | div.ExecutionVisualizer div#legendDiv { 138 | margin-top: 10px; 139 | padding: 0px; 140 | text-align: left; 141 | color: #666; 142 | font-size: 9pt; 143 | } 144 | 145 | div.ExecutionVisualizer div#editCodeLinkDiv { 146 | text-align: center; 147 | /* 148 | margin-top: 12px; 149 | margin-bottom: 4px; 150 | */ 151 | margin: 8px auto; 152 | } 153 | 154 | div.ExecutionVisualizer div#annotateLinkDiv { 155 | /*text-align: left;*/ 156 | margin-top: 0px; 157 | margin-bottom: 12px; 158 | /* 159 | margin-left: auto; 160 | margin-right: auto; 161 | */ 162 | } 163 | 164 | div.ExecutionVisualizer div#stepAnnotationDiv { 165 | margin-bottom: 12px; 166 | } 167 | 168 | div.ExecutionVisualizer textarea#stepAnnotationEditor, 169 | div.ExecutionVisualizer textarea#vizTitleEditor, 170 | div.ExecutionVisualizer textarea#vizDescriptionEditor { 171 | border: 1px solid #999999; 172 | padding: 4px; 173 | 174 | overflow: auto; /* to look pretty on IE */ 175 | /* make sure textarea doesn't grow and stretch */ 176 | resize: none; 177 | } 178 | 179 | 180 | div.ExecutionVisualizer #errorOutput { 181 | color: #e93f34; /* should match brightRed JavaScript variable */ 182 | font-size: 12pt; 183 | padding: 2px; 184 | line-height: 1.5em; 185 | margin-bottom: 4px; 186 | } 187 | 188 | /* VCR control buttons for stepping through execution */ 189 | 190 | div.ExecutionVisualizer #vcrControls { 191 | margin: 15px auto; 192 | /*width: 100%;*/ 193 | text-align: center; 194 | } 195 | 196 | div.ExecutionVisualizer #vcrControls button { 197 | margin-left: 2px; 198 | margin-right: 2px; 199 | } 200 | 201 | div.ExecutionVisualizer #vcrControls #curInstr { 202 | margin-left: 4px; 203 | margin-right: 4px; 204 | } 205 | 206 | div.ExecutionVisualizer #pyStdout { 207 | border: 1px solid #999999; 208 | font-size: 12pt; 209 | padding: 4px; 210 | font-family: Andale mono, monospace; 211 | 212 | overflow: auto; /* to look pretty on IE */ 213 | /* make sure textarea doesn't grow and stretch */ 214 | resize: none; 215 | 216 | -moz-box-sizing: border-box; 217 | box-sizing: border-box; 218 | 219 | width: 100%; 220 | } 221 | 222 | 223 | div.ExecutionVisualizer .vizFrame { 224 | margin-bottom: 20px; 225 | padding-left: 8px; 226 | border-left: 2px solid #cccccc; 227 | } 228 | 229 | 230 | /* Rendering of primitive types */ 231 | 232 | div.ExecutionVisualizer .nullObj { 233 | // font-size: 8pt; 234 | } 235 | 236 | div.ExecutionVisualizer .stringObj, 237 | div.ExecutionVisualizer .customObj, 238 | div.ExecutionVisualizer .funcObj { 239 | font-family: Andale mono, monospace; 240 | white-space: nowrap; 241 | } 242 | 243 | div.ExecutionVisualizer .retval { 244 | font-size: 9pt; 245 | } 246 | 247 | div.ExecutionVisualizer .stackFrame .retval { 248 | color: #e93f34; /* highlight non-zombie stack frame return values - 249 | should match brightRed JavaScript variable */ 250 | } 251 | 252 | /* Rendering of basic compound types */ 253 | 254 | div.ExecutionVisualizer table.listTbl, 255 | div.ExecutionVisualizer table.tupleTbl, 256 | div.ExecutionVisualizer table.setTbl { 257 | background-color: #ffffc6; 258 | } 259 | 260 | 261 | div.ExecutionVisualizer table.listTbl { 262 | border: 0px solid black; 263 | border-spacing: 0px; 264 | } 265 | 266 | div.ExecutionVisualizer table.listTbl td.listHeader, 267 | div.ExecutionVisualizer table.tupleTbl td.tupleHeader { 268 | padding-left: 4px; 269 | padding-top: 2px; 270 | padding-bottom: 3px; 271 | font-size: 8pt; 272 | color: #777; 273 | text-align: left; 274 | border-left: 1px solid #555555; 275 | } 276 | 277 | div.ExecutionVisualizer table.tupleTbl { 278 | border-spacing: 0px; 279 | color: black; 280 | 281 | border-bottom: 1px solid #555555; /* must match td.tupleHeader border */ 282 | border-top: 1px solid #555555; /* must match td.tupleHeader border */ 283 | border-right: 1px solid #555555; /* must match td.tupleHeader border */ 284 | } 285 | 286 | 287 | div.ExecutionVisualizer table.listTbl td.listElt { 288 | border-bottom: 1px solid #555555; /* must match td.listHeader border */ 289 | border-left: 1px solid #555555; /* must match td.listHeader border */ 290 | } 291 | 292 | div.ExecutionVisualizer table.tupleTbl td.tupleElt { 293 | border-left: 1px solid #555555; /* must match td.tupleHeader border */ 294 | } 295 | 296 | div.ExecutionVisualizer table.customObjTbl { 297 | background-color: white; 298 | color: black; 299 | border: 1px solid black; 300 | } 301 | 302 | div.ExecutionVisualizer table.customObjTbl td.customObjElt { 303 | padding: 5px; 304 | } 305 | 306 | div.ExecutionVisualizer table.listTbl td.listElt, 307 | div.ExecutionVisualizer table.tupleTbl td.tupleElt { 308 | padding-top: 0px; 309 | padding-bottom: 8px; 310 | padding-left: 10px; 311 | padding-right: 10px; 312 | vertical-align: bottom; 313 | } 314 | 315 | div.ExecutionVisualizer table.setTbl { 316 | border: 1px solid #555555; 317 | border-spacing: 0px; 318 | text-align: center; 319 | } 320 | 321 | div.ExecutionVisualizer table.setTbl td.setElt { 322 | padding: 8px; 323 | } 324 | 325 | 326 | div.ExecutionVisualizer table.dictTbl, 327 | div.ExecutionVisualizer table.instTbl, 328 | div.ExecutionVisualizer table.classTbl { 329 | border-spacing: 1px; 330 | } 331 | 332 | div.ExecutionVisualizer table.dictTbl td.dictKey, 333 | div.ExecutionVisualizer table.instTbl td.instKey, 334 | div.ExecutionVisualizer table.classTbl td.classKey { 335 | background-color: #faebbf; 336 | } 337 | 338 | div.ExecutionVisualizer table.dictTbl td.dictVal, 339 | div.ExecutionVisualizer table.instTbl td.instVal, 340 | div.ExecutionVisualizer table.classTbl td.classVal { 341 | background-color: #ffffc6; 342 | } 343 | 344 | 345 | div.ExecutionVisualizer table.dictTbl td.dictKey, 346 | div.ExecutionVisualizer table.instTbl td.instKey, 347 | div.ExecutionVisualizer table.classTbl td.classKey { 348 | padding-top: 12px /*15px*/; 349 | padding-bottom: 5px; 350 | padding-left: 10px; 351 | padding-right: 4px; 352 | 353 | text-align: right; 354 | } 355 | 356 | div.ExecutionVisualizer table.dictTbl td.dictVal, 357 | div.ExecutionVisualizer table.instTbl td.instVal, 358 | div.ExecutionVisualizer table.classTbl td.classVal { 359 | padding-top: 12px /*15px*/; 360 | padding-bottom: 5px; 361 | padding-right: 10px; 362 | padding-left: 4px; 363 | } 364 | 365 | 366 | div.ExecutionVisualizer table.classTbl td, 367 | div.ExecutionVisualizer table.instTbl td { 368 | border-bottom: 1px #888 solid; 369 | } 370 | 371 | div.ExecutionVisualizer table.classTbl td.classVal, 372 | div.ExecutionVisualizer table.instTbl td.instVal { 373 | border-left: 1px #888 solid; 374 | } 375 | 376 | div.ExecutionVisualizer table.classTbl { 377 | border-collapse: collapse; 378 | border: 1px #888 solid; 379 | } 380 | 381 | /* only add a border to dicts if they're embedded within another object */ 382 | div.ExecutionVisualizer td.listElt table.dictTbl, 383 | div.ExecutionVisualizer td.tupleElt table.dictTbl, 384 | div.ExecutionVisualizer td.dictVal table.dictTbl, 385 | div.ExecutionVisualizer td.instVal table.dictTbl, 386 | div.ExecutionVisualizer td.classVal table.dictTbl { 387 | border: 1px #888 solid; 388 | } 389 | 390 | div.ExecutionVisualizer .objectIdLabel { 391 | font-size: 8pt; 392 | color: #444; 393 | margin-bottom: 2px; 394 | } 395 | 396 | div.ExecutionVisualizer .typeLabel { 397 | font-size: 8pt; 398 | color: #555; 399 | margin-bottom: 2px; 400 | } 401 | 402 | div.ExecutionVisualizer div#stack, 403 | div.ExecutionVisualizer div#globals_area { 404 | padding-left: 10px; 405 | padding-right: 30px; 406 | 407 | /* no longer necessary ... */ 408 | /*float: left;*/ 409 | /* border-right: 1px dashed #bbbbbb; */ 410 | } 411 | 412 | div.ExecutionVisualizer div.stackFrame, 413 | div.ExecutionVisualizer div.zombieStackFrame { 414 | background-color: #ffffff; 415 | margin-bottom: 15px; 416 | padding: 2px; 417 | padding-left: 6px; 418 | padding-right: 6px; 419 | padding-bottom: 4px; 420 | font-size: 10pt; 421 | } 422 | 423 | div.ExecutionVisualizer div.zombieStackFrame { 424 | border-left: 1px dotted #aaa; 425 | /*color: #c0c0c0;*/ 426 | color: #a0a0a0; 427 | } 428 | 429 | div.ExecutionVisualizer div.highlightedStackFrame { 430 | background-color: #e2ebf6; 431 | /*background-color: #d7e7fb;*/ 432 | 433 | /*background-color: #c0daf8;*/ 434 | /*background-color: #9eeaff #c5dfea;*/ 435 | } 436 | 437 | div.ExecutionVisualizer div.stackFrame, 438 | div.ExecutionVisualizer div.highlightedStackFrame { 439 | border-left: 1px solid #a6b3b6; 440 | } 441 | 442 | 443 | div.ExecutionVisualizer div.stackFrameHeader { 444 | font-family: Andale mono, monospace; 445 | font-size: 10pt; 446 | margin-top: 4px; 447 | margin-bottom: 3px; 448 | white-space: nowrap; 449 | } 450 | 451 | div.ExecutionVisualizer td.stackFrameVar { 452 | text-align: right; 453 | padding-right: 8px; 454 | padding-top: 3px; 455 | padding-bottom: 3px; 456 | } 457 | 458 | div.ExecutionVisualizer td.stackFrameValue { 459 | text-align: left; 460 | border-bottom: 1px solid #aaaaaa; 461 | border-left: 1px solid #aaaaaa; 462 | 463 | vertical-align: middle; 464 | 465 | padding-top: 3px; 466 | padding-left: 3px; 467 | padding-bottom: 3px; 468 | } 469 | 470 | div.ExecutionVisualizer .stackFrameVarTable tr { 471 | 472 | } 473 | 474 | div.ExecutionVisualizer .stackFrameVarTable { 475 | text-align: right; 476 | padding-top: 3px; 477 | 478 | /* right-align the table */ 479 | margin-left: auto; 480 | margin-right: 0px; 481 | 482 | /* hack to counteract possible nasty CSS reset styles from parent divs */ 483 | border-collapse: separate; 484 | border-spacing: 2px; 485 | } 486 | 487 | div.ExecutionVisualizer div#heap { 488 | float: left; 489 | padding-left: 30px; 490 | } 491 | 492 | div.ExecutionVisualizer td.toplevelHeapObject { 493 | /* needed for d3 to do transitions */ 494 | padding-left: 8px; 495 | padding-right: 8px; 496 | padding-top: 4px; 497 | padding-bottom: 4px; 498 | /* 499 | border: 2px dotted white; 500 | border-color: white; 501 | */ 502 | } 503 | 504 | div.ExecutionVisualizer table.heapRow { 505 | margin-bottom: 10px; 506 | } 507 | 508 | div.ExecutionVisualizer div.heapObject { 509 | padding-left: 2px; /* leave a TINY amount of room for connector endpoints */ 510 | } 511 | 512 | div.ExecutionVisualizer div.heapPrimitive { 513 | padding-left: 4px; /* leave some more room for connector endpoints */ 514 | } 515 | 516 | div.ExecutionVisualizer div#stackHeader { 517 | margin-bottom: 15px; 518 | text-align: right; 519 | } 520 | 521 | div.ExecutionVisualizer div#heapHeader { 522 | /*margin-top: 2px; 523 | margin-bottom: 13px;*/ 524 | margin-bottom: 15px; 525 | } 526 | 527 | div.ExecutionVisualizer div#stackHeader, 528 | div.ExecutionVisualizer div#heapHeader { 529 | color: #333333; 530 | font-size: 10pt; 531 | } 532 | 533 | div.ExecutionVisualizer #executionSlider { 534 | /* if you set 'width', then it looks ugly when you dynamically resize */ 535 | margin-top: 15px; 536 | margin-bottom: 5px; 537 | 538 | margin-left: auto; 539 | margin-right: auto; 540 | 541 | width: 95%; 542 | } 543 | 544 | div.ExecutionVisualizer #executionSliderCaption { 545 | font-size: 8pt; 546 | color: #666666; 547 | margin-top: 15px; 548 | } 549 | 550 | div.ExecutionVisualizer #executionSliderFooter { 551 | margin-top: -7px; /* make it butt up against #executionSlider */ 552 | } 553 | 554 | 555 | /* darken slider handle a bit */ 556 | div.ExecutionVisualizer .ui-slider .ui-slider-handle { 557 | border: 1px solid #999; 558 | } 559 | 560 | 561 | /* for annotation bubbles */ 562 | 563 | /* For styling tricks, see: http://css-tricks.com/textarea-tricks/ */ 564 | textarea.bubbleInputText { 565 | border: 1px solid #ccc; 566 | outline: none; 567 | overflow: auto; /* to look pretty on IE */ 568 | 569 | /* make sure textarea doesn't grow and stretch the enclosing bubble */ 570 | resize: none; 571 | width: 225px; 572 | max-width: 225px; 573 | height: 35px; 574 | max-height: 35px; 575 | } 576 | 577 | 578 | .ui-tooltip-pgbootstrap, 579 | textarea.bubbleInputText { 580 | font-family: verdana, arial, helvetica, sans-serif; 581 | font-size: 9pt; 582 | line-height: 1.3em; 583 | } 584 | 585 | 586 | /* modified version of Twitter bootstrap style by Philip Guo */ 587 | .ui-tooltip-pgbootstrap{ 588 | color: #333; 589 | background-color: #ffffff; 590 | 591 | max-width: 250px; 592 | min-width: 10px; 593 | 594 | border: 2px solid #4284D3; 595 | 596 | cursor: pointer; 597 | 598 | *border-right-width: 2px; 599 | *border-bottom-width: 2px; 600 | 601 | -webkit-border-radius: 5px; 602 | -moz-border-radius: 5px; 603 | border-radius: 5px; 604 | 605 | /* way too poofy ... 606 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 607 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 608 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 609 | */ 610 | 611 | -webkit-box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, 0.2); 612 | -moz-box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, 0.2); 613 | box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, 0.2); 614 | 615 | -webkit-background-clip: padding-box; 616 | -moz-background-clip: padding; 617 | background-clip: padding-box; 618 | } 619 | 620 | .ui-tooltip-pgbootstrap .ui-tooltip-titlebar{ 621 | font-size: 18px; 622 | line-height: 22px; 623 | 624 | border-bottom: 1px solid #ccc; 625 | background-color: transparent; 626 | } 627 | 628 | .ui-tooltip-pgbootstrap .ui-tooltip-content{ 629 | padding: 5px /* 5px is minimum or else it might look ugly */ 8px; 630 | } 631 | 632 | 633 | .ui-tooltip-pgbootstrap .ui-tooltip-titlebar .ui-state-default{ 634 | right: 9px; top: 49%; 635 | border-style: none; 636 | } 637 | 638 | .ui-tooltip-pgbootstrap .ui-tooltip-icon{ 639 | background: white; 640 | } 641 | 642 | .ui-tooltip-pgbootstrap .ui-tooltip-icon .ui-icon{ 643 | width: auto; 644 | height: auto; 645 | float: right; 646 | font-size: 20px; 647 | font-weight: bold; 648 | line-height: 18px; 649 | color: #000000; 650 | text-shadow: 0 1px 0 #ffffff; 651 | opacity: 0.2; 652 | filter: alpha(opacity=20); 653 | } 654 | 655 | .ui-tooltip-pgbootstrap .ui-tooltip-icon .ui-icon:hover{ 656 | color: #000000; 657 | text-decoration: none; 658 | cursor: pointer; 659 | opacity: 0.4; 660 | filter: alpha(opacity=40); 661 | } 662 | 663 | 664 | /* Add rounded corners to your tooltips in: FF3+, Chrome 2+, Opera 10.6+, IE9+, Safari 2+ */ 665 | .ui-tooltip-pgbootstrap{ 666 | -moz-border-radius: 5px; 667 | -webkit-border-radius: 5px; 668 | border-radius: 5px; 669 | } 670 | 671 | 672 | .ui-tooltip-pgbootstrap-stub{ 673 | border: 1px solid #999; 674 | 675 | /* 676 | -webkit-box-shadow: none; 677 | -moz-box-shadow: none; 678 | box-shadow: none; 679 | */ 680 | } 681 | 682 | .ui-tooltip-pgbootstrap-stub .ui-tooltip-content{ 683 | padding: 6px 9px; 684 | } 685 | 686 | 687 | div.ExecutionVisualizer .annotationText, 688 | div.ExecutionVisualizer .vizDescriptionText { 689 | font-family: verdana, arial, helvetica, sans-serif; 690 | font-size: 11pt; 691 | line-height: 1.5em; 692 | } 693 | 694 | div.ExecutionVisualizer .vizTitleText { 695 | font-family: verdana, arial, helvetica, sans-serif; 696 | font-size: 16pt; 697 | margin-bottom: 12pt; 698 | } 699 | 700 | div.ExecutionVisualizer div#vizHeader { 701 | margin-bottom: 10px; 702 | width: 700px; 703 | max-width: 700px; 704 | } 705 | 706 | /* prev then curr, so curr gets precedence when both apply */ 707 | div.ExecutionVisualizer .highlight-prev { 708 | background-color: #F0F0EA; 709 | } 710 | 711 | div.ExecutionVisualizer .highlight-cur { 712 | background-color: #FFFF66; 713 | } 714 | 715 | div.ExecutionVisualizer .highlight-legend { 716 | padding: 2px; 717 | } 718 | 719 | /* resizing sliders from David Pritchard */ 720 | .ui-resizable-e { 721 | background-color: #dddddd; 722 | width: 1px; 723 | border: 3px solid white; 724 | } 725 | 726 | .ui-resizable-e:hover { 727 | border-color: #dddddd; 728 | } 729 | 730 | 731 | /* for pyCrazyMode */ 732 | 733 | /* prev then curr, so curr gets precedence when both apply */ 734 | div.ExecutionVisualizer .pycrazy-highlight-prev { 735 | background-color: #eeeeee; /*#F0F0EA;*/ 736 | /* 737 | text-decoration: none; 738 | border-bottom: 1px solid #dddddd; 739 | */ 740 | } 741 | 742 | div.ExecutionVisualizer .pycrazy-highlight-cur { 743 | background-color: #FFFF66; 744 | /* aligned slightly higher than border-bottom */ 745 | /* 746 | text-decoration: none; 747 | border-bottom: 1px solid #e93f34; 748 | */ 749 | } 750 | 751 | div.ExecutionVisualizer .pycrazy-highlight-prev-and-cur { 752 | background-color: #FFFF66; 753 | 754 | text-decoration: none; 755 | border-bottom: 1px solid #999999; 756 | } 757 | -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/embed/css/ui-lightness/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /embed/css/ui-lightness/jquery-ui-1.8.24.custom.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery UI CSS Framework 1.8.24 3 | * 4 | * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Theming/API 9 | */ 10 | 11 | /* Layout helpers 12 | ----------------------------------*/ 13 | .ui-helper-hidden { display: none; } 14 | .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } 15 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } 16 | .ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } 17 | .ui-helper-clearfix:after { clear: both; } 18 | .ui-helper-clearfix { zoom: 1; } 19 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } 20 | 21 | 22 | /* Interaction Cues 23 | ----------------------------------*/ 24 | .ui-state-disabled { cursor: default !important; } 25 | 26 | 27 | /* Icons 28 | ----------------------------------*/ 29 | 30 | /* states and images */ 31 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } 32 | 33 | 34 | /* Misc visuals 35 | ----------------------------------*/ 36 | 37 | /* Overlays */ 38 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } 39 | 40 | 41 | /*! 42 | * jQuery UI CSS Framework 1.8.24 43 | * 44 | * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) 45 | * Dual licensed under the MIT or GPL Version 2 licenses. 46 | * http://jquery.org/license 47 | * 48 | * http://docs.jquery.com/UI/Theming/API 49 | * 50 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px 51 | */ 52 | 53 | 54 | /* Component containers 55 | ----------------------------------*/ 56 | .ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } 57 | .ui-widget .ui-widget { font-size: 1em; } 58 | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } 59 | /* pgbovine - switch border from #dddddd to #ccc */ 60 | .ui-widget-content { border: 1px solid #ccc; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } 61 | .ui-widget-content a { color: #333333; } 62 | .ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } 63 | .ui-widget-header a { color: #ffffff; } 64 | 65 | /* Interaction states 66 | ----------------------------------*/ 67 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } 68 | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } 69 | 70 | /* pgbovine - eliminate hover colors */ 71 | /* 72 | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } 73 | .ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } 74 | */ 75 | 76 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } 77 | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } 78 | .ui-widget :active { outline: none; } 79 | 80 | /* Interaction Cues 81 | ----------------------------------*/ 82 | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } 83 | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } 84 | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } 85 | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } 86 | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } 87 | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } 88 | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } 89 | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } 90 | 91 | /* Icons 92 | ----------------------------------*/ 93 | 94 | /* states and images */ 95 | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } 96 | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } 97 | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } 98 | .ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } 99 | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } 100 | .ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } 101 | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } 102 | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } 103 | 104 | /* positioning */ 105 | .ui-icon-carat-1-n { background-position: 0 0; } 106 | .ui-icon-carat-1-ne { background-position: -16px 0; } 107 | .ui-icon-carat-1-e { background-position: -32px 0; } 108 | .ui-icon-carat-1-se { background-position: -48px 0; } 109 | .ui-icon-carat-1-s { background-position: -64px 0; } 110 | .ui-icon-carat-1-sw { background-position: -80px 0; } 111 | .ui-icon-carat-1-w { background-position: -96px 0; } 112 | .ui-icon-carat-1-nw { background-position: -112px 0; } 113 | .ui-icon-carat-2-n-s { background-position: -128px 0; } 114 | .ui-icon-carat-2-e-w { background-position: -144px 0; } 115 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 116 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 117 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 118 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 119 | .ui-icon-triangle-1-s { background-position: -64px -16px; } 120 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 121 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 122 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 123 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 124 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 125 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 126 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 127 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 128 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 129 | .ui-icon-arrow-1-s { background-position: -64px -32px; } 130 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 131 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 132 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 133 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 134 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 135 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 136 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 137 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 138 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 139 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 140 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 141 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } 142 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 143 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 144 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 145 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 146 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 147 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 148 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 149 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 150 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 151 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 152 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 153 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 154 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 155 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 156 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 157 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 158 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 159 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 160 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 161 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 162 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 163 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 164 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 165 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 166 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 167 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 168 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 169 | .ui-icon-arrow-4 { background-position: 0 -80px; } 170 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 171 | .ui-icon-extlink { background-position: -32px -80px; } 172 | .ui-icon-newwin { background-position: -48px -80px; } 173 | .ui-icon-refresh { background-position: -64px -80px; } 174 | .ui-icon-shuffle { background-position: -80px -80px; } 175 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 176 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 177 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 178 | .ui-icon-folder-open { background-position: -16px -96px; } 179 | .ui-icon-document { background-position: -32px -96px; } 180 | .ui-icon-document-b { background-position: -48px -96px; } 181 | .ui-icon-note { background-position: -64px -96px; } 182 | .ui-icon-mail-closed { background-position: -80px -96px; } 183 | .ui-icon-mail-open { background-position: -96px -96px; } 184 | .ui-icon-suitcase { background-position: -112px -96px; } 185 | .ui-icon-comment { background-position: -128px -96px; } 186 | .ui-icon-person { background-position: -144px -96px; } 187 | .ui-icon-print { background-position: -160px -96px; } 188 | .ui-icon-trash { background-position: -176px -96px; } 189 | .ui-icon-locked { background-position: -192px -96px; } 190 | .ui-icon-unlocked { background-position: -208px -96px; } 191 | .ui-icon-bookmark { background-position: -224px -96px; } 192 | .ui-icon-tag { background-position: -240px -96px; } 193 | .ui-icon-home { background-position: 0 -112px; } 194 | .ui-icon-flag { background-position: -16px -112px; } 195 | .ui-icon-calendar { background-position: -32px -112px; } 196 | .ui-icon-cart { background-position: -48px -112px; } 197 | .ui-icon-pencil { background-position: -64px -112px; } 198 | .ui-icon-clock { background-position: -80px -112px; } 199 | .ui-icon-disk { background-position: -96px -112px; } 200 | .ui-icon-calculator { background-position: -112px -112px; } 201 | .ui-icon-zoomin { background-position: -128px -112px; } 202 | .ui-icon-zoomout { background-position: -144px -112px; } 203 | .ui-icon-search { background-position: -160px -112px; } 204 | .ui-icon-wrench { background-position: -176px -112px; } 205 | .ui-icon-gear { background-position: -192px -112px; } 206 | .ui-icon-heart { background-position: -208px -112px; } 207 | .ui-icon-star { background-position: -224px -112px; } 208 | .ui-icon-link { background-position: -240px -112px; } 209 | .ui-icon-cancel { background-position: 0 -128px; } 210 | .ui-icon-plus { background-position: -16px -128px; } 211 | .ui-icon-plusthick { background-position: -32px -128px; } 212 | .ui-icon-minus { background-position: -48px -128px; } 213 | .ui-icon-minusthick { background-position: -64px -128px; } 214 | .ui-icon-close { background-position: -80px -128px; } 215 | .ui-icon-closethick { background-position: -96px -128px; } 216 | .ui-icon-key { background-position: -112px -128px; } 217 | .ui-icon-lightbulb { background-position: -128px -128px; } 218 | .ui-icon-scissors { background-position: -144px -128px; } 219 | .ui-icon-clipboard { background-position: -160px -128px; } 220 | .ui-icon-copy { background-position: -176px -128px; } 221 | .ui-icon-contact { background-position: -192px -128px; } 222 | .ui-icon-image { background-position: -208px -128px; } 223 | .ui-icon-video { background-position: -224px -128px; } 224 | .ui-icon-script { background-position: -240px -128px; } 225 | .ui-icon-alert { background-position: 0 -144px; } 226 | .ui-icon-info { background-position: -16px -144px; } 227 | .ui-icon-notice { background-position: -32px -144px; } 228 | .ui-icon-help { background-position: -48px -144px; } 229 | .ui-icon-check { background-position: -64px -144px; } 230 | .ui-icon-bullet { background-position: -80px -144px; } 231 | .ui-icon-radio-off { background-position: -96px -144px; } 232 | .ui-icon-radio-on { background-position: -112px -144px; } 233 | .ui-icon-pin-w { background-position: -128px -144px; } 234 | .ui-icon-pin-s { background-position: -144px -144px; } 235 | .ui-icon-play { background-position: 0 -160px; } 236 | .ui-icon-pause { background-position: -16px -160px; } 237 | .ui-icon-seek-next { background-position: -32px -160px; } 238 | .ui-icon-seek-prev { background-position: -48px -160px; } 239 | .ui-icon-seek-end { background-position: -64px -160px; } 240 | .ui-icon-seek-start { background-position: -80px -160px; } 241 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 242 | .ui-icon-seek-first { background-position: -80px -160px; } 243 | .ui-icon-stop { background-position: -96px -160px; } 244 | .ui-icon-eject { background-position: -112px -160px; } 245 | .ui-icon-volume-off { background-position: -128px -160px; } 246 | .ui-icon-volume-on { background-position: -144px -160px; } 247 | .ui-icon-power { background-position: 0 -176px; } 248 | .ui-icon-signal-diag { background-position: -16px -176px; } 249 | .ui-icon-signal { background-position: -32px -176px; } 250 | .ui-icon-battery-0 { background-position: -48px -176px; } 251 | .ui-icon-battery-1 { background-position: -64px -176px; } 252 | .ui-icon-battery-2 { background-position: -80px -176px; } 253 | .ui-icon-battery-3 { background-position: -96px -176px; } 254 | .ui-icon-circle-plus { background-position: 0 -192px; } 255 | .ui-icon-circle-minus { background-position: -16px -192px; } 256 | .ui-icon-circle-close { background-position: -32px -192px; } 257 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 258 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 259 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 260 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 261 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 262 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 263 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 264 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 265 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 266 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 267 | .ui-icon-circle-check { background-position: -208px -192px; } 268 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 269 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 270 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 271 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 272 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 273 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 274 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 275 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 276 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 277 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 278 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 279 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 280 | 281 | 282 | /* Misc visuals 283 | ----------------------------------*/ 284 | 285 | /* Corner radius */ 286 | .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } 287 | .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } 288 | .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } 289 | .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } 290 | 291 | /* Overlays */ 292 | .ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } 293 | .ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*! 294 | * jQuery UI Resizable 1.8.24 295 | * 296 | * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) 297 | * Dual licensed under the MIT or GPL Version 2 licenses. 298 | * http://jquery.org/license 299 | * 300 | * http://docs.jquery.com/UI/Resizable#theming 301 | */ 302 | .ui-resizable { position: relative;} 303 | .ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } 304 | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } 305 | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } 306 | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } 307 | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } 308 | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } 309 | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } 310 | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } 311 | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } 312 | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*! 313 | * jQuery UI Slider 1.8.24 314 | * 315 | * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) 316 | * Dual licensed under the MIT or GPL Version 2 licenses. 317 | * http://jquery.org/license 318 | * 319 | * http://docs.jquery.com/UI/Slider#theming 320 | */ 321 | .ui-slider { position: relative; text-align: left; } 322 | .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } 323 | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } 324 | 325 | .ui-slider-horizontal { height: .8em; } 326 | .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } 327 | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } 328 | .ui-slider-horizontal .ui-slider-range-min { left: 0; } 329 | .ui-slider-horizontal .ui-slider-range-max { right: 0; } 330 | 331 | .ui-slider-vertical { width: .8em; height: 100px; } 332 | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } 333 | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } 334 | .ui-slider-vertical .ui-slider-range-min { bottom: 0; } 335 | .ui-slider-vertical .ui-slider-range-max { top: 0; } 336 | -------------------------------------------------------------------------------- /embed/js/iframe-embed.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Online Python Tutor 4 | https://github.com/pgbovine/OnlinePythonTutor/ 5 | 6 | Copyright (C) 2010-2013 Philip J. Guo (philip@pgbovine.net) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a 9 | copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included 17 | in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | */ 28 | 29 | 30 | // Pre-reqs: 31 | // - pytutor.js 32 | // - jquery.ba-bbq.min.js 33 | // - opt-frontend-common.js 34 | // should all be imported BEFORE this file 35 | 36 | 37 | var myVisualizer = null; // singleton ExecutionVisualizer instance 38 | 39 | 40 | function NOP() {}; 41 | 42 | 43 | $(document).ready(function() { 44 | var queryStrOptions = getQueryStringOptions(); 45 | 46 | var preseededCode = queryStrOptions.preseededCode; 47 | var pyState = queryStrOptions.pyState; 48 | var verticalStackBool = (queryStrOptions.verticalStack == 'true'); 49 | var heapPrimitivesBool = (queryStrOptions.heapPrimitives == 'true'); 50 | var drawParentPointerBool = (queryStrOptions.drawParentPointers == 'true'); 51 | var textRefsBool = (queryStrOptions.textRefs == 'true'); 52 | var showOnlyOutputsBool = (queryStrOptions.showOnlyOutputs == 'true'); 53 | var cumModeBool = (queryStrOptions.cumulativeState == 'true'); 54 | 55 | var codeDivWidth = undefined; 56 | var codeDivWidth = 350; 57 | var cdw = $.bbq.getState('codeDivWidth'); 58 | var cdw = $.bbq.getState('width'); 59 | if (cdw) { 60 | codeDivWidth = Number(cdw); 61 | } 62 | 63 | var codeDivHeight = undefined; 64 | var cdh = $.bbq.getState('codeDivHeight'); 65 | if (cdh) { 66 | codeDivHeight = Number(cdh); 67 | } 68 | 69 | 70 | var startingInstruction = queryStrOptions.preseededCurInstr; 71 | if (!startingInstruction) { 72 | startingInstruction = 0; 73 | } 74 | 75 | var backend_script = null; 76 | if (pyState == '2') { 77 | backend_script = python2_backend_script; 78 | } 79 | else if (pyState == '3') { 80 | backend_script = python3_backend_script; 81 | } 82 | else if (pyState == '2crazy') { 83 | backend_script = python2crazy_backend_script; 84 | } 85 | 86 | 87 | // David Pritchard's code for resizeContainer option ... 88 | var resizeContainer = ($.bbq.getState('resizeContainer') == 'true'); 89 | 90 | if (resizeContainer) { 91 | function findContainer() { 92 | try { 93 | var ifs = window.top.document.getElementsByTagName("iframe"); 94 | for(var i = 0, len = ifs.length; i < len; i++) { 95 | var f = ifs[i]; 96 | var fDoc = f.contentDocument || f.contentWindow.document; 97 | if(fDoc === document) { 98 | return f; 99 | } 100 | } 101 | } catch (e) { 102 | // ignore SecurityError 103 | } 104 | } 105 | 106 | var container = findContainer(); 107 | 108 | function resizeContainerNow() { 109 | $(container).height($("html").height()); 110 | }; 111 | } 112 | 113 | // set up all options in a JS object 114 | var backendOptionsObj = {cumulative_mode: cumModeBool, 115 | heap_primitives: heapPrimitivesBool, 116 | show_only_outputs: showOnlyOutputsBool, 117 | py_crazy_mode: (pyState == '2crazy'), 118 | origin: 'iframe-embed.js'}; 119 | 120 | var frontendOptionsObj = {startingInstruction: startingInstruction, 121 | embeddedMode: true, 122 | verticalStack: verticalStackBool, 123 | disableHeapNesting: true, 124 | drawParentPointers: drawParentPointerBool, 125 | textualMemoryLabels: textRefsBool, 126 | showOnlyOutputs: showOnlyOutputsBool, 127 | executeCodeWithRawInputFunc: executeCodeWithRawInput, 128 | heightChangeCallback: (resizeContainer ? resizeContainerNow : NOP), 129 | 130 | // undocumented experimental modes: 131 | pyCrazyMode: (pyState == '2crazy'), 132 | highlightLines: typeof $.bbq.getState("highlightLines") !== "undefined", 133 | codeDivWidth: codeDivWidth, 134 | codeDivHeight: codeDivHeight, 135 | } 136 | 137 | function executeCode(forceStartingInstr) { 138 | if (forceStartingInstr) { 139 | frontendOptionsObj.startingInstruction = forceStartingInstr; 140 | } 141 | executePythonCode(preseededCode, 142 | backend_script, backendOptionsObj, 143 | frontendOptionsObj, 144 | 'vizDiv', 145 | function() { // success 146 | /* if (serverReply.stdin != "") { 147 | var stdinHTML = '
stdin:
'; 148 | $('#dataViz').append(stdinHTML); 149 | $("#stdinShow").html(serverReply.stdin); 150 | }*/ 151 | if ($.bbq.getState('rightStdout')) { 152 | $("#progOutputs").prependTo("#dataViz"); 153 | }; 154 | if (resizeContainer) 155 | resizeContainerNow(); 156 | }, 157 | NOP); 158 | } 159 | 160 | 161 | function executeCodeFromScratch() { 162 | // reset these globals 163 | rawInputLst = []; 164 | executeCode(); 165 | } 166 | 167 | function executeCodeWithRawInput(rawInputStr, curInstr) { 168 | // set some globals 169 | rawInputLst.push(rawInputStr); 170 | executeCode(curInstr); 171 | } 172 | 173 | 174 | // log a generic AJAX error handler 175 | $(document).ajaxError(function() { 176 | alert("Ugh, Online Python Tutor server error :("); 177 | }); 178 | 179 | 180 | // redraw connector arrows on window resize 181 | $(window).resize(function() { 182 | myVisualizer.redrawConnectors(); 183 | }); 184 | 185 | executeCodeFromScratch(); // finally, execute code and display visualization 186 | 187 | 188 | }); 189 | 190 | -------------------------------------------------------------------------------- /embed/js/jquery.ba-bbq.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 3 | * http://benalman.com/projects/jquery-bbq-plugin/ 4 | * 5 | * Copyright (c) 2010 "Cowboy" Ben Alman 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://benalman.com/about/license/ 8 | */ 9 | (function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); -------------------------------------------------------------------------------- /embed/js/opt-frontend-common.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Online Python Tutor 4 | https://github.com/pgbovine/OnlinePythonTutor/ 5 | 6 | Copyright (C) 2010-2013 Philip J. Guo (philip@pgbovine.net) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a 9 | copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included 17 | in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | */ 28 | 29 | 30 | // backend scripts to execute (Python 2 and 3 variants, if available) 31 | // make two copies of ../web_exec.py and give them the following names, 32 | // then change the first line (starting with #!) to the proper version 33 | // of the Python interpreter (i.e., Python 2 or Python 3). 34 | // Note that your hosting provider might have stringent rules for what 35 | // kind of scripts are allowed to execute. For instance, my provider 36 | // (Webfaction) seems to let scripts execute only if permissions are 37 | // something like: 38 | // -rwxr-xr-x 1 pgbovine pgbovine 2.5K Jul 5 22:46 web_exec_py2.py* 39 | // (most notably, only the owner of the file should have write 40 | // permissions) 41 | //var python2_backend_script = 'web_exec_py2.py'; 42 | //var python3_backend_script = 'web_exec_py3.py'; 43 | 44 | 45 | 46 | var rawInputLst = []; // a list of strings inputted by the user in response to raw_input or mouse_input events 47 | 48 | 49 | function getQueryStringOptions() { 50 | // note that any of these can be 'undefined' 51 | var preseededCode = $.bbq.getState('code'); 52 | var preseededCurInstr = Number($.bbq.getState('curInstr')); 53 | var pyState = $.bbq.getState('py'); 54 | var verticalStack = $.bbq.getState('verticalStack'); 55 | var heapPrimitives = $.bbq.getState('heapPrimitives'); 56 | var drawParentPointers = $.bbq.getState('drawParentPointers'); 57 | var disableHeapNesting = true; 58 | var textRefs = $.bbq.getState('textReferences'); 59 | var showOnlyOutputs = $.bbq.getState('showOnlyOutputs'); 60 | var cumulativeState = $.bbq.getState('cumulative'); 61 | var raw_input = $.bbq.getState('raw_input'); 62 | 63 | return {preseededCode: preseededCode, 64 | preseededCurInstr: preseededCurInstr, 65 | pyState: pyState, 66 | verticalStack: verticalStack, 67 | heapPrimitives: heapPrimitives, 68 | drawParentPointers: drawParentPointers, 69 | disableHeapNesting: disableHeapNesting, 70 | textRefs: textRefs, 71 | showOnlyOutputs: showOnlyOutputs, 72 | cumulativeState: cumulativeState, 73 | raw_input: raw_input}; 74 | } 75 | 76 | 77 | function executePythonCode(pythonSourceCode, 78 | backendScript, backendOptionsObj, 79 | frontendOptionsObj, 80 | outputDiv, 81 | handleSuccessFunc, handleUncaughtExceptionFunc) { 82 | if (!backendScript) { 83 | alert('Server configuration error: No backend script'); 84 | return; 85 | } 86 | 87 | $.get(backendScript, 88 | {data:$.bbq.getState('data')}, 89 | /* 90 | raw_input_json: rawInputLst.length > 0 ? JSON.stringify(rawInputLst) : '', 91 | */ 92 | function(dataFromBackend) { 93 | var trace = dataFromBackend.trace; 94 | 95 | // don't enter visualize mode if there are killer errors: 96 | if (!trace || 97 | (trace.length == 0) || 98 | (trace[trace.length - 1].event == 'uncaught_exception')) { 99 | 100 | handleUncaughtExceptionFunc(trace); 101 | 102 | if (trace.length == 1) { 103 | alert(trace[0].exception_msg); 104 | } 105 | else if (trace[trace.length - 1].exception_msg) { 106 | alert(trace[trace.length - 1].exception_msg); 107 | } 108 | else { 109 | alert("Unknown error. Reload to try again," + 110 | "or report a bug to philip@pgbovine.net\n\n" + 111 | "(Click the 'Generate URL' button to include a " + 112 | "unique URL in your email bug report.)"); 113 | } 114 | } 115 | else { 116 | // fail-soft to prevent running off of the end of trace 117 | if (frontendOptionsObj.startingInstruction >= trace.length) { 118 | frontendOptionsObj.startingInstruction = 0; 119 | } 120 | myVisualizer = new ExecutionVisualizer(outputDiv, dataFromBackend, frontendOptionsObj); 121 | 122 | // set keyboard bindings 123 | // VERY IMPORTANT to clear and reset this every time or 124 | // else the handlers might be bound multiple times 125 | $(document).unbind('keydown'); 126 | $(document).keydown(function(k) { 127 | if (k.keyCode == 37) { // left arrow 128 | if (myVisualizer.stepBack()) { 129 | k.preventDefault(); // don't horizontally scroll the display 130 | } 131 | } 132 | else if (k.keyCode == 39) { // right arrow 133 | if (myVisualizer.stepForward()) { 134 | k.preventDefault(); // don't horizontally scroll the display 135 | } 136 | } 137 | }); 138 | 139 | handleSuccessFunc(); 140 | } 141 | }, 142 | "json"); 143 | } 144 | -------------------------------------------------------------------------------- /embed/js/opt-frontend.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Online Python Tutor 4 | https://github.com/pgbovine/OnlinePythonTutor/ 5 | 6 | Copyright (C) 2010-2013 Philip J. Guo (philip@pgbovine.net) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a 9 | copy of this software and associated documentation files (the 10 | "Software"), to deal in the Software without restriction, including 11 | without limitation the rights to use, copy, modify, merge, publish, 12 | distribute, sublicense, and/or sell copies of the Software, and to 13 | permit persons to whom the Software is furnished to do so, subject to 14 | the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included 17 | in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | */ 28 | 29 | 30 | 31 | // Pre-reqs: 32 | // - pytutor.js 33 | // - jquery.ba-bbq.min.js 34 | // - opt-frontend-common.js 35 | // should all be imported BEFORE this file 36 | 37 | var appMode = 'edit'; // 'edit', 'display', or 'display_no_frills' 38 | 39 | var preseededCurInstr = null; // if you passed in a 'curInstr=' in the URL, then set this var 40 | 41 | var myVisualizer = null; // singleton ExecutionVisualizer instance 42 | 43 | 44 | function enterEditMode() { 45 | $.bbq.pushState({ mode: 'edit' }, 2 /* completely override other hash strings to keep URL clean */); 46 | } 47 | 48 | function enterDisplayNoFrillsMode() { 49 | $.bbq.pushState({ mode: 'display_no_frills' }, 2 /* completely override other hash strings to keep URL clean */); 50 | } 51 | 52 | var pyInputCodeMirror; // CodeMirror object that contains the input text 53 | 54 | function setCodeMirrorVal(dat) { 55 | pyInputCodeMirror.setValue(dat.rtrim() /* kill trailing spaces */); 56 | $('#urlOutput,#embedCodeOutput').val(''); 57 | 58 | // also scroll to top to make the UI more usable on smaller monitors 59 | $(document).scrollTop(0); 60 | } 61 | 62 | 63 | $(document).ready(function() { 64 | 65 | $("#embedLinkDiv").hide(); 66 | 67 | pyInputCodeMirror = CodeMirror(document.getElementById('codeInputPane'), { 68 | mode: 69 | {name: "python", 70 | version: 3, 71 | singleLineStringErrors: false 72 | }, 73 | lineNumbers: true, 74 | indentUnit: 3, 75 | tabSize: 3, 76 | matchBrackets: true, 77 | extraKeys: { 78 | Tab: function(cm) { 79 | var spaces = Array(cm.getOption("indentUnit") + 1).join(" "); 80 | cm.replaceSelection(spaces, "end", "+input"); 81 | } 82 | } 83 | }); 84 | 85 | //pyInputCodeMirror.setSize(null, '240px'); 86 | 87 | 88 | 89 | // be friendly to the browser's forward and back buttons 90 | // thanks to http://benalman.com/projects/jquery-bbq-plugin/ 91 | $(window).bind("hashchange", function(e) { 92 | appMode = $.bbq.getState('mode'); // assign this to the GLOBAL appMode 93 | 94 | if (appMode === undefined || appMode == 'edit') { 95 | $("#pyInputPane").show(); 96 | $("#pyOutputPane").hide(); 97 | $("#embedLinkDiv").hide(); 98 | 99 | // destroy all annotation bubbles (NB: kludgy) 100 | if (myVisualizer) { 101 | myVisualizer.destroyAllAnnotationBubbles(); 102 | } 103 | } 104 | else if (appMode == 'display') { 105 | $("#pyInputPane").hide(); 106 | $("#pyOutputPane").show(); 107 | 108 | $("#embedLinkDiv").show(); 109 | 110 | $('#executeBtn').html("Visualize Execution"); 111 | $('#executeBtn').attr('disabled', false); 112 | 113 | 114 | // do this AFTER making #pyOutputPane visible, or else 115 | // jsPlumb connectors won't render properly 116 | myVisualizer.updateOutput(); 117 | 118 | // customize edit button click functionality AFTER rendering (NB: awkward!) 119 | $('#pyOutputPane #editCodeLinkDiv').show(); 120 | $('#pyOutputPane #editBtn').click(function() { 121 | enterEditMode(); 122 | }); 123 | } 124 | else if (appMode == 'display_no_frills') { 125 | $("#pyInputPane").hide(); 126 | $("#pyOutputPane").show(); 127 | $("#embedLinkDiv").show(); 128 | } 129 | else { 130 | assert(false); 131 | } 132 | 133 | $('#urlOutput,#embedCodeOutput').val(''); // clear to avoid stale values 134 | }); 135 | 136 | function getRawInput() { 137 | if (typeof window.stdinPane === "undefined") 138 | return ""; 139 | else return window.stdinPane.value; 140 | } 141 | 142 | function executeCode(forceStartingInstr) { 143 | var backend_script = null; 144 | if ($('#pythonVersionSelector').val() == '2') { 145 | backend_script = python2_backend_script; 146 | } 147 | else if ($('#pythonVersionSelector').val() == '3') { 148 | backend_script = python3_backend_script; 149 | } 150 | // experimental KRAZY MODE!!! 151 | else if ($('#pythonVersionSelector').val() == '2crazy') { 152 | backend_script = python2crazy_backend_script; 153 | } 154 | 155 | $('#executeBtn').html("Please wait ... processing your code"); 156 | $('#executeBtn').attr('disabled', true); 157 | $("#pyOutputPane").hide(); 158 | $("#embedLinkDiv").hide(); 159 | 160 | var backendOptionsObj = {cumulative_mode: ($('#cumulativeModeSelector').val() == 'true'), 161 | heap_primitives: ($('#heapPrimitivesSelector').val() == 'true'), 162 | show_only_outputs: ($('#showOnlyOutputsSelector').val() == 'true'), 163 | py_crazy_mode: ($('#pythonVersionSelector').val() == '2crazy'), 164 | raw_input: getRawInput(), 165 | origin: 'opt-frontend.js'}; 166 | 167 | 168 | var startingInstruction = 0; 169 | 170 | // only do this at most ONCE, and then clear out preseededCurInstr 171 | // NOP anyways if preseededCurInstr is 0 172 | if (preseededCurInstr) { 173 | startingInstruction = preseededCurInstr; 174 | preseededCurInstr = null; 175 | } 176 | 177 | // forceStartingInstr overrides everything else 178 | if (forceStartingInstr !== undefined) { 179 | startingInstruction = forceStartingInstr; 180 | } 181 | 182 | var frontendOptionsObj = {startingInstruction: startingInstruction, 183 | // tricky: selector 'true' and 'false' values are strings! 184 | disableHeapNesting: ($('#heapPrimitivesSelector').val() == 'true'), 185 | drawParentPointers: ($('#drawParentPointerSelector').val() == 'true'), 186 | textualMemoryLabels: ($('#textualMemoryLabelsSelector').val() == 'true'), 187 | showOnlyOutputs: ($('#showOnlyOutputsSelector').val() == 'true'), 188 | executeCodeWithRawInputFunc: executeCodeWithRawInput, 189 | updateOutputCallback: function() {$('#urlOutput,#embedCodeOutput').val('');}, 190 | 191 | // undocumented experimental modes: 192 | pyCrazyMode: ($('#pythonVersionSelector').val() == '2crazy'), 193 | //allowEditAnnotations: true, 194 | 195 | highlightLines: true, 196 | } 197 | 198 | function handleSuccessFunc() { 199 | // also scroll to top to make the UI more usable on smaller monitors 200 | $(document).scrollTop(0); 201 | 202 | $.bbq.pushState({ mode: 'display' }, 2 /* completely override other hash strings to keep URL clean */); 203 | } 204 | 205 | function handleUncaughtExceptionFunc(trace) { 206 | if (trace.length == 1) { 207 | var errorLineNo = trace[0].line - 1; /* CodeMirror lines are zero-indexed */ 208 | if (errorLineNo !== undefined) { 209 | // highlight the faulting line in pyInputCodeMirror 210 | pyInputCodeMirror.focus(); 211 | /* CodeMirror 2 212 | pyInputCodeMirror.setCursor(errorLineNo, 0); 213 | pyInputCodeMirror.setLineClass(errorLineNo, null, 'errorLine'); 214 | 215 | pyInputCodeMirror.setOption('onChange', function() { 216 | pyInputCodeMirror.setLineClass(errorLineNo, null, null); // reset line back to normal 217 | pyInputCodeMirror.setOption('onChange', null); // cancel 218 | }); 219 | */ 220 | /* CodeMirror 3 */ 221 | var marked = pyInputCodeMirror.addLineClass(errorLineNo, null, 'errorLine'); 222 | var hook = function(marked) { return function() { 223 | pyInputCodeMirror.removeLineClass(marked, null, 'errorLine'); // reset line back to normal 224 | pyInputCodeMirror.off('change', hook); // cancel 225 | }} (marked); 226 | pyInputCodeMirror.on('change', hook); 227 | 228 | } 229 | 230 | $('#executeBtn').html("Visualize Execution"); 231 | $('#executeBtn').attr('disabled', false); 232 | } 233 | } 234 | 235 | executePythonCode(pyInputCodeMirror.getValue(), 236 | backend_script, backendOptionsObj, 237 | frontendOptionsObj, 238 | 'pyOutputPane', 239 | handleSuccessFunc, handleUncaughtExceptionFunc); 240 | } 241 | 242 | function executeCodeFromScratch() { 243 | // reset these globals 244 | rawInputLst = []; 245 | executeCode(); 246 | } 247 | 248 | function executeCodeWithRawInput(rawInputStr, curInstr) { 249 | enterDisplayNoFrillsMode(); 250 | 251 | // set some globals 252 | rawInputLst.push(rawInputStr); 253 | executeCode(curInstr); 254 | } 255 | 256 | $("#executeBtn").attr('disabled', false); 257 | $("#executeBtn").click(executeCodeFromScratch); 258 | 259 | 260 | // canned examples 261 | 262 | $("#tutorialExampleLink").click(function() { 263 | $.get("example-code/py_tutorial.txt", setCodeMirrorVal); 264 | return false; 265 | }); 266 | 267 | $("#strtokExampleLink").click(function() { 268 | $.get("example-code/strtok.txt", setCodeMirrorVal); 269 | return false; 270 | }); 271 | 272 | $("#listCompLink").click(function() { 273 | $.get("example-code/list-comp.txt", setCodeMirrorVal); 274 | return false; 275 | }); 276 | 277 | $("#fibonacciExampleLink").click(function() { 278 | $.get("example-code/fib.txt", setCodeMirrorVal); 279 | return false; 280 | }); 281 | 282 | $("#memoFibExampleLink").click(function() { 283 | $.get("example-code/memo_fib.txt", setCodeMirrorVal); 284 | return false; 285 | }); 286 | 287 | $("#factExampleLink").click(function() { 288 | $.get("example-code/fact.txt", setCodeMirrorVal); 289 | return false; 290 | }); 291 | 292 | $("#filterExampleLink").click(function() { 293 | $.get("example-code/filter.txt", setCodeMirrorVal); 294 | return false; 295 | }); 296 | 297 | $("#insSortExampleLink").click(function() { 298 | $.get("example-code/ins_sort.txt", setCodeMirrorVal); 299 | return false; 300 | }); 301 | 302 | $("#aliasExampleLink").click(function() { 303 | $.get("example-code/aliasing.txt", setCodeMirrorVal); 304 | return false; 305 | }); 306 | 307 | $("#happyExampleLink").click(function() { 308 | $.get("example-code/happy.txt", setCodeMirrorVal); 309 | return false; 310 | }); 311 | 312 | $("#newtonExampleLink").click(function() { 313 | $.get("example-code/sqrt.txt", setCodeMirrorVal); 314 | return false; 315 | }); 316 | 317 | $("#oopSmallExampleLink").click(function() { 318 | $.get("example-code/oop_small.txt", setCodeMirrorVal); 319 | return false; 320 | }); 321 | 322 | $("#mapExampleLink").click(function() { 323 | $.get("example-code/map.txt", setCodeMirrorVal); 324 | return false; 325 | }); 326 | 327 | $("#rawInputExampleLink").click(function() { 328 | $.get("example-code/raw_input.txt", setCodeMirrorVal); 329 | return false; 330 | }); 331 | 332 | $("#oop1ExampleLink").click(function() { 333 | $.get("example-code/oop_1.txt", setCodeMirrorVal); 334 | return false; 335 | }); 336 | 337 | $("#oop2ExampleLink").click(function() { 338 | $.get("example-code/oop_2.txt", setCodeMirrorVal); 339 | return false; 340 | }); 341 | 342 | $("#inheritanceExampleLink").click(function() { 343 | $.get("example-code/oop_inherit.txt", setCodeMirrorVal); 344 | return false; 345 | }); 346 | 347 | $("#sumExampleLink").click(function() { 348 | $.get("example-code/sum.txt", setCodeMirrorVal); 349 | return false; 350 | }); 351 | 352 | $("#pwGcdLink").click(function() { 353 | $.get("example-code/wentworth_gcd.txt", setCodeMirrorVal); 354 | return false; 355 | }); 356 | 357 | $("#pwSumListLink").click(function() { 358 | $.get("example-code/wentworth_sumList.txt", setCodeMirrorVal); 359 | return false; 360 | }); 361 | 362 | $("#towersOfHanoiLink").click(function() { 363 | $.get("example-code/towers_of_hanoi.txt", setCodeMirrorVal); 364 | return false; 365 | }); 366 | 367 | $("#pwTryFinallyLink").click(function() { 368 | $.get("example-code/wentworth_try_finally.txt", setCodeMirrorVal); 369 | return false; 370 | }); 371 | 372 | $("#sumCubesLink").click(function() { 373 | $.get("example-code/sum-cubes.txt", setCodeMirrorVal); 374 | return false; 375 | }); 376 | 377 | $("#decoratorsLink").click(function() { 378 | $.get("example-code/decorators.txt", setCodeMirrorVal); 379 | return false; 380 | }); 381 | 382 | $("#genPrimesLink").click(function() { 383 | $.get("example-code/gen_primes.txt", setCodeMirrorVal); 384 | return false; 385 | }); 386 | 387 | $("#genExprLink").click(function() { 388 | $.get("example-code/genexpr.txt", setCodeMirrorVal); 389 | return false; 390 | }); 391 | 392 | 393 | $('#closure1Link').click(function() { 394 | $.get("example-code/closures/closure1.txt", setCodeMirrorVal); 395 | return false; 396 | }); 397 | $('#closure2Link').click(function() { 398 | $.get("example-code/closures/closure2.txt", setCodeMirrorVal); 399 | return false; 400 | }); 401 | $('#closure3Link').click(function() { 402 | $.get("example-code/closures/closure3.txt", setCodeMirrorVal); 403 | return false; 404 | }); 405 | $('#closure4Link').click(function() { 406 | $.get("example-code/closures/closure4.txt", setCodeMirrorVal); 407 | return false; 408 | }); 409 | $('#closure5Link').click(function() { 410 | $.get("example-code/closures/closure5.txt", setCodeMirrorVal); 411 | return false; 412 | }); 413 | $('#lambdaParamLink').click(function() { 414 | $.get("example-code/closures/lambda-param.txt", setCodeMirrorVal); 415 | return false; 416 | }); 417 | $('#tortureLink').click(function() { 418 | $.get("example-code/closures/student-torture.txt", setCodeMirrorVal); 419 | return false; 420 | }); 421 | 422 | 423 | 424 | $('#aliasing1Link').click(function() { 425 | $.get("example-code/aliasing/aliasing1.txt", setCodeMirrorVal); 426 | return false; 427 | }); 428 | $('#aliasing2Link').click(function() { 429 | $.get("example-code/aliasing/aliasing2.txt", setCodeMirrorVal); 430 | return false; 431 | }); 432 | $('#aliasing3Link').click(function() { 433 | $.get("example-code/aliasing/aliasing3.txt", setCodeMirrorVal); 434 | return false; 435 | }); 436 | $('#aliasing4Link').click(function() { 437 | $.get("example-code/aliasing/aliasing4.txt", setCodeMirrorVal); 438 | return false; 439 | }); 440 | $('#aliasing5Link').click(function() { 441 | $.get("example-code/aliasing/aliasing5.txt", setCodeMirrorVal); 442 | return false; 443 | }); 444 | $('#aliasing6Link').click(function() { 445 | $.get("example-code/aliasing/aliasing6.txt", setCodeMirrorVal); 446 | return false; 447 | }); 448 | $('#aliasing7Link').click(function() { 449 | $.get("example-code/aliasing/aliasing7.txt", setCodeMirrorVal); 450 | return false; 451 | }); 452 | $('#aliasing8Link').click(function() { 453 | $.get("example-code/aliasing/aliasing8.txt", setCodeMirrorVal); 454 | return false; 455 | }); 456 | 457 | 458 | $('#ll1Link').click(function() { 459 | $.get("example-code/linked-lists/ll1.txt", setCodeMirrorVal); 460 | return false; 461 | }); 462 | $('#ll2Link').click(function() { 463 | $.get("example-code/linked-lists/ll2.txt", setCodeMirrorVal); 464 | return false; 465 | }); 466 | $('#sumListLink').click(function() { 467 | $.get("example-code/sum-list.txt", setCodeMirrorVal); 468 | return false; 469 | }); 470 | 471 | $('#varargsLink').click(function() { 472 | $.get("example-code/varargs.txt", setCodeMirrorVal); 473 | return false; 474 | }); 475 | 476 | $('#forElseLink').click(function() { 477 | $.get("example-code/for-else.txt", setCodeMirrorVal); 478 | return false; 479 | }); 480 | 481 | $('#nonlocalLink').click(function() { 482 | $.get("example-code/nonlocal.txt", setCodeMirrorVal); 483 | return false; 484 | }); 485 | 486 | 487 | var queryStrOptions = getQueryStringOptions(); 488 | 489 | if (queryStrOptions.preseededCode) { 490 | setCodeMirrorVal(queryStrOptions.preseededCode); 491 | } 492 | else { 493 | // select a canned example on start-up: 494 | // $("#aliasExampleLink").trigger('click'); 495 | } 496 | 497 | if (queryStrOptions.raw_input !== undefined) { 498 | window.stdinPane.value = queryStrOptions.raw_input; 499 | } 500 | 501 | // ugh, ugly tristate due to the possibility of each being undefined 502 | if (queryStrOptions.pyState !== undefined) { 503 | $('#pythonVersionSelector').val(queryStrOptions.pyState); 504 | } 505 | if (queryStrOptions.cumulativeState !== undefined) { 506 | $('#cumulativeModeSelector').val(queryStrOptions.cumulativeState); 507 | } 508 | if (queryStrOptions.heapPrimitives !== undefined) { 509 | $('#heapPrimitivesSelector').val(queryStrOptions.heapPrimitives); 510 | } 511 | if (queryStrOptions.drawParentPointers !== undefined) { 512 | $('#drawParentPointerSelector').val(queryStrOptions.drawParentPointers); 513 | } 514 | if (queryStrOptions.textRefs !== undefined) { 515 | $('#textualMemoryLabelsSelector').val(queryStrOptions.textRefs); 516 | } 517 | if (queryStrOptions.showOnlyOutputs !== undefined) { 518 | $('#showOnlyOutputsSelector').val(queryStrOptions.showOnlyOutputs); 519 | } 520 | 521 | 522 | appMode = $.bbq.getState('mode'); // assign this to the GLOBAL appMode 523 | if ((appMode == "display") && queryStrOptions.preseededCode /* jump to display only with pre-seeded code */) { 524 | preseededCurInstr = queryStrOptions.preseededCurInstr; // ugly global 525 | $("#executeBtn").trigger('click'); 526 | } 527 | else { 528 | if (appMode === undefined) { 529 | // default mode is 'edit', don't trigger a "hashchange" event 530 | appMode = 'edit'; 531 | } 532 | else { 533 | // fail-soft by killing all passed-in hashes and triggering a "hashchange" 534 | // event, which will then go to 'edit' mode 535 | $.bbq.removeState(); 536 | } 537 | } 538 | 539 | 540 | // log a generic AJAX error handler 541 | $(document).ajaxError(function() { 542 | alert("Server error (possibly due to memory/resource overload). " + 543 | "Report a bug to philip@pgbovine.net\n\n" + 544 | "(Click the 'Generate URL' button to include a unique URL in your email bug report.)"); 545 | 546 | $('#executeBtn').html("Visualize Execution"); 547 | $('#executeBtn').attr('disabled', false); 548 | }); 549 | 550 | 551 | // redraw connector arrows on window resize 552 | $(window).resize(function() { 553 | if (appMode == 'display') { 554 | myVisualizer.redrawConnectors(); 555 | } 556 | }); 557 | 558 | $('#genUrlBtn').bind('click', function() { 559 | var myArgs = {code: pyInputCodeMirror.getValue(), 560 | mode: appMode, 561 | //cumulative: $('#cumulativeModeSelector').val(), 562 | //heapPrimitives: $('#heapPrimitivesSelector').val(), 563 | //drawParentPointers: $('#drawParentPointerSelector').val(), 564 | //textReferences: $('#textualMemoryLabelsSelector').val(), 565 | //showOnlyOutputs: $('#showOnlyOutputsSelector').val(), 566 | //py: $('#pythonVersionSelector').val() 567 | raw_input: getRawInput(), 568 | }; 569 | 570 | if (appMode == 'display') { 571 | myArgs.curInstr = myVisualizer.curInstr; 572 | } 573 | 574 | var urlStr = $.param.fragment(window.location.href, myArgs, 2 /* clobber all */); 575 | $('#urlOutput').val(urlStr); 576 | }); 577 | 578 | 579 | $('#genEmbedBtn').bind('click', function() { 580 | assert(appMode == 'display'); 581 | var myArgs = {code: pyInputCodeMirror.getValue(), 582 | cumulative: $('#cumulativeModeSelector').val(), 583 | heapPrimitives: $('#heapPrimitivesSelector').val(), 584 | drawParentPointers: $('#drawParentPointerSelector').val(), 585 | textReferences: $('#textualMemoryLabelsSelector').val(), 586 | showOnlyOutputs: $('#showOnlyOutputsSelector').val(), 587 | py: $('#pythonVersionSelector').val(), 588 | curInstr: myVisualizer.curInstr, 589 | codeDivWidth: myVisualizer.DEFAULT_EMBEDDED_CODE_DIV_WIDTH, 590 | codeDivHeight: myVisualizer.DEFAULT_EMBEDDED_CODE_DIV_HEIGHT, 591 | }; 592 | 593 | var embedUrlStr = $.param.fragment(domain + "iframe-embed.html", myArgs, 2 /* clobber all */); 594 | var iframeStr = ''; 595 | $('#embedCodeOutput').val(iframeStr); 596 | }); 597 | }); 598 | 599 | -------------------------------------------------------------------------------- /example-code/(Default).java: -------------------------------------------------------------------------------- 1 | public class ClassNameHere { 2 | public static void main(String[] args) { 3 | 4 | } 5 | } -------------------------------------------------------------------------------- /example-code/.dir-locals.el: -------------------------------------------------------------------------------- 1 | ( 2 | (java-mode 3 | (indent-tabs-mode . nil) 4 | (c-basic-offset . 3)) 5 | ) 6 | -------------------------------------------------------------------------------- /example-code/.gitignore: -------------------------------------------------------------------------------- 1 | Fakey.java -------------------------------------------------------------------------------- /example-code/.htaccess: -------------------------------------------------------------------------------- 1 | Options +Indexes -------------------------------------------------------------------------------- /example-code/Casting.java: -------------------------------------------------------------------------------- 1 | public class Casting { 2 | public static void main(String[] args) { 3 | // casting doesn't change the object 4 | Object obj; 5 | { 6 | Stopwatch w = new Stopwatch(); 7 | obj = w; 8 | } 9 | System.out.println(obj); // still a Stopwatch 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example-code/CmdLineArgs.java: -------------------------------------------------------------------------------- 1 | public class CmdLineArgs { 2 | public static void main(String[] args) { 3 | // you can change "args" in the boxes below this window 4 | int a = Integer.parseInt(args[0]); 5 | int b = Integer.parseInt(args[1]); 6 | int sum = a + b; 7 | int prod = a * b; 8 | int quot = a / b; 9 | int rem = a % b; 10 | System.out.println(a + " + " + b + " = " + sum); 11 | System.out.println(a + " * " + b + " = " + prod); 12 | System.out.println(a + " / " + b + " = " + quot); 13 | System.out.println(a + " % " + b + " = " + rem); 14 | } 15 | } 16 | /*viz_options {"args":["1234","99"]}*/ -------------------------------------------------------------------------------- /example-code/Complex.java: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * From: http://introcs.cs.princeton.edu/java/home/ (Section 9.7) 3 | * 4 | * Compilation: javac Complex.java 5 | * Execution: java Complex 6 | * 7 | * Data type for complex numbers. 8 | * 9 | * The data type is "immutable" so once you create and initialize 10 | * a Complex object, you cannot change it. The "final" keyword 11 | * when declaring re and im enforces this rule, making it a 12 | * compile-time error to change the .re or .im fields after 13 | * they've been initialized. 14 | * 15 | * % java Complex 16 | * a = 5.0 + 6.0i 17 | * b = -3.0 + 4.0i 18 | * Re(a) = 5.0 19 | * Im(a) = 6.0 20 | * b + a = 2.0 + 10.0i 21 | * a - b = 8.0 + 2.0i 22 | * a * b = -39.0 + 2.0i 23 | * b * a = -39.0 + 2.0i 24 | * a / b = 0.36 - 1.52i 25 | * (a / b) * b = 5.0 + 6.0i 26 | * conj(a) = 5.0 - 6.0i 27 | * |a| = 7.810249675906654 28 | * tan(a) = -6.685231390246571E-6 + 1.0000103108981198i 29 | * 30 | *************************************************************************/ 31 | 32 | public class Complex { 33 | private final double re; // the real part 34 | private final double im; // the imaginary part 35 | 36 | // create a new object with the given real and imaginary parts 37 | public Complex(double real, double imag) { 38 | re = real; 39 | im = imag; 40 | } 41 | 42 | // return a string representation of the invoking Complex object 43 | public String toString() { 44 | if (im == 0) return re + ""; 45 | if (re == 0) return im + "i"; 46 | if (im < 0) return re + " - " + (-im) + "i"; 47 | return re + " + " + im + "i"; 48 | } 49 | 50 | // return abs/modulus/magnitude and angle/phase/argument 51 | public double abs() { return Math.hypot(re, im); } // Math.sqrt(re*re + im*im) 52 | public double phase() { return Math.atan2(im, re); } // between -pi and pi 53 | 54 | // return a new Complex object whose value is (this + b) 55 | public Complex plus(Complex b) { 56 | Complex a = this; // invoking object 57 | double real = a.re + b.re; 58 | double imag = a.im + b.im; 59 | return new Complex(real, imag); 60 | } 61 | 62 | // return a new Complex object whose value is (this - b) 63 | public Complex minus(Complex b) { 64 | Complex a = this; 65 | double real = a.re - b.re; 66 | double imag = a.im - b.im; 67 | return new Complex(real, imag); 68 | } 69 | 70 | // return a new Complex object whose value is (this * b) 71 | public Complex times(Complex b) { 72 | Complex a = this; 73 | double real = a.re * b.re - a.im * b.im; 74 | double imag = a.re * b.im + a.im * b.re; 75 | return new Complex(real, imag); 76 | } 77 | 78 | // scalar multiplication 79 | // return a new object whose value is (this * alpha) 80 | public Complex times(double alpha) { 81 | return new Complex(alpha * re, alpha * im); 82 | } 83 | 84 | // return a new Complex object whose value is the conjugate of this 85 | public Complex conjugate() { return new Complex(re, -im); } 86 | 87 | // return a new Complex object whose value is the reciprocal of this 88 | public Complex reciprocal() { 89 | double scale = re*re + im*im; 90 | return new Complex(re / scale, -im / scale); 91 | } 92 | 93 | // return the real or imaginary part 94 | public double re() { return re; } 95 | public double im() { return im; } 96 | 97 | // return a / b 98 | public Complex divides(Complex b) { 99 | Complex a = this; 100 | return a.times(b.reciprocal()); 101 | } 102 | 103 | // return a new Complex object whose value is the complex exponential of this 104 | public Complex exp() { 105 | return new Complex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im)); 106 | } 107 | 108 | // return a new Complex object whose value is the complex sine of this 109 | public Complex sin() { 110 | return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im)); 111 | } 112 | 113 | // return a new Complex object whose value is the complex cosine of this 114 | public Complex cos() { 115 | return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im)); 116 | } 117 | 118 | // return a new Complex object whose value is the complex tangent of this 119 | public Complex tan() { 120 | return sin().divides(cos()); 121 | } 122 | 123 | 124 | 125 | // a static version of plus 126 | public static Complex plus(Complex a, Complex b) { 127 | double real = a.re + b.re; 128 | double imag = a.im + b.im; 129 | Complex sum = new Complex(real, imag); 130 | return sum; 131 | } 132 | 133 | 134 | 135 | // sample client for testing 136 | public static void main(String[] args) { 137 | Complex a = new Complex(5.0, 6.0); 138 | Complex b = new Complex(-3.0, 4.0); 139 | 140 | System.out.println("a = " + a); 141 | System.out.println("b = " + b); 142 | System.out.println("Re(a) = " + a.re()); 143 | System.out.println("Im(a) = " + a.im()); 144 | System.out.println("b + a = " + b.plus(a)); 145 | System.out.println("a - b = " + a.minus(b)); 146 | System.out.println("a * b = " + a.times(b)); 147 | System.out.println("b * a = " + b.times(a)); 148 | System.out.println("a / b = " + a.divides(b)); 149 | System.out.println("(a / b) * b = " + a.divides(b).times(b)); 150 | System.out.println("conj(a) = " + a.conjugate()); 151 | System.out.println("|a| = " + a.abs()); 152 | } 153 | 154 | } -------------------------------------------------------------------------------- /example-code/ControlFlow.java: -------------------------------------------------------------------------------- 1 | public class ControlFlow { 2 | public static void main(String[] args) { 3 | while (true) { 4 | double roll = 3*Math.random(); 5 | if (roll > 2.8) 6 | break; 7 | if ((int)roll == 2) 8 | continue; 9 | else if ((int)roll == 0) 10 | System.out.println("low"); 11 | else 12 | System.out.println("hi"); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /example-code/Exception.java: -------------------------------------------------------------------------------- 1 | public class Exception { 2 | public static void main(String[] args) { 3 | // this one will be caught 4 | int x = 0; 5 | try { 6 | x = 1/x; 7 | } 8 | catch (RuntimeException e) { 9 | x = -1; 10 | System.out.println("Caught!"); 11 | } 12 | System.out.println(x); 13 | 14 | System.out.println(1/0); 15 | System.out.println("this won't run"); 16 | } 17 | } -------------------------------------------------------------------------------- /example-code/ExceptionFlow.java: -------------------------------------------------------------------------------- 1 | public class ExceptionFlow { 2 | static String trace = ""; 3 | 4 | static void f() { 5 | trace += "call-f "; 6 | g(); 7 | trace += "return-f "; 8 | } 9 | 10 | static void g() { 11 | trace += "call-g "; 12 | int z = 1/0; 13 | trace += "return-g "; 14 | } 15 | 16 | public static void main(String[] args) { 17 | try { 18 | f(); 19 | } 20 | catch (RuntimeException e) { 21 | trace += "caught!"; 22 | } 23 | System.out.println(trace); 24 | } 25 | } -------------------------------------------------------------------------------- /example-code/ExecLimit.java: -------------------------------------------------------------------------------- 1 | public class ExecLimit { 2 | public static void main(String[] args) { 3 | int sum = 0; 4 | for (int i=0; i<300; i++) 5 | sum += i; 6 | } 7 | } -------------------------------------------------------------------------------- /example-code/Forest.java: -------------------------------------------------------------------------------- 1 | // Princeton COS 126 Written Exam 2, Fall 2010, Question 3 2 | // note: this is a proof-of-concept, but to do this on 3 | // paper you would instead skip as many internal steps of 4 | // root, merge, and merged as possible 5 | 6 | public class Node { 7 | private Node next; 8 | private int index; 9 | private Node root() { 10 | if (next == null) return this; 11 | return next.root(); 12 | } 13 | public static void merge(Node a, Node b) { 14 | a.root().next = b.root(); 15 | } 16 | public static boolean merged(Node a, Node b) { 17 | return a.root() == b.root(); 18 | } 19 | public static void main(String[] args) { 20 | Node[] f = new Node[8]; 21 | for (int i=0; i<8; i++) {f[i] = new Node(); f[i].index=i;} 22 | merge(f[0], f[3]); 23 | merge(f[1], f[2]); 24 | merge(f[1], f[4]); 25 | merge(f[5], f[6]); 26 | merge(f[3], f[4]); 27 | merge(f[7], f[5]); 28 | 29 | System.out.println(merged(f[0], f[3])); 30 | System.out.println(merged(f[0], f[7])); 31 | System.out.println(merged(f[1], f[3])); 32 | System.out.println(merged(f[4], f[5])); 33 | } 34 | } -------------------------------------------------------------------------------- /example-code/Knapsack.java: -------------------------------------------------------------------------------- 1 | public class Knapsack { 2 | public static void main(String[] args) { 3 | int[] itemSizes = {3, 5, 6, 8}; 4 | int capacity = 15; 5 | boolean[] canMakeSum = new boolean[capacity+1]; 6 | canMakeSum[0] = true; 7 | for (int size : itemSizes) { 8 | for (int i=capacity; i>=size; i--) 9 | canMakeSum[i] |= canMakeSum[i-size]; 10 | } 11 | System.out.println(java.util.Arrays.toString(canMakeSum)); 12 | } 13 | } -------------------------------------------------------------------------------- /example-code/LambdaExample.java: -------------------------------------------------------------------------------- 1 | import java.util.function.*; 2 | 3 | public class LambdaExample { 4 | // note: this only works in Java 8 5 | 6 | static Function inc(int x) { 7 | return y -> x+y; 8 | } 9 | 10 | static Function mul(int x) { 11 | return y -> x*y; 12 | } 13 | 14 | public static void main(String[] args) { 15 | // bad style, generic erasure to get array 16 | Function[] fs = {inc(5), inc(10), mul(7), mul(2)}; 17 | 18 | for (Function f : fs) 19 | System.out.println( 20 | ((Function)f).apply(100)); 21 | } 22 | } -------------------------------------------------------------------------------- /example-code/LinkedList.java: -------------------------------------------------------------------------------- 1 | // named after barrel of monkeys: 2 | // each one hangs on to the next 3 | public class LinkedList { 4 | 5 | // structure of items in list 6 | class Node { 7 | // each node knows "next" node 8 | Node next; 9 | // and stores a value 10 | String name; 11 | // constructor for nodes 12 | Node(String initialName) { 13 | name = initialName; 14 | } 15 | } 16 | 17 | // beginning of the list, initially empty 18 | private Node first = null; 19 | 20 | // a demo to create a length-3 list 21 | public void threeKongs() { 22 | first = new Node("DK Sr."); 23 | first.next = new Node("DK"); 24 | first.next.next = new Node("DK Jr."); 25 | } 26 | 27 | // use a loop to print all 28 | public void printAll() { 29 | // a while loop also can work 30 | for (Node current = first; 31 | current != null; 32 | current = current.next) { 33 | System.out.println(current.name); 34 | } 35 | } 36 | 37 | public static void main(String[] args) { 38 | LinkedList mc = new LinkedList(); 39 | mc.threeKongs(); 40 | mc.printAll(); 41 | } 42 | } 43 | /*viz_options {"disableNesting":true}*/ -------------------------------------------------------------------------------- /example-code/PassByValue.java: -------------------------------------------------------------------------------- 1 | public class PassByValue { 2 | 3 | static void reset(int x) { 4 | x = 0; 5 | } 6 | 7 | static void reset(int[] x) { 8 | for (int i : x) 9 | i = 0; 10 | } 11 | 12 | static void reallyReset(int[] x) { 13 | for (int i=0; i stacky = new Stack<>(); 5 | for (char ch : "123+45*6-+-".toCharArray()) { 6 | if (ch == '+') 7 | stacky.push(stacky.pop() + stacky.pop()); 8 | else if (ch == '*') 9 | stacky.push(stacky.pop() * stacky.pop()); 10 | else if (ch == '-') 11 | stacky.push(-stacky.pop() + stacky.pop()); 12 | else 13 | stacky.push(ch-'0'); 14 | } 15 | System.out.println(stacky.pop()); 16 | } 17 | } -------------------------------------------------------------------------------- /example-code/Recursion.java: -------------------------------------------------------------------------------- 1 | public class Recursion { 2 | public static void ruler(int n) { 3 | if (n>0) ruler(n-1); 4 | System.out.println(n); 5 | if (n>0) ruler(n-1); 6 | } 7 | public static void main(String[] args) { 8 | ruler(2); 9 | } 10 | } -------------------------------------------------------------------------------- /example-code/Reflect.java: -------------------------------------------------------------------------------- 1 | import java.lang.reflect.*; 2 | 3 | public class Reflect { 4 | public static void announce() { 5 | System.out.println("Someone called announce()."); 6 | } 7 | public static void main(String[] args) { 8 | try { 9 | Method m = Reflect.class.getMethod("announce", null); 10 | m.invoke(null); // null "this" since it's a static method 11 | } 12 | catch (NoSuchMethodException | IllegalAccessException 13 | | InvocationTargetException e) {} 14 | } 15 | } -------------------------------------------------------------------------------- /example-code/Rolex.java: -------------------------------------------------------------------------------- 1 | public class Rolex { 2 | private final long start; 3 | 4 | public Rolex() { 5 | start = System.currentTimeMillis(); 6 | } 7 | 8 | // return time (in seconds) since this object was created 9 | public double elapsedTime() { 10 | long now = System.currentTimeMillis(); 11 | return (now - start) / 1000.0; 12 | } 13 | 14 | public static void main(String[] args) { 15 | Rolex watchOne = new Rolex(); 16 | // waste time so it is large enough to be measurable 17 | try {Thread.sleep(500);} catch (InterruptedException e) {} 18 | 19 | Rolex watchTwo = new Rolex(); 20 | // waste time so it is large enough to be measurable 21 | try {Thread.sleep(500);} catch (InterruptedException e) {} 22 | 23 | // right now, watchOne is older 24 | System.out.println("watchOne " + watchOne.elapsedTime()); 25 | System.out.println("watchTwo " + watchTwo.elapsedTime()); 26 | 27 | Rolex watchTmp = watchOne; 28 | watchOne = watchTwo; 29 | watchTwo = watchTmp; 30 | 31 | // swapped! now watchTwo is the older one 32 | // e.g. watchTwo.elapsedTime() returns a value 33 | // (slightly) larger than watchOne.elapsedTime() 34 | System.out.println("watchOne " + watchOne.elapsedTime()); 35 | System.out.println("watchTwo " + watchTwo.elapsedTime()); 36 | } 37 | } -------------------------------------------------------------------------------- /example-code/Sqrt.java: -------------------------------------------------------------------------------- 1 | public class Sqrt { 2 | public static void main(String[] args) { 3 | double target = 2013; 4 | double x = 1; 5 | double oldx; 6 | do { 7 | oldx = x; 8 | x = (x + target / x) / 2; 9 | } 10 | while (oldx != x); 11 | System.out.println(x); 12 | System.out.println(x*x); 13 | } 14 | } -------------------------------------------------------------------------------- /example-code/StackOverflow.java: -------------------------------------------------------------------------------- 1 | public class StackOverflow { 2 | private static void burn(int i) { 3 | i = i + 1; 4 | burn(i); 5 | } 6 | public static void main(String[] args) { 7 | burn(0); 8 | } 9 | } -------------------------------------------------------------------------------- /example-code/StackQueue.java: -------------------------------------------------------------------------------- 1 | public class StackQueue { 2 | public static void main(String[] args) { 3 | Stack stack = new Stack<>(); 4 | Queue queue = new Queue<>(); 5 | 6 | stack.push("stack-first"); 7 | stack.push("stack-last"); 8 | 9 | queue.enqueue("queue-first"); 10 | queue.enqueue("queue-last"); 11 | 12 | for (String s : stack) 13 | System.out.println("stack contains " + s); 14 | for (String s : queue) 15 | System.out.println("queue contains " + s); 16 | 17 | while (!stack.isEmpty()) 18 | System.out.println(stack.pop()); 19 | while (!queue.isEmpty()) 20 | System.out.println(queue.dequeue()); 21 | } 22 | } -------------------------------------------------------------------------------- /example-code/StaticInitializer.java: -------------------------------------------------------------------------------- 1 | public class StaticInitializer { 2 | static { 3 | // static initializer, runs when class is initialized 4 | System.out.println("When will this print?"); 5 | } 6 | public static void main(String[] args) { 7 | System.out.println("Now we're in main"); 8 | } 9 | } -------------------------------------------------------------------------------- /example-code/StdIn.java: -------------------------------------------------------------------------------- 1 | public class StdInDemo { 2 | public static void main(String[] args) { 3 | StdOut.println("int: " + StdIn.readInt()); 4 | StdOut.println("double: " + StdIn.readDouble()); 5 | StdOut.println("String (token): " + StdIn.readString()); 6 | StdOut.println("char: " + StdIn.readChar()); 7 | StdOut.println("char: " + StdIn.readChar()); 8 | StdOut.println("line: " + StdIn.readLine()); 9 | StdOut.println("empty?: " + StdIn.isEmpty()); 10 | } 11 | } 12 | /*viz_options {"stdin":"13 3.4 mytoken chars rest of line\nanother line"} */ -------------------------------------------------------------------------------- /example-code/Strings.java: -------------------------------------------------------------------------------- 1 | public class Strings { 2 | public static void main(String[] args) { 3 | String a = "Hello, world!"; 4 | String b = "Hello, world!!".substring(0, 13); 5 | String c = "Hello, "; 6 | c += "world!"; 7 | String d = "Hello, w"+"orld!"; // constant expr, interned 8 | String e = a.substring(0, 13); 9 | System.out.println((a == b) + " " + a.equals(b)); 10 | System.out.println((a == c) + " " + a.equals(c)); 11 | System.out.println((a == d) + " " + a.equals(d)); 12 | System.out.println((a == e) + " " + a.equals(e)); 13 | } 14 | } 15 | /*viz_options {"showStringsAsObjects":true}*/ -------------------------------------------------------------------------------- /example-code/SymbolTable.java: -------------------------------------------------------------------------------- 1 | public class SymbolTable { 2 | public static void main(String[] args) { 3 | ST st = new ST<>(); 4 | st.put("key1", "value1"); 5 | st.put("key2", "value2"); 6 | st.put("key3", "value3"); 7 | st.put("key1", "different value"); 8 | st.delete("key2"); 9 | for (String s : st.keys()) 10 | StdOut.println(s + " " + st.get(s)); 11 | } 12 | } -------------------------------------------------------------------------------- /example-code/Synthetic.java: -------------------------------------------------------------------------------- 1 | public class Synthetic { 2 | 3 | class Inner { 4 | // contains auto-generated (synthetic) 5 | // field "this$0" of type Synthetic 6 | } 7 | 8 | public static void main(String[] args) { 9 | Synthetic a = new Synthetic(); 10 | Synthetic b = new Synthetic(); 11 | Inner c = a.new Inner(); 12 | Inner d = b.new Inner(); 13 | // end of first 14 | 15 | final String[] magic = {"7", "8"}; 16 | // anonymous class 17 | Object e = new Object(){ 18 | public String toString() { 19 | return magic[1]; 20 | } 21 | }; 22 | // it has a synthetic variable val$magic 23 | System.out.println(e.toString()); 24 | 25 | class Local { 26 | void foo() {System.out.println(magic.length);} 27 | } 28 | Local x = new Local(); 29 | x.foo(); 30 | } 31 | } 32 | /*viz_options {"showAllFields":true}*/ -------------------------------------------------------------------------------- /example-code/ToString.java: -------------------------------------------------------------------------------- 1 | public class ToString { 2 | int x; 3 | 4 | public String toString() { 5 | return "Instance with x = " + x; 6 | } 7 | 8 | public static void main(String[] args) { 9 | ToString ts = new ToString(); 10 | ts.x = 5; 11 | System.out.println(ts); 12 | } 13 | } -------------------------------------------------------------------------------- /example-code/TwoClasses.java: -------------------------------------------------------------------------------- 1 | public class TwoClasses { 2 | String message = "Can you put two classes in one file?"; 3 | void proclaim() { 4 | System.out.println(message); 5 | } 6 | public static void main(String[] args) { 7 | new TwoClasses().proclaim(); 8 | new AnotherClass().proclaim(); 9 | } 10 | } 11 | class AnotherClass extends TwoClasses{ 12 | {message = "Yup";} // instance initializer 13 | } 14 | -------------------------------------------------------------------------------- /example-code/Variables.java: -------------------------------------------------------------------------------- 1 | public class Variables { 2 | public static void main(String[] args) { 3 | String me = "me"; 4 | String you = "you"; 5 | String tmp = me; 6 | me = you; 7 | you = tmp; 8 | 9 | int x = 5; 10 | int y = 10; 11 | int t = x; 12 | x = y; 13 | y = t; 14 | } 15 | } -------------------------------------------------------------------------------- /iframe-embed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Online Python Tutor - iframe embed page 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /img/README: -------------------------------------------------------------------------------- 1 | Icon based on 2 | * Coffee icon: http://thenounproject.com/noun/coffee/#icon-No4115 3 | by Jacob Halton http://thenounproject.com/jacob 4 | and 5 | * Glasses icon: http://thenounproject.com/noun/glasses/#icon-No15009 6 | by Francesco Terzini http://thenounproject.com/fterzini 7 | -------------------------------------------------------------------------------- /img/jv128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/img/jv128.png -------------------------------------------------------------------------------- /img/jv256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/img/jv256.png -------------------------------------------------------------------------------- /img/jv32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/img/jv32.png -------------------------------------------------------------------------------- /img/jv64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daveagp/java_visualize/705b1d8c44d6f61a64321e02f71930922ba0369a/img/jv64.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 44 | 45 | 46 | Java Visualizer 47 | 48 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 |
Java Visualizer
(beta: 85 | report a bug) 86 |
87 | 88 |
89 | 90 |

Write your Java code here:

91 | 92 |
93 |
94 | 95 | 96 | 99 | 123 |
97 | 98 | 100 | 122 |
124 | 125 |
126 | args: 127 | 128 |
129 | 130 |
131 | 132 | (also visualizes consumption of StdIn) 133 | 138 |
139 | 140 | 172 | 173 | 196 | 197 | 205 | 215 | 230 | 231 |

232 | 233 |

234 | 235 | 236 |

237 | 238 | 317 |

The visualizer supports 318 | StdIn, 319 | StdOut, 320 | most other stdlib libraries, 321 | Stack, 322 | Queue, 323 | and ST. 324 |
325 |
326 | Click for FAQ. 327 |
328 | 336 |
337 | 338 |
339 | 340 | 341 |
342 |
343 | 344 | 411 | 412 | 413 | 414 | 415 | -------------------------------------------------------------------------------- /java_safe_ram_maketrace.php: -------------------------------------------------------------------------------- 1 | config_get("java_jail-abspath"), 54 | 55 | // you may choose to tweak these important performance parameters 56 | "clock" => config_get("safeexec_wallclock_s", 15), 57 | "cpu" => config_get("safeexec_cpu_s", 10), 58 | "mem" => config_get("safeexec_mem_k", 8000000), 59 | // use up to 8000000k ~ 8g of memory (YMMV) 60 | // counting both VMs and all overhead 61 | // see java_jail/cp/traceprinter/MEMORY-NOTES 62 | 63 | // on almost all machines you should not need to edit anything below in this file 64 | 65 | "exec_dir" => "/", // execute in root of chroot 66 | "env_vars" => "''", // no env vars 67 | "nproc" => "200", // max 200 processes 68 | "nfile" => "200", // up to 200 file handles. 69 | // depends on number of files you are including! 70 | 71 | "share_newnet" => "", // don't unshare network: 2 VMs talk over port 72 | ); 73 | 74 | // allow arbitrary overrides 75 | foreach (config_get("safeexec_args", array()) as $k=>$v) 76 | $safeexec_args[$k] = $v; 77 | 78 | // allow wholesale replacement 79 | $safeexec_args = config_get("safeexec_args_override", $safeexec_args); 80 | 81 | // the next two definitions assume things are set up like 82 | // https://github.com/daveagp/java_jail 83 | $java_in_jail = config_get("java_in_jail", "/java/bin/java"); 84 | $java_args = array( 85 | "Xmx" => "512M", // 128 mb per VM 86 | "cp" => '/cp/:/cp/javax.json-1.0.jar:/java/lib/tools.jar:/cp/visualizer-stdlib' 87 | ); 88 | 89 | // allow arbitrary overrides 90 | foreach (config_get("java_args", array()) as $k=>$v) 91 | $java_args[$k] = $v; 92 | 93 | // allow wholesale replacement 94 | $java_args = config_get("java_args_override", $java_args); 95 | 96 | // safeexec uses --exec, sandbox uses nothing 97 | $safeexec_exec_signal = config_get("safeexec_exec_signal", "--exec"); 98 | 99 | // now, build the command: 100 | // safeexec --arg1 val1 ... --exec java_in_jail -arg1 val1 ... traceprinter.InMemory 101 | $jv_cmd = $safeexec; 102 | foreach ($safeexec_args as $a=>$v) $jv_cmd .= " --$a $v "; 103 | $jv_cmd .= " $safeexec_exec_signal $java_in_jail"; 104 | // -X commands don't use a space 105 | foreach ($java_args as $a=>$v) $jv_cmd .= " " . (substr($a, 0, 1)=='X' ? "-$a$v" : "-$a $v") . " "; 106 | $jv_cmd .= "traceprinter.InMemory"; 107 | 108 | // necessary for sandbox at princeton 109 | $newdir = config_get("chdir_before_call", "."); 110 | chdir($newdir); 111 | 112 | // echo $jv_cmd; // for debugging 113 | 114 | // report an error which caused the code not to run 115 | function visError($msg, $row, $col, $code, $se_stdout = null) { 116 | if (!is_int($col)) 117 | $col = 0; 118 | if (!is_int($row)) 119 | $row = -1; 120 | return '{"trace":[{"line": '.$row.', "event": "uncaught_exception", ' 121 | .'"offset": '.$col.', "exception_msg": '.json_encode($msg).'}],' 122 | .'"code":'.json_encode($code) . 123 | ($se_stdout === null ? '' : (',"se_stdout":'.json_encode($se_stdout))) 124 | .'}'; 125 | } 126 | 127 | // do logging if enabled 128 | function logit($user_code, $internal_error) { 129 | 130 | if (config_get("db_host", "") != "" 131 | && config_get("db_user", "") != "" 132 | && config_get("db_database", "") != "" 133 | && config_get("db_password", "") != "") 134 | 135 | /* 136 | At the moment, it's pretty crappy and just logs requests to a 137 | table 'jv_history' that should have this structure 138 | 139 | CREATE TABLE IF NOT EXISTS `jv_history` ( 140 | `id` int(11) NOT NULL AUTO_INCREMENT, 141 | `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 142 | `user_code` varchar(8000) COLLATE utf8_unicode_ci NOT NULL, 143 | `internal_error` tinyint(1) NOT NULL, 144 | PRIMARY KEY (`id`) 145 | ) 146 | 147 | In the future, it could make sense to cache anything that is not randomized. 148 | */ 149 | { 150 | $con = mysqli_connect(config_get("db_host"), config_get("db_user"), 151 | config_get("db_password"), config_get("db_database")); 152 | $stmt = $con->prepare("INSERT INTO jv_history (user_code, internal_error) VALUES (?, " . ($internal_error?1:0).")"); 153 | $stmt->bind_param("s", $user_code); 154 | $stmt->execute(); 155 | $stmt->close(); 156 | } 157 | } 158 | 159 | 160 | // the main method 161 | function maketrace() { 162 | if (!array_key_exists('data', $_REQUEST)) 163 | return visError("Error: http mangling? Could not find data variable.", 0, 0, ""); 164 | 165 | $data = $_REQUEST['data']; 166 | 167 | if (strlen($data) > config_get("max_request_size_bytes", 10000)) 168 | return visError("Too much code!"); 169 | 170 | $data = json_decode($data, true); // get assoc. arrays, not objects 171 | 172 | $user_code = $data['user_script']; 173 | 174 | $options = $data['options']; 175 | // sanitize options 176 | foreach ($options as $k => $v) { 177 | if ($k == "showStringsAsValues" || $k == "showAllFields") { 178 | $options[$k] = $options[$k] ? true : false; 179 | } 180 | else unset($options[$k]); 181 | } 182 | 183 | $args = $data['args']; 184 | if (!is_array($args)) 185 | return visError("args is not an array"); 186 | if (count($args)>0 && array_keys($args) !== range(0, count($args) - 1)) 187 | return visError("wrong args format"); 188 | for ($i=0; $i array("pipe", "r"), 198 | 1 => array("pipe", "w"),// stdout 199 | 2 => array("pipe", "w"),// stderr 200 | ); 201 | 202 | $output = array(); 203 | $return = -1; 204 | 205 | global $jv_cmd; 206 | // use the command 207 | $process = proc_open($jv_cmd, $descriptorspec, $pipes); //pwd, env not needed 208 | 209 | if (!is_resource($process)) return FALSE; 210 | 211 | global $visualizer_args; 212 | if (count($visualizer_args)==0) $visualizer_args = null; // b/c array() is not associative in php! 213 | $data_to_send = json_encode(array("usercode"=>$user_code, 214 | "options"=>$options, 215 | "args"=>$args, 216 | "stdin"=>$stdin, 217 | "visualizer_args"=>$visualizer_args)); 218 | 219 | fwrite($pipes[0], $data_to_send); 220 | fclose($pipes[0]); 221 | 222 | $se_stdout = stream_get_contents($pipes[1]); 223 | $se_stderr = stream_get_contents($pipes[2]); 224 | 225 | fclose($pipes[1]); 226 | fclose($pipes[2]); 227 | 228 | $safeexec_retval = proc_close($process); 229 | 230 | if ($safeexec_retval === 0 && $se_stdout != "") { //executed okay 231 | logit($user_code, false); 232 | return $se_stdout; 233 | } 234 | 235 | // there was an error 236 | logit($user_code, true); 237 | 238 | if ($safeexec_retval === 0) 239 | return visError("Internal error: safeexec returned 0, but an empty string.\nsafeexec stderr:\n" . $se_stderr, 0, 0, $user_code); 240 | 241 | //this will gum up the javascript, but is convenient to see with browser debugging tools 242 | return visError("Safeexec did not succeed:\n" . $se_stderr, 0, 0, $user_code, $se_stdout); 243 | } 244 | 245 | header("Content-type: text/plain; charset=utf-8"); 246 | echo maketrace(); 247 | 248 | // end of file. 249 | -------------------------------------------------------------------------------- /jv-config.example.json: -------------------------------------------------------------------------------- 1 | {"remark1" : "edit the 2 paths below to run anything", 2 | 3 | "safeexec-executable-abspath": "/your/path/to/safeexec/safeexec", 4 | "java_jail-abspath": "/your/path/to/java_jail/", 5 | 6 | "remark2" : [ 7 | "optinally, edit these to log the submissions", 8 | "see java_safe_ram_maketrace.php for db format", 9 | "WARNING: check that the url with the passwords,", 10 | "http://url-referencing-java_visualize/config.json", 11 | "can NOT be accessed in the browser.", 12 | ".htaccess tries to hide it, but YMMV!!!", 13 | 14 | "also note that .gitignore ignores config.json", 15 | "because of this security information.", 16 | "back it up using an alternative method if desired." 17 | ], 18 | 19 | "db_host": "", 20 | "db_user": "", 21 | "db_database": "", 22 | "db_password": "", 23 | 24 | "remark3" : "optionally, edit these performance parameters", 25 | 26 | "ajax_timeout_millis": 30000, 27 | 28 | "safeexec_wallclock_s": 15, 29 | "safeexec_cpu_s": 10, 30 | "safeexec_mem_k": 8000000, 31 | 32 | "visualizer_args": { 33 | "MAX_STEPS": 512, 34 | "MAX_STACK_SIZE": 16, 35 | "MAX_WALLTIME_SECONDS": 5, 36 | "remark": "time above starts before compiling" 37 | }, 38 | 39 | "max_request_size_bytes" : 10000, 40 | 41 | "remark4": "below is the amount of memory for _each_ of the 2 VMs", 42 | "java_args" : { 43 | "Xmx" : "512M" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /jv-frontend.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This file, jv-frontend.js, is based on 4 | opt-frontend.js from the Online Python Tutor. 5 | Changes made by David Pritchard (daveagp@gmail.com); 6 | see README for more details. 7 | 8 | Summary of changes made: 9 | - uses Java, not Python 10 | - uses CodeMirror latest version 11 | - lazier approach for loading examples 12 | 13 | ==== Header from opt-frontend.js ==== 14 | 15 | Online Python Tutor 16 | https://github.com/pgbovine/OnlinePythonTutor/ 17 | 18 | Copyright (C) 2010-2013 Philip J. Guo (philip@pgbovine.net) 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a 21 | copy of this software and associated documentation files (the 22 | "Software"), to deal in the Software without restriction, including 23 | without limitation the rights to use, copy, modify, merge, publish, 24 | distribute, sublicense, and/or sell copies of the Software, and to 25 | permit persons to whom the Software is furnished to do so, subject to 26 | the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included 29 | in all copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 32 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 33 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 34 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 35 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 36 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 37 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 38 | 39 | */ 40 | 41 | 42 | // Pre-reqs: pytutor.js and jquery.ba-bbq.min.js should be imported BEFORE this file 43 | 44 | 45 | // backend scripts to execute (Python 2 and 3 variants, if available) 46 | //var python2_backend_script = 'web_exec_py2.py'; 47 | //var python3_backend_script = 'web_exec_py3.py'; 48 | 49 | // uncomment below if you're running on Google App Engine using the built-in app.yaml 50 | var python2_backend_script = 'exec'; 51 | var python3_backend_script = null; 52 | 53 | var java_iframe_url = './iframe-embed.html'; 54 | var java_backend_script = './java_safe_ram_maketrace.php'; 55 | 56 | var appMode = 'edit'; // 'edit', 'display', or 'display_no_frills' 57 | 58 | var preseededCode = null; // if you passed in a 'code=' in the URL, then set this var 59 | var preseededCurInstr = null; // if you passed in a 'curInstr=' in the URL, then set this var 60 | 61 | var rawInputLst = []; // a list of strings inputted by the user in response to raw_input or mouse_input events 62 | 63 | var myVisualizer = null; // singleton ExecutionVisualizer instance 64 | 65 | // set keyboard bindings 66 | $(document).keydown(function(k) { 67 | //if (!keyStuckDown) { 68 | if (k.keyCode == 37 && myVisualizer != null) { // left arrow 69 | if (myVisualizer.stepBack()) { 70 | k.preventDefault(); // don't horizontally scroll the display 71 | keyStuckDown = true; 72 | } 73 | } 74 | else if (k.keyCode == 39 && myVisualizer != null) { // right arrow 75 | if (myVisualizer.stepForward()) { 76 | k.preventDefault(); // don't horizontally scroll the display 77 | keyStuckDown = true; 78 | } 79 | } 80 | //} 81 | }); 82 | 83 | $(document).keyup(function(k) { 84 | keyStuckDown = false; 85 | }); 86 | 87 | 88 | var keyStuckDown = false; 89 | 90 | function enterEditMode() { 91 | $.bbq.pushState({ mode: 'edit' }, 2 /* completely override other hash strings to keep URL clean */); 92 | } 93 | 94 | function enterDisplayNoFrillsMode() { 95 | $.bbq.pushState({ mode: 'display_no_frills' }, 2 /* completely override other hash strings to keep URL clean */); 96 | } 97 | 98 | var pyInputCodeMirror; // CodeMirror object that contains the input text 99 | 100 | function setCodeMirrorVal(dat) { 101 | if (dat.indexOf("/*viz_options")>-1) { 102 | var viz_options = dat.substring(dat.indexOf("/*viz_options")+13); 103 | dat = dat.substring(0, dat.indexOf("/*viz_options")); 104 | viz_options = viz_options.replace(/\s*(\*\/)?\s*$/, ""); // remove trailing spaces, */ 105 | viz_options = JSON.parse(viz_options); 106 | setOptions(function(key){ return viz_options[key] }); 107 | } 108 | else { 109 | setOptions(function(key){ return undefined;}); 110 | } 111 | pyInputCodeMirror.setValue(dat.rtrim()); 112 | $('#urlOutput,#embedCodeOutput').val(''); 113 | 114 | // also scroll to top to make the UI more usable on smaller monitors 115 | $(document).scrollTop(0); 116 | } 117 | 118 | function getUserArgs() { 119 | return $.map($('#argslist .arg input'), function(e){return e.value;}); 120 | } 121 | 122 | function getUserStdin() { 123 | return window.stdinarea.value; 124 | } 125 | 126 | $(document).ready(function() { 127 | 128 | $("#embedLinkDiv").hide(); 129 | 130 | pyInputCodeMirror = CodeMirror(document.getElementById('codeInputPane'), { 131 | mode: 'text/x-java', 132 | lineNumbers: true, 133 | matchBrackets: true, 134 | tabSize: 3, 135 | indentUnit: 3, 136 | extraKeys: { 137 | Tab: function(cm) { 138 | var lo = cm.getCursor("start").line; 139 | var hi = cm.getCursor("end").line; 140 | for (var i = lo; i <= hi; i++) 141 | cm.indentLine(i, "smart"); 142 | cm.setCursor(cm.getCursor("end")); 143 | return true; 144 | }, 145 | F5 : function() {return false;} 146 | } 147 | }); 148 | 149 | // setCodeMirrorVal( 150 | // "public class ClassNameHere {\n" + 151 | // " public static void main(String[] args) {\n \n }\n}"); 152 | 153 | pyInputCodeMirror.setSize(null, 'auto'); 154 | 155 | 156 | 157 | // be friendly to the browser's forward and back buttons 158 | // thanks to http://benalman.com/projects/jquery-bbq-plugin/ 159 | $(window).bind("hashchange", function(e) { 160 | appMode = $.bbq.getState('mode'); // assign this to the GLOBAL appMode 161 | 162 | if (appMode === undefined || appMode == 'edit') { 163 | $("#pyInputPane").show(); 164 | $("#pyOutputPane").hide(); 165 | $("#embedLinkDiv").hide(); 166 | 167 | // destroy all annotation bubbles (NB: kludgy) 168 | if (myVisualizer) { 169 | myVisualizer.destroyAllAnnotationBubbles(); 170 | } 171 | } 172 | else if (appMode == 'display') { 173 | $("#pyInputPane").hide(); 174 | $("#pyOutputPane").show(); 175 | 176 | $("#embedLinkDiv").show(); 177 | 178 | $('#executeBtn').html("Visualize execution"); 179 | $('#executeBtn').attr('disabled', false); 180 | 181 | 182 | // do this AFTER making #pyOutputPane visible, or else 183 | // jsPlumb connectors won't render properly 184 | myVisualizer.updateOutput(); 185 | 186 | // customize edit button click functionality AFTER rendering (NB: awkward!) 187 | $('#pyOutputPane #editCodeLinkDiv').show(); 188 | $('#pyOutputPane #editBtn').click(function() { 189 | $("#iframeURL-div").hide(); 190 | enterEditMode(); 191 | }); 192 | } 193 | else if (appMode == 'display_no_frills') { 194 | $("#pyInputPane").hide(); 195 | $("#pyOutputPane").show(); 196 | $("#embedLinkDiv").show(); 197 | } 198 | else { 199 | assert(false); 200 | } 201 | 202 | $('#urlOutput,#embedCodeOutput').val(''); // clear to avoid stale values 203 | }); 204 | 205 | 206 | function executeCode(forceStartingInstr) { 207 | var backend_script = java_backend_script; 208 | /* if ($('#pythonVersionSelector').val() == '2') { 209 | backend_script = python2_backend_script; 210 | } 211 | else if ($('#pythonVersionSelector').val() == '3') { 212 | backend_script = python3_backend_script; 213 | } 214 | 215 | if (!backend_script) { 216 | alert('Error: This server is not configured to run Python ' + $('#pythonVersionSelector').val()); 217 | return; 218 | }*/ 219 | 220 | $('#executeBtn').html("Please wait ... processing your code"); 221 | $('#executeBtn').attr('disabled', true); 222 | $("#pyOutputPane").hide(); 223 | $("#embedLinkDiv").hide(); 224 | 225 | var java_backend_options = {}; 226 | java_backend_options.showStringsAsValues = !$('#showStringsAsObjects').is(':checked'); 227 | java_backend_options.showAllFields = $('#showAllFields').is(':checked'); 228 | 229 | var package = { 230 | user_script : pyInputCodeMirror.getValue(), 231 | options: java_backend_options, 232 | args: getUserArgs(), 233 | stdin: getUserStdin() 234 | }; 235 | 236 | $("#iframeURL-div").show(); 237 | // USC Wordpress approach from Spring '15 238 | // $("#iframeURL").html('[visualize]'+encodeURIComponent(JSON.stringify(package))+'[/visualize]'); 239 | // but this is simpler assuming you are editing raw html: 240 | var a = document.createElement('a'); 241 | // absolutize iframe-embed.html 242 | a.href = java_iframe_url; 243 | $('#iframeURL').val(''); 248 | 249 | 250 | $.ajax({url: backend_script, 251 | data: {data : JSON.stringify(package)}, 252 | /*, 253 | raw_input_json: rawInputLst.length > 0 ? JSON.stringify(rawInputLst) : '', 254 | options_json: JSON.stringify(options)*/ 255 | dataType: "json", 256 | timeout: pytutor_ajax_timeout_millis, //ms 257 | error: ajaxErrorHandler, 258 | success: function(dataFromBackend) { 259 | console.log(["Data from backend:", dataFromBackend]); 260 | 261 | var trace = dataFromBackend.trace; 262 | 263 | // don't enter visualize mode if there are killer errors: 264 | if (!trace || 265 | (trace.length == 0) || 266 | (trace[trace.length - 1].event == 'uncaught_exception')) { 267 | 268 | if (trace.length == 1) { 269 | var errorLineNo = trace[0].line - 1; /* CodeMirror lines are zero-indexed */ 270 | if (errorLineNo !== undefined) { 271 | // highlight the faulting line in pyInputCodeMirror 272 | pyInputCodeMirror.focus(); 273 | pyInputCodeMirror.setCursor(errorLineNo, 0); 274 | var marked = pyInputCodeMirror.addLineClass(errorLineNo, null, 'errorLine'); 275 | //console.log(marked); 276 | var hook = function(marked) { return function() { 277 | pyInputCodeMirror.removeLineClass(marked, null, 'errorLine'); // reset line back to normal 278 | pyInputCodeMirror.off('change', hook); // cancel 279 | }} (marked); 280 | pyInputCodeMirror.on('change', hook); 281 | } 282 | 283 | alert(trace[0].exception_msg); 284 | } 285 | else if (trace[trace.length - 1].exception_msg) { 286 | alert(trace[trace.length - 1].exception_msg); 287 | } 288 | else { 289 | alert("Whoa, unknown error! Reload to try again, or report a bug to daveagp@gmail.com\n\n(Click the 'Generate URL' button to include a unique URL in your email bug report.)"); 290 | } 291 | 292 | $('#executeBtn').html("Visualize execution"); 293 | $('#executeBtn').attr('disabled', false); 294 | } 295 | else { 296 | var startingInstruction = 0; 297 | 298 | // only do this at most ONCE, and then clear out preseededCurInstr 299 | if (preseededCurInstr && preseededCurInstr < trace.length) { // NOP anyways if preseededCurInstr is 0 300 | startingInstruction = preseededCurInstr; 301 | preseededCurInstr = null; 302 | } 303 | 304 | // forceStartingInstr overrides everything else 305 | if (forceStartingInstr !== undefined) { 306 | startingInstruction = forceStartingInstr; 307 | } 308 | 309 | var frontend_options = 310 | {startingInstruction: startingInstruction, 311 | updateOutputCallback: 312 | function() { 313 | $('#urlOutput,#embedCodeOutput').val(''); 314 | }, 315 | disableHeapNesting: $('#disableNesting').is(':checked'), 316 | drawParentPointers: false, 317 | textualMemoryLabels: false, 318 | showOnlyOutputs: false, 319 | executeCodeWithRawInputFunc: executeCodeWithRawInput, 320 | //allowEditAnnotations: true, 321 | resizeLeftRight: true, 322 | highlightLines: true, 323 | stdin: getUserStdin(), 324 | }; 325 | 326 | myVisualizer = new ExecutionVisualizer('pyOutputPane', 327 | dataFromBackend, 328 | frontend_options); 329 | 330 | // also scroll to top to make the UI more usable on smaller monitors 331 | $(document).scrollTop(0); 332 | 333 | $.bbq.pushState({ mode: 'display' }, 2 /* completely override other hash strings to keep URL clean */); 334 | 335 | } 336 | }}); 337 | } 338 | 339 | function executeCodeFromScratch() { 340 | // reset these globals 341 | rawInputLst = []; 342 | 343 | executeCode(); 344 | } 345 | 346 | function executeCodeWithRawInput(rawInputStr, curInstr) { 347 | enterDisplayNoFrillsMode(); 348 | 349 | // set some globals 350 | rawInputLst.push(rawInputStr); 351 | 352 | executeCode(curInstr); 353 | } 354 | 355 | $("#executeBtn").attr('disabled', false); 356 | $("#executeBtn").click(executeCodeFromScratch); 357 | 358 | 359 | // canned examples 360 | 361 | var examplesDir = "./example-code/"; 362 | 363 | var exampleCallback = function(url) { 364 | return function() {$.get(url, setCodeMirrorVal); return false;}; 365 | } 366 | 367 | String.prototype.endsWith = function(suffix) { 368 | return this.indexOf(suffix, this.length - suffix.length) !== -1; 369 | }; 370 | 371 | // populate examples 372 | var done = {}; 373 | for (var i=0; i"); 375 | $("#examplesHolder").append(topics[i][0]); 376 | $("#examplesHolder").append(" examples"); 377 | for (var j=0; j" + filename + ""); 381 | newItem.click(exampleCallback(examplesDir + filename + ".java")); 382 | $("#examplesHolder").append(newItem); 383 | done[filename] = true; 384 | } 385 | } 386 | 387 | var populate_misc = function(index_page) { 388 | $("#examplesHolder").append("
misc examples"); 389 | var first = true; 390 | $(index_page).find("td > a").each(function() { 391 | var filename = $(this).attr("href"); 392 | if (filename.endsWith(".java")) { // an example 393 | filename = filename.substring(0, filename.length-5); 394 | if (done[filename]) return; 395 | var newItem = $("" + filename + ""); 396 | newItem.click(exampleCallback(examplesDir + filename + ".java")); 397 | $("#examplesHolder").append(" | "); 398 | $("#examplesHolder").append(newItem); 399 | } 400 | }); 401 | }; 402 | 403 | // fetch uncategorized 404 | $.ajax({ 405 | url: "./example-code/", 406 | success: populate_misc, 407 | error: function() {console.log("warning: couldn't read examples directory index");} 408 | }); 409 | 410 | 411 | // handle hash parameters passed in when loading the page 412 | preseededCode = $.bbq.getState('code'); 413 | if (preseededCode) { 414 | setCodeMirrorVal(preseededCode); 415 | } 416 | else { 417 | // select a canned example on start-up: 418 | exampleCallback(examplesDir+"(Default).java")(); 419 | } 420 | 421 | var loadExample = $.bbq.getState('sampleFile'); 422 | if (loadExample) { 423 | //console.log(loadExample); 424 | if (loadExample.match(/[a-zA-Z]+/)) 425 | exampleCallback(examplesDir+loadExample+".java")(); 426 | } 427 | 428 | // args, and only args, is parsed specially 429 | setOptions(function(key){ 430 | var value = $.bbq.getState(key); 431 | if (key=='args' && value != undefined) value = JSON.parse(value); 432 | return value; 433 | }); 434 | 435 | // log a generic AJAX error handler 436 | var ajaxErrorHandler = function(jqXHR, textStatus, errorThrown) { 437 | var errinfo = "textStatus: " + textStatus + "\nerrorThrown: " + errorThrown + "\nServer reply: " + jqXHR.responseText; 438 | 439 | alert("Server error. Report a bug to daveagp@gmail.com (click 'Generate URL' and include it). Debug info (also copied to console):\n" + errinfo); 440 | 441 | console.log(errinfo); 442 | 443 | $('#executeBtn').html("Visualize execution"); 444 | $('#executeBtn').attr('disabled', false); 445 | }; 446 | 447 | // $(document).ajaxError(ajaxErrorHandler); 448 | 449 | 450 | // redraw connector arrows on window resize 451 | $(window).resize(function() { 452 | if (appMode == 'display') { 453 | myVisualizer.redrawConnectors(); 454 | } 455 | }); 456 | 457 | $('#genUrlBtn').bind('click', function() { 458 | var myArgs = {code: pyInputCodeMirror.getValue(), 459 | mode: appMode 460 | /* 461 | , cumulative: $('#cumulativeModeSelector').val(), 462 | heapPrimitives: $('#heapPrimitivesSelector').val(), 463 | drawParentPointers: $('#drawParentPointerSelector').val(), 464 | textReferences: $('#textualMemoryLabelsSelector').val(), 465 | showOnlyOutputs: $('#showOnlyOutputsSelector').val(), 466 | py: $('#pythonVersionSelector').val() 467 | */}; 468 | 469 | // Set these to a value which coerces to true 470 | if ($('#showStringsAsObjects').is(':checked')) 471 | myArgs.showStringsAsObjects=1; 472 | if ($('#showAllFields').is(':checked')) 473 | myArgs.showAllFields=1; 474 | if ($('#disableNesting').is(':checked')) 475 | myArgs.disableNesting=1; 476 | if ($('#verticalLists').is(':checked')) 477 | myArgs.verticalLists=1; 478 | 479 | if (getUserArgs().length > 0) 480 | myArgs.args = JSON.stringify(getUserArgs()); 481 | 482 | if (getUserStdin().length > 0) 483 | myArgs.stdin = getUserStdin(); 484 | 485 | if (appMode == 'display') { 486 | myArgs.curInstr = myVisualizer.curInstr; 487 | } 488 | 489 | var urlStr = $.param.fragment(window.location.href, myArgs, 2 /* clobber all */); 490 | $('#urlOutput').val(urlStr); 491 | }); 492 | 493 | 494 | $('#genEmbedBtn').bind('click', function() { 495 | assert(appMode == 'display'); 496 | var myArgs = {code: pyInputCodeMirror.getValue(), 497 | cumulative: $('#cumulativeModeSelector').val(), 498 | heapPrimitives: $('#heapPrimitivesSelector').val(), 499 | drawParentPointers: $('#drawParentPointerSelector').val(), 500 | textReferences: $('#textualMemoryLabelsSelector').val(), 501 | showOnlyOutputs: $('#showOnlyOutputsSelector').val(), 502 | py: $('#pythonVersionSelector').val(), 503 | curInstr: myVisualizer.curInstr, 504 | }; 505 | 506 | var embedUrlStr = $.param.fragment('http://pythontutor.com/iframe-embed.html', myArgs, 2 /* clobber all */); 507 | var iframeStr = ''; 508 | $('#embedCodeOutput').val(iframeStr); 509 | }); 510 | }); 511 | 512 | var setOptions = function(lookup_function) { 513 | var userArgs = lookup_function('args'); 514 | if (userArgs) { 515 | if (!userArgs instanceof Array) 516 | userArgs = JSON.parse(userArgs); 517 | for (var i=0; inull'); 26 | else if (typ == "number") 27 | d3DomElement.append('' + obj + ''); 28 | else if (typ == "boolean") { 29 | if (obj) 30 | d3DomElement.append('true'); 31 | else 32 | d3DomElement.append('false'); 33 | } 34 | else if (obj instanceof Array && obj[0] == "VOID") { 35 | d3DomElement.append('void'); 36 | } 37 | else if (obj instanceof Array && obj[0] == "NUMBER-LITERAL") { 38 | // actually transmitted as a string 39 | d3DomElement.append('' + obj[1] + ''); 40 | } 41 | else if (obj instanceof Array && obj[0] == "CHAR-LITERAL") { 42 | var asc = obj[1].charCodeAt(0); 43 | var ch = obj[1]; 44 | 45 | // default 46 | var show = asc.toString(16); 47 | while (show.length < 4) show = "0" + show; 48 | show = "\\u" + show; 49 | 50 | if (ch == "\n") show = "\\n"; 51 | else if (ch == "\r") show = "\\r"; 52 | else if (ch == "\t") show = "\\t"; 53 | else if (ch == "\b") show = "\\b"; 54 | else if (ch == "\f") show = "\\f"; 55 | else if (ch == "\'") show = "\\\'"; 56 | else if (ch == "\"") show = "\\\""; 57 | else if (ch == "\\") show = "\\\\"; 58 | else if (asc >= 32) show = ch; 59 | 60 | // stringObj to make monospace 61 | d3DomElement.append('\'' + show + '\''); 62 | } 63 | else 64 | return [false]; // we didn't handle it 65 | return [true]; // we handled it 66 | }); 67 | 68 | add_pytutor_hook( 69 | "isPrimitiveType", 70 | function(args) { 71 | var obj = args.obj; 72 | if ((obj instanceof Array && obj[0] == "VOID") 73 | || (obj instanceof Array && obj[0] == "NUMBER-LITERAL") 74 | || (obj instanceof Array && obj[0] == "CHAR-LITERAL") 75 | || (obj instanceof Array && obj[0] == "ELIDE")) 76 | return [true, true]; // we handled it, it's primitive 77 | return [false]; // didn't handle it 78 | }); 79 | 80 | add_pytutor_hook( 81 | "end_updateOutput", 82 | function(args) { 83 | // find the colophon if it exists, and change it to something that makes more sense 84 | $('#codeDisplayDiv div a').each(function(i, elt) { 85 | if (elt.parentElement.innerHTML.indexOf('Code visualized') > -1) { 86 | if (faking_cpp) { 87 | elt.parentElement.parentElement.removeChild(elt.parentElement); 88 | } 89 | else { 90 | elt.setAttribute('href', 'http://cscircles.cemc.uwaterloo.ca/java_visualize/'); 91 | elt.innerHTML = 'Java Visualizer'; 92 | } 93 | } 94 | }); 95 | 96 | if (faking_cpp) { 97 | $("#stackHeader").html('Variables'); 98 | $("#heapHeader").html('Memory'); 99 | } 100 | 101 | var myViz = args.myViz; 102 | var curEntry = myViz.curTrace[myViz.curInstr]; 103 | if (myViz.params.stdin && myViz.params.stdin != "") { 104 | var stdinPosition = curEntry.stdinPosition || 0; 105 | var stdinContent = 106 | ''+ 107 | escapeHtml(myViz.params.stdin.substr(0, stdinPosition))+ 108 | ''+ 109 | escapeHtml(myViz.params.stdin.substr(stdinPosition)); 110 | myViz.domRoot.find('#stdinShow').html(stdinContent); 111 | } 112 | return [false]; 113 | }); 114 | 115 | add_pytutor_hook( 116 | "end_constructor", 117 | function(args) { 118 | var myViz = args.myViz; 119 | if ((myViz.curTrace.length > 0) 120 | && myViz.curTrace[myViz.curTrace.length-1] 121 | && myViz.curTrace[myViz.curTrace.length-1].stdout) { 122 | myViz.hasStdout = true; 123 | myViz.stdoutLines = myViz.curTrace[myViz.curTrace.length-1].stdout.split("\n").length; 124 | } 125 | // if last frame is a step limit 126 | else if ((myViz.curTrace.length > 1) 127 | && myViz.curTrace[myViz.curTrace.length-2] 128 | && myViz.curTrace[myViz.curTrace.length-2].stdout) { 129 | myViz.hasStdout = true; 130 | myViz.stdoutLines = myViz.curTrace[myViz.curTrace.length-2].stdout.split("\n").length; 131 | } 132 | else { 133 | myViz.stdoutLines = -1; 134 | } 135 | if (myViz.hasStdout) 136 | for (var i=0; i' + typeLabelPrefix + 'empty ' + visibleLabel + ''); 183 | return [true]; //handled 184 | } 185 | 186 | d3DomElement.append('
' + typeLabelPrefix + visibleLabel + '
'); 187 | d3DomElement.append('
'); 188 | var tbl = d3DomElement.children('table'); 189 | 190 | if (obj[0] == 'LIST') { 191 | tbl.append(''); 192 | var headerTr = tbl.find('tr:first'); 193 | var contentTr = tbl.find('tr:last'); 194 | 195 | // i: actual index in json object; ind: apparent index 196 | for (var i=1, ind=0; i'); 203 | headerTr.find('td:last').append(elide ? "…" : ind); 204 | 205 | contentTr.append(''); 206 | if (!elide) { 207 | myViz.renderNestedObject(val, stepNum, contentTr.find('td:last')); 208 | ind++; 209 | } 210 | else { 211 | contentTr.find('td:last').append("…"); 212 | ind += val[1]; // val[1] is the number of cells to skip 213 | } 214 | } 215 | } // end of LIST handling 216 | 217 | // Stack and Queue handling code by Will Gwozdz 218 | /* The table produced for stacks and queues is formed slightly differently than the others, 219 | missing the header row. Two rows made the dashed border not line up properly */ 220 | if (obj[0] == 'STACK') { 221 | tbl.append(''); 222 | var contentTr = tbl.find('tr:last'); 223 | contentTr.append(''+''+''); 224 | $.each(obj, function(ind, val) { 225 | if (ind < 1) return; // skip type tag and ID entry 226 | contentTr.append(''); 227 | myViz.renderNestedObject(val, stepNum, contentTr.find('td:last')); 228 | }); 229 | contentTr.append(''+''); 230 | } 231 | 232 | if (obj[0] == 'QUEUE') { 233 | tbl.append(''); 234 | var contentTr = tbl.find('tr:last'); 235 | // Add arrows showing in/out direction 236 | contentTr.append(''+''); 237 | $.each(obj, function(ind, val) { 238 | if (ind < 1) return; // skip type tag and ID entry 239 | contentTr.append(''); 240 | myViz.renderNestedObject(val, stepNum, contentTr.find('td:last')); 241 | }); 242 | contentTr.append(''+''); 243 | } 244 | 245 | return [true]; // did handle 246 | }); 247 | 248 | add_pytutor_hook( 249 | "end_renderDataStructures", 250 | function(args) { 251 | var myViz = args.myViz; 252 | myViz.domRoot.find("td.instKey:contains('___NO_LABEL!___')").hide(); 253 | myViz.domRoot.find(".typeLabel:contains('dict')").each( 254 | function(i) { 255 | if ($(this).html()=='dict') 256 | $(this).html('symbol table'); 257 | if ($(this).html()=='empty dict') 258 | $(this).html('empty symbol table'); 259 | }); 260 | }); 261 | 262 | // java synthetics cause things which javascript doesn't like in an id 263 | var old_generateID = ExecutionVisualizer.prototype.generateID; 264 | ExecutionVisualizer.prototype.generateID = function(original_id) { 265 | var sanitized = original_id.replace( 266 | /[^0-9a-zA-Z_]/g, 267 | function(match) {return '-'+match.charCodeAt(0)+'-';} 268 | ); 269 | return old_generateID(sanitized); 270 | } 271 | 272 | // utility functions 273 | var entityMap = { 274 | "&": "&", 275 | "<": "<", 276 | ">": ">", 277 | '"': '"', 278 | "'": ''', 279 | "/": '/' 280 | }; 281 | 282 | var escapeHtml = function(string) { 283 | return String(string).replace(/[&<>"'\/]/g, function (s) { 284 | return entityMap[s]; 285 | }); 286 | }; 287 | 288 | // fix bug where suppressed lines confuse the ui when they are executed 289 | String.prototype.rtrim = function() { 290 | return this; 291 | }; 292 | --------------------------------------------------------------------------------