├── .awsbox.json ├── .gitignore ├── README.md ├── config.js ├── doc ├── leak-allocations.png └── leak-gc-events.png ├── package.json ├── server.js ├── something.txt ├── static ├── client.js ├── d3.v2.min.js ├── graph.js ├── head.min.js ├── index.html ├── jquery-1.7.1.min.js ├── jquery.noisy.min.js ├── style.css └── svg.css └── worker.js /.awsbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "processes": [ "server.js" ] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /talk 3 | *~ 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Discovering and Finding Memory Leaks with `node-memwatch` 2 | ========================================================= 3 | 4 | Memory leaks are bad. They are also notoriously hard to detect. 5 | 6 | We present [node-memwatch](https://github.com/lloyd/node-memwatch) as 7 | a tool to help detect and track down memory leaks. 8 | 9 | This document is the outline of a presentation to be given at 10 | [NodeConf 2012](http://nodeconf/). It describes some examples of 11 | memory leaks and the problems they can cause, lists some well-known 12 | tools and methods for detecting and finding Node.JS memory leaks, and 13 | introduces `node-memwatch`, which we believe has some unique 14 | advantages. 15 | 16 | To run this demonstration: 17 | 18 | - Clone this repo (`git clone git://github.com/jedp/node-memwatch-demo.git`) 19 | - `npm install` 20 | - Edit `config.js` (instructions inside) 21 | - `npm start` 22 | - Visit http://localhost:3000/ 23 | 24 | Don't forget to kill the server if you're running in 'leak' mode or 25 | your computer will hate you! 26 | 27 | Memory Leaks? So What? 28 | ----------------------- 29 | 30 | Cool story, bro, but I've got 2 GB of RAM on this box. Why should I 31 | bother spending days tracking down hard-to-find leaks when I can just 32 | restart? 33 | 34 | Well, there are at least three things you should be concerned about: 35 | 36 | 1. As memory heap size grows, V8 becomes increasingly sluggish. (In 37 | part, this is because V8's survival instincts kick in and it starts 38 | performing full garbage-collections very aggressively.) Memory 39 | leaks hurt performance. 40 | 41 | 2. Leaks can be a vector for other types of failure. If your leaky 42 | code is hanging onto references to other resources, you may find 43 | you run out of file descriptors, for example, before you run out of 44 | memory. So your app might still trudge along, but your database 45 | might be inaccessible. 46 | 47 | 3. Eventually, your stuff will crash. And it will probably happen 48 | right when you're getting popular. And then everybody will laugh 49 | and it will be horrid. 50 | 51 | Some Examples of Leaks 52 | ---------------------- 53 | 54 | Closures are the most notorious source of memory leaks in JavaScript. 55 | This is because closures maintain references to their scope and all 56 | variables therein. For example: 57 | 58 | ```javascript 59 | function Leaky() { 60 | var leaked = new InnocentBystander(); 61 | var x = 42; 62 | return function() { 63 | return x; 64 | }; 65 | } 66 | ``` 67 | 68 | Leaks like this will probably be spotted eventually if somebody's 69 | looking for them. But in Node's asynchronous world, we generate 70 | closures all the time in the form of callbacks. If these callbacks 71 | are not handled as fast as they are created, memory allocations will 72 | build up and code that doesn't look leaky will act leaky. That's 73 | harder to spot. 74 | 75 | And what if your application is leaking due to a bug in upstream code? 76 | You may be able to track down the location in your code from where the 77 | leak is emanating, but you might just stare in bewilderment at your 78 | perfectly-written code wondering how in the world it can be leaking! 79 | For example, until fairly recently, anyone using `http.ClientRequest` 80 | was leaking a teensy bit of memory. Long-running services under heavy 81 | load were leaking a lot of memory. (The fix in the Node codebase was 82 | a change of a [mere two 83 | characters](https://github.com/vvo/node/commit/e138f76ab243ba3579ac859f08261a721edc20fe), replacing the method `on()` with the method `once()`.) 84 | 85 | 86 | Tools for Finding Leaks 87 | ----------------------- 88 | 89 | The classic approach is at this point to make a huge pot of coffee, 90 | lock yourself in a closet, and start bisecting code for hours or days 91 | until you find the offender. 92 | 93 | Since this is a memory problem, we can start by looking at `top` or 94 | `htop` or some system utility to discover our memory footprint. 95 | 96 | Within Node itself, there is `process.memoryUsage()`, which will 97 | report Node's heap footprint. 98 | 99 | But that won't get us far. We need tools to help us find leaks. 100 | Happily, there is a growing collection of good collection of tools for 101 | finding leaks in Node.JS applications. 102 | 103 | - Jimb Esser's 104 | [node-mtrace](https://github.com/Jimbly/node-mtrace), which uses the 105 | GCC `mtrace` utility to profile heap usage. 106 | 107 | - Dave Pacheco's 108 | [node-heap-dump](https://github.com/davepacheco/node-heap-dump) 109 | takes a snapshot of the V8 heap and serializes the whole thing out 110 | in a huge JSON file. It includes tools to traverse and investigate 111 | the resulting snapshot in JavaScript. 112 | 113 | - Danny Coates's 114 | [v8-profiler](https://github.com/dannycoates/v8-profiler) and 115 | [node-inspector](https://github.com/dannycoates/node-inspector) 116 | provide Node bindings for the V8 profiler and a Node debugging 117 | interface using the WebKit Web Inspector. 118 | 119 | - Felix Gnass's fork of the same that [un-disables the retainers 120 | graph](http://fgnass.posterous.com/finding-memory-leaks-in-nodejs-applications) 121 | 122 | - Felix Geisendörfer's [Node Memory Leak 123 | Tutorial](https://github.com/felixge/node-memory-leak-tutorial) is a 124 | short and sweet explanation of how to use the `v8-profiler` and 125 | `node-debugger`, and is presently the state-of-the-art for most 126 | Node.JS memory leak debugging. 127 | 128 | - Joyent's SmartOS platform, which furnishes an arsenal of tools at 129 | your disposal for [debugging Node.JS memory 130 | leaks](http://dtrace.org/blogs/bmc/2012/05/05/debugging-node-js-memory-leaks/) 131 | 132 | All these tools are brilliant, but they also have some drawbacks. The 133 | Web Inspector approach is suitable for applications in development, 134 | but is difficult to use on a live deployment, especially when multiple 135 | servers and subprocess are involved in the mix. As such, it may be 136 | difficult to reproduce memory leaks that bite in long-running and 137 | heavily-loaded production environments. Tools like `dtrace` and 138 | `libumem` are awe-inspiring, but only work on certain platforms. 139 | 140 | Goal of `node-memwatch` 141 | ----------------------- 142 | 143 | We would like to have a platform-independent debugging library 144 | requiring no instrumentation that can alert us when our programs might 145 | be leaking memory, and help us find where they are leaking. 146 | 147 | The API will provide three main things: 148 | 149 | - A `'leak'` event emitter 150 | 151 | ```javascript 152 | memwatch.on('leak', function(info) { 153 | // look at info to find out about top contributors 154 | }); 155 | ``` 156 | 157 | - A `'stats'` event emitter 158 | 159 | ```javascript 160 | var memwatch = require('memwatch'); 161 | memwatch.on('stats', function(stats) { 162 | // do something with post-gc memory usage stats 163 | }); 164 | ``` 165 | 166 | - A heap diff class 167 | 168 | ```javascript 169 | var hd = new memwatch.HeapDiff(); 170 | // ... stuff happens ... 171 | var diff = hd.end(); 172 | ``` 173 | 174 | - There is also a function to trigger garbage collection which can be 175 | useful in testing. 176 | 177 | ```javascript 178 | var stats = memwatch.gc(); 179 | ``` 180 | 181 | This is what we want to arrive at. Now let's begin at the beginning. 182 | 183 | Tracking Memory Usage 184 | --------------------- 185 | 186 | Starting with the most basic approach, a simple way to look for leaks 187 | would be to repeatedly call `memoryUsage()` at a fixed interval and 188 | see if there's a positive delta in heap allocations. 189 | 190 | To try this we'll make a simple EventEmitter that emits the memory 191 | usage every minute or so, and plot the usage over time. We'll write a 192 | simple, well-behaved program and track its memory usage: 193 | 194 | - run example 1 195 | 196 | Heap usage spikes up and down chaotically, and it may be difficult to 197 | find a meaningful trend. How long will we have to wait to know that 198 | we have a leak? How long to convince ourselves that we don't have a 199 | leak? 200 | 201 | 202 | `memwatch.on('stats', ...)`: Post-GC Heap Statistics 203 | ---------------------------------------------------- 204 | 205 | We can do a lot better. We can sample memory usage directlyafter a 206 | full garbage-collection and memory compaction, before any new JS 207 | objects have been allocated. 208 | 209 | We'll make a native module utilizing V8's post-gc hook, 210 | `V8::AddGCEpilogueCallback`, and gather heap usage statistics every 211 | time GC occurs. We'll emit this data up to our graph whenever it 212 | arrives. 213 | 214 | This is the first part of our API, the `'stats'` event emitter. It 215 | will emit a message containing the following: 216 | 217 | - usage_trend 218 | - current_base 219 | - estimated_base 220 | - num_full_gc 221 | - num_inc_gc 222 | - heap_compactions 223 | - min 224 | - max 225 | 226 | 227 | - run example 2 228 | 229 | This seems promising. We can see the base memory usage over time much 230 | more clearly. 231 | 232 | We can also prove that `memwatch` itself doesn't leak memory. 233 | 234 | 235 | `memwatch.on('leak', ...)`: Heap Allocation Trends 236 | -------------------------------------------------- 237 | 238 | In this example, we introduce a leaky function to see how our profiler 239 | behaves. 240 | 241 | We can add some analysis to this data and try to establish a trend in 242 | usage over time. 243 | 244 | So let's try this with a leaky program and see what happens. 245 | 246 | ![leak-gc-events](https://github.com/jedp/node-memwatch-demo/raw/master/doc/leak-gc-events.png) 247 | 248 | We can see clearly that the base heap usage only goes up and up. The 249 | indicator `usage_trend` remains positive, showing us that we're 250 | allocating more and more heap over time. 251 | 252 | `memwatch` will keep an eye on this for you, and emit a `'leak'` event 253 | if heap allocation has grown through five consecutive GCs. It tells 254 | you in nice, human-readable form what's going on. 255 | 256 | ```javascript 257 | { start: Fri, 29 Jun 2012 14:12:13 GMT, 258 | end: Fri, 29 Jun 2012 14:12:33 GMT, 259 | growth: 67984, 260 | reason: 'heap growth over 5 consecutive GCs (20s) - 11.67 mb/hr' } 261 | ``` 262 | 263 | `memwatch.HeapDiff()`: Finding Leaks 264 | ------------------------------------ 265 | 266 | Now that we have a leak detector, we want a leak identifier. 267 | 268 | By traversing the V8 heap graph, `memwatch` can collect the names and 269 | allocation counts for all objects on the heap. By comparing two 270 | successive heap snapshots, we can produce a diff. 271 | 272 | The API is: 273 | 274 | ```javascript 275 | var hd = new memwatch.HeapDiff(); 276 | 277 | // do something ... 278 | 279 | var diff = hd.end(); 280 | ``` 281 | 282 | The contents of `diff` will look something like this: 283 | 284 | ```javascript 285 | { 286 | "before": { 287 | "nodes": 11625, 288 | "size_bytes": 1869904, 289 | "size": "1.78 mb" 290 | }, 291 | "after": { 292 | "nodes": 21435, 293 | "size_bytes": 2119136, 294 | "size": "2.02 mb" 295 | }, 296 | "change": { 297 | "size_bytes": 249232, 298 | "size": "243.39 kb", 299 | "freed_nodes": 197, 300 | "allocated_nodes": 10007, 301 | "details": [ 302 | { 303 | "what": "Array", 304 | "size_bytes": 66688, 305 | "size": "65.13 kb", 306 | "+": 4, 307 | "-": 78 308 | }, 309 | { 310 | "what": "Code", 311 | "size_bytes": -55296, 312 | "size": "-54 kb", 313 | "+": 1, 314 | "-": 57 315 | }, 316 | { 317 | "what": "LeakingClass", 318 | "size_bytes": 239952, 319 | "size": "234.33 kb", 320 | "+": 9998, 321 | "-": 0 322 | }, 323 | { 324 | "what": "String", 325 | "size_bytes": -2120, 326 | "size": "-2.07 kb", 327 | "+": 3, 328 | "-": 62 329 | } 330 | ] 331 | } 332 | } 333 | ``` 334 | 335 | `HeapDiff` triggers a full GC before taking its samples, so the data 336 | won't be full of a lot of junk. `memwatch`'s event emitters will not 337 | notify of `HeapDiff` GC events, so you can safely put `HeapDiff` calls 338 | in your `'stats'` handler. 339 | 340 | ![heap-allocations](https://github.com/jedp/node-memwatch-demo/raw/master/doc/leak-allocations.png) 341 | 342 | 343 | Future Work 344 | ----------- 345 | 346 | Our next steps will be to provide a list of a few example instances of 347 | a leaked object - names of variables it's been assigned to, index in 348 | an array, closure code, etc. 349 | 350 | Summary 351 | ------- 352 | 353 | With `node-gcstats` we present 354 | 355 | - Accurate memory usage tracking 356 | - Notifications about probable leaks 357 | - A means to produce a heap diff 358 | - That is cross-platform 359 | - And that does not require any extra instrumentation 360 | 361 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /* 3 | * leak 4 | * (boolean) Set to true to leak memory 5 | */ 6 | leak: false, 7 | 8 | /* 9 | * hdInterval 10 | * (integer) Minimum interval in ms to perform heapdump 11 | * comparisons. Note that heapdump triggers gc, 12 | * so you can't do heapdump on gc without getting 13 | * yourself into a pretty tight loop. 14 | */ 15 | hdInterval: 1000 * 5, 16 | 17 | /* 18 | * clientConfig 19 | * (dict) What to show in the client 20 | * 21 | * 'usage' specifies a comma-separated list of 22 | * "events", "usage", and "allocations". Because 23 | * of space constraints and my laziness, "usage" 24 | * and "allocations" are mutually exclusive. So 25 | * you can have "events", "envents,usage", 26 | * "events,allocations", or just plain "usage" or 27 | * "allocations". 28 | * 29 | * 'title' specifies the title at the top of the 30 | * page. Useful if you're demo'ing to an audience. 31 | */ 32 | clientConfig: { 33 | title: "Memory Usage of a Well-Behaved (?) Program", 34 | show: "events,allocations" 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /doc/leak-allocations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jedp/node-memwatch-demo/9f8ecefcffa2815f45e65eb50268eb0000d1694d/doc/leak-allocations.png -------------------------------------------------------------------------------- /doc/leak-gc-events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jedp/node-memwatch-demo/9f8ecefcffa2815f45e65eb50268eb0000d1694d/doc/leak-gc-events.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leaky", 3 | "version": "0.0.1", 4 | "private": true, 5 | 6 | "dependencies": { 7 | "express": "2.5.10", 8 | "socket.io": "0.9.6", 9 | "node-gcstats": "git://github.com/jedp/node-memwatch#incremental" 10 | }, 11 | 12 | "scripts": { 13 | "start": "node server.js" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'), 2 | app = express.createServer(), 3 | io = require('socket.io').listen(app), 4 | config = require('./config'), 5 | memwatch = require('memwatch'), 6 | worker = require('./worker'); 7 | 8 | var hd = new memwatch.HeapDiff(); 9 | var lastHD = Date.now(); 10 | var clients = []; 11 | 12 | app.configure(function(){ 13 | app.use(express.static(__dirname + '/static')); 14 | app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); 15 | }); 16 | 17 | app.listen(process.env['PORT'] || 3000, function() { 18 | console.log("server listening on port %d", app.address().port); 19 | }); 20 | 21 | // reduce socket.io logging noise 22 | io.set('log level', 1); 23 | 24 | io.sockets.on('connection', function(socket) { 25 | clients.push(socket); 26 | 27 | socket.emit('configure', config.clientConfig); 28 | 29 | socket.on('disconnect', function() { 30 | clients.splice(clients.indexOf(socket), 1); 31 | }); 32 | 33 | // The buttons in the console can cause us to force GC or do a bunch of work 34 | socket.on('message', function(message) { 35 | switch (message) { 36 | case "do_gc": 37 | memwatch.gc(); 38 | break; 39 | 40 | case "add_load": 41 | worker.doStuff(); 42 | break; 43 | 44 | case "pause": 45 | io.sockets.emit('pause', {paused: worker.togglePause()}); 46 | break; 47 | 48 | default: 49 | console.log("what is " + message + "?"); 50 | break; 51 | } 52 | }); 53 | }); 54 | 55 | // every interval, send sample data to the server 56 | 57 | var allocations = {}; 58 | var snoitacolla = {}; 59 | function updateHeapDiff(diff) { 60 | var oldValue; 61 | var newValue; 62 | diff.change.details.forEach(function(data) { 63 | if (allocations[data.what] !== undefined) { 64 | oldValue = allocations[data.what]; 65 | snoitacolla[oldValue].pop(snoitacolla[oldValue].indexOf(oldValue)); 66 | if (!snoitacolla[oldValue].length) { 67 | delete snoitacolla[oldValue]; 68 | } 69 | } else { 70 | oldValue = 0; 71 | } 72 | newValue = oldValue + data["+"] - data["-"]; 73 | allocations[data.what] = newValue; 74 | if (!snoitacolla[newValue]) snoitacolla[newValue] = []; 75 | snoitacolla[newValue].push(data.what); 76 | }); 77 | } 78 | 79 | function topHeapAllocations(howMany) { 80 | howMany = howMany || 6; 81 | var result = []; 82 | // annoyingly, we have to convert the keys to integers first 83 | var keys = []; 84 | Object.keys(snoitacolla).forEach(function(key) { keys.push(parseInt(key, 10)); }); 85 | // sort greatest to least 86 | keys.sort(function(a,b) {return b-a;}); 87 | 88 | keys.slice(0, howMany).forEach(function(key) { 89 | result.push([key, snoitacolla[key]]); 90 | }); 91 | return result; 92 | } 93 | 94 | setInterval(function() { 95 | io.sockets.emit('temporal-sample', process.memoryUsage()); 96 | }, 333); 97 | 98 | // and also emit post-gc stats 99 | memwatch.on('stats', function(data) { 100 | if (data.type === 'inc') { 101 | io.sockets.emit('post-incremental-gc-sample', data); 102 | } else { 103 | if ((Date.now() - lastHD) > config.hdInterval) { 104 | updateHeapDiff(hd.end()); 105 | hd = new memwatch.HeapDiff(); 106 | lastHD = Date.now(); 107 | io.sockets.emit('heap-allocations', topHeapAllocations()); 108 | } 109 | io.sockets.emit('post-full-gc-sample', data); 110 | } 111 | }); 112 | -------------------------------------------------------------------------------- /something.txt: -------------------------------------------------------------------------------- 1 | # Network services, Internet style 2 | # 3 | # Note that it is presently the policy of IANA to assign a single well-known 4 | # port number for both TCP and UDP; hence, officially ports have two entries 5 | # even if the protocol doesn't support UDP operations. 6 | # 7 | # Updated from http://www.iana.org/assignments/port-numbers and other 8 | # sources like http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services . 9 | # New ports will be added on request if they have been officially assigned 10 | # by IANA and used in the real-world or are needed by a debian package. 11 | # If you need a huge list of used numbers please install the nmap package. 12 | 13 | tcpmux 1/tcp # TCP port service multiplexer 14 | echo 7/tcp 15 | echo 7/udp 16 | discard 9/tcp sink null 17 | discard 9/udp sink null 18 | systat 11/tcp users 19 | daytime 13/tcp 20 | daytime 13/udp 21 | netstat 15/tcp 22 | qotd 17/tcp quote 23 | msp 18/tcp # message send protocol 24 | msp 18/udp 25 | chargen 19/tcp ttytst source 26 | chargen 19/udp ttytst source 27 | ftp-data 20/tcp 28 | ftp 21/tcp 29 | fsp 21/udp fspd 30 | ssh 22/tcp # SSH Remote Login Protocol 31 | ssh 22/udp 32 | telnet 23/tcp 33 | smtp 25/tcp mail 34 | time 37/tcp timserver 35 | time 37/udp timserver 36 | rlp 39/udp resource # resource location 37 | nameserver 42/tcp name # IEN 116 38 | whois 43/tcp nicname 39 | tacacs 49/tcp # Login Host Protocol (TACACS) 40 | tacacs 49/udp 41 | re-mail-ck 50/tcp # Remote Mail Checking Protocol 42 | re-mail-ck 50/udp 43 | domain 53/tcp # Domain Name Server 44 | domain 53/udp 45 | mtp 57/tcp # deprecated 46 | tacacs-ds 65/tcp # TACACS-Database Service 47 | tacacs-ds 65/udp 48 | bootps 67/tcp # BOOTP server 49 | bootps 67/udp 50 | bootpc 68/tcp # BOOTP client 51 | bootpc 68/udp 52 | tftp 69/udp 53 | gopher 70/tcp # Internet Gopher 54 | gopher 70/udp 55 | rje 77/tcp netrjs 56 | finger 79/tcp 57 | http 80/tcp www # WorldWideWeb HTTP 58 | http 80/udp # HyperText Transfer Protocol 59 | link 87/tcp ttylink 60 | kerberos 88/tcp kerberos5 krb5 kerberos-sec # Kerberos v5 61 | kerberos 88/udp kerberos5 krb5 kerberos-sec # Kerberos v5 62 | supdup 95/tcp 63 | hostnames 101/tcp hostname # usually from sri-nic 64 | iso-tsap 102/tcp tsap # part of ISODE 65 | acr-nema 104/tcp dicom # Digital Imag. & Comm. 300 66 | acr-nema 104/udp dicom 67 | csnet-ns 105/tcp cso-ns # also used by CSO name server 68 | csnet-ns 105/udp cso-ns 69 | rtelnet 107/tcp # Remote Telnet 70 | rtelnet 107/udp 71 | pop2 109/tcp postoffice pop-2 # POP version 2 72 | pop2 109/udp pop-2 73 | pop3 110/tcp pop-3 # POP version 3 74 | pop3 110/udp pop-3 75 | sunrpc 111/tcp portmapper # RPC 4.0 portmapper 76 | sunrpc 111/udp portmapper 77 | auth 113/tcp authentication tap ident 78 | sftp 115/tcp 79 | uucp-path 117/tcp 80 | nntp 119/tcp readnews untp # USENET News Transfer Protocol 81 | ntp 123/tcp 82 | ntp 123/udp # Network Time Protocol 83 | pwdgen 129/tcp # PWDGEN service 84 | pwdgen 129/udp 85 | loc-srv 135/tcp epmap # Location Service 86 | loc-srv 135/udp epmap 87 | netbios-ns 137/tcp # NETBIOS Name Service 88 | netbios-ns 137/udp 89 | netbios-dgm 138/tcp # NETBIOS Datagram Service 90 | netbios-dgm 138/udp 91 | netbios-ssn 139/tcp # NETBIOS session service 92 | netbios-ssn 139/udp 93 | imap2 143/tcp imap # Interim Mail Access P 2 and 4 94 | imap2 143/udp imap 95 | snmp 161/tcp # Simple Net Mgmt Protocol 96 | snmp 161/udp 97 | snmp-trap 162/tcp snmptrap # Traps for SNMP 98 | snmp-trap 162/udp snmptrap 99 | cmip-man 163/tcp # ISO mgmt over IP (CMOT) 100 | cmip-man 163/udp 101 | cmip-agent 164/tcp 102 | cmip-agent 164/udp 103 | mailq 174/tcp # Mailer transport queue for Zmailer 104 | mailq 174/udp 105 | xdmcp 177/tcp # X Display Mgr. Control Proto 106 | xdmcp 177/udp 107 | nextstep 178/tcp NeXTStep NextStep # NeXTStep window 108 | nextstep 178/udp NeXTStep NextStep # server 109 | bgp 179/tcp # Border Gateway Protocol 110 | bgp 179/udp 111 | prospero 191/tcp # Cliff Neuman's Prospero 112 | prospero 191/udp 113 | irc 194/tcp # Internet Relay Chat 114 | irc 194/udp 115 | smux 199/tcp # SNMP Unix Multiplexer 116 | smux 199/udp 117 | at-rtmp 201/tcp # AppleTalk routing 118 | at-rtmp 201/udp 119 | at-nbp 202/tcp # AppleTalk name binding 120 | at-nbp 202/udp 121 | at-echo 204/tcp # AppleTalk echo 122 | at-echo 204/udp 123 | at-zis 206/tcp # AppleTalk zone information 124 | at-zis 206/udp 125 | qmtp 209/tcp # Quick Mail Transfer Protocol 126 | qmtp 209/udp 127 | z3950 210/tcp wais # NISO Z39.50 database 128 | z3950 210/udp wais 129 | ipx 213/tcp # IPX 130 | ipx 213/udp 131 | imap3 220/tcp # Interactive Mail Access 132 | imap3 220/udp # Protocol v3 133 | pawserv 345/tcp # Perf Analysis Workbench 134 | pawserv 345/udp 135 | zserv 346/tcp # Zebra server 136 | zserv 346/udp 137 | fatserv 347/tcp # Fatmen Server 138 | fatserv 347/udp 139 | rpc2portmap 369/tcp 140 | rpc2portmap 369/udp # Coda portmapper 141 | codaauth2 370/tcp 142 | codaauth2 370/udp # Coda authentication server 143 | clearcase 371/tcp Clearcase 144 | clearcase 371/udp Clearcase 145 | ulistserv 372/tcp # UNIX Listserv 146 | ulistserv 372/udp 147 | ldap 389/tcp # Lightweight Directory Access Protocol 148 | ldap 389/udp 149 | imsp 406/tcp # Interactive Mail Support Protocol 150 | imsp 406/udp 151 | svrloc 427/tcp # Server Location 152 | svrloc 427/udp 153 | https 443/tcp # http protocol over TLS/SSL 154 | https 443/udp 155 | snpp 444/tcp # Simple Network Paging Protocol 156 | snpp 444/udp 157 | microsoft-ds 445/tcp # Microsoft Naked CIFS 158 | microsoft-ds 445/udp 159 | kpasswd 464/tcp 160 | kpasswd 464/udp 161 | saft 487/tcp # Simple Asynchronous File Transfer 162 | saft 487/udp 163 | isakmp 500/tcp # IPsec - Internet Security Association 164 | isakmp 500/udp # and Key Management Protocol 165 | rtsp 554/tcp # Real Time Stream Control Protocol 166 | rtsp 554/udp 167 | nqs 607/tcp # Network Queuing system 168 | nqs 607/udp 169 | npmp-local 610/tcp dqs313_qmaster # npmp-local / DQS 170 | npmp-local 610/udp dqs313_qmaster 171 | npmp-gui 611/tcp dqs313_execd # npmp-gui / DQS 172 | npmp-gui 611/udp dqs313_execd 173 | hmmp-ind 612/tcp dqs313_intercell # HMMP Indication / DQS 174 | hmmp-ind 612/udp dqs313_intercell 175 | qmqp 628/tcp 176 | qmqp 628/udp 177 | ipp 631/tcp # Internet Printing Protocol 178 | ipp 631/udp 179 | # 180 | # UNIX specific services 181 | # 182 | exec 512/tcp 183 | biff 512/udp comsat 184 | login 513/tcp 185 | who 513/udp whod 186 | shell 514/tcp cmd # no passwords used 187 | syslog 514/udp 188 | printer 515/tcp spooler # line printer spooler 189 | talk 517/udp 190 | ntalk 518/udp 191 | route 520/udp router routed # RIP 192 | timed 525/udp timeserver 193 | tempo 526/tcp newdate 194 | courier 530/tcp rpc 195 | conference 531/tcp chat 196 | netnews 532/tcp readnews 197 | netwall 533/udp # for emergency broadcasts 198 | gdomap 538/tcp # GNUstep distributed objects 199 | gdomap 538/udp 200 | uucp 540/tcp uucpd # uucp daemon 201 | klogin 543/tcp # Kerberized `rlogin' (v5) 202 | kshell 544/tcp krcmd # Kerberized `rsh' (v5) 203 | dhcpv6-client 546/tcp 204 | dhcpv6-client 546/udp 205 | dhcpv6-server 547/tcp 206 | dhcpv6-server 547/udp 207 | afpovertcp 548/tcp # AFP over TCP 208 | afpovertcp 548/udp 209 | idfp 549/tcp 210 | idfp 549/udp 211 | remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem 212 | nntps 563/tcp snntp # NNTP over SSL 213 | nntps 563/udp snntp 214 | submission 587/tcp # Submission [RFC4409] 215 | submission 587/udp 216 | ldaps 636/tcp # LDAP over SSL 217 | ldaps 636/udp 218 | tinc 655/tcp # tinc control port 219 | tinc 655/udp 220 | silc 706/tcp 221 | silc 706/udp 222 | kerberos-adm 749/tcp # Kerberos `kadmin' (v5) 223 | # 224 | webster 765/tcp # Network dictionary 225 | webster 765/udp 226 | rsync 873/tcp 227 | rsync 873/udp 228 | ftps-data 989/tcp # FTP over SSL (data) 229 | ftps 990/tcp 230 | telnets 992/tcp # Telnet over SSL 231 | telnets 992/udp 232 | imaps 993/tcp # IMAP over SSL 233 | imaps 993/udp 234 | ircs 994/tcp # IRC over SSL 235 | ircs 994/udp 236 | pop3s 995/tcp # POP-3 over SSL 237 | pop3s 995/udp 238 | # 239 | # From ``Assigned Numbers'': 240 | # 241 | #> The Registered Ports are not controlled by the IANA and on most systems 242 | #> can be used by ordinary user processes or programs executed by ordinary 243 | #> users. 244 | # 245 | #> Ports are used in the TCP [45,106] to name the ends of logical 246 | #> connections which carry long term conversations. For the purpose of 247 | #> providing services to unknown callers, a service contact port is 248 | #> defined. This list specifies the port used by the server process as its 249 | #> contact port. While the IANA can not control uses of these ports it 250 | #> does register or list uses of these ports as a convienence to the 251 | #> community. 252 | # 253 | socks 1080/tcp # socks proxy server 254 | socks 1080/udp 255 | proofd 1093/tcp 256 | proofd 1093/udp 257 | rootd 1094/tcp 258 | rootd 1094/udp 259 | openvpn 1194/tcp 260 | openvpn 1194/udp 261 | rmiregistry 1099/tcp # Java RMI Registry 262 | rmiregistry 1099/udp 263 | kazaa 1214/tcp 264 | kazaa 1214/udp 265 | nessus 1241/tcp # Nessus vulnerability 266 | nessus 1241/udp # assessment scanner 267 | lotusnote 1352/tcp lotusnotes # Lotus Note 268 | lotusnote 1352/udp lotusnotes 269 | ms-sql-s 1433/tcp # Microsoft SQL Server 270 | ms-sql-s 1433/udp 271 | ms-sql-m 1434/tcp # Microsoft SQL Monitor 272 | ms-sql-m 1434/udp 273 | ingreslock 1524/tcp 274 | ingreslock 1524/udp 275 | prospero-np 1525/tcp # Prospero non-privileged 276 | prospero-np 1525/udp 277 | datametrics 1645/tcp old-radius 278 | datametrics 1645/udp old-radius 279 | sa-msg-port 1646/tcp old-radacct 280 | sa-msg-port 1646/udp old-radacct 281 | kermit 1649/tcp 282 | kermit 1649/udp 283 | groupwise 1677/tcp 284 | groupwise 1677/udp 285 | l2f 1701/tcp l2tp 286 | l2f 1701/udp l2tp 287 | radius 1812/tcp 288 | radius 1812/udp 289 | radius-acct 1813/tcp radacct # Radius Accounting 290 | radius-acct 1813/udp radacct 291 | msnp 1863/tcp # MSN Messenger 292 | msnp 1863/udp 293 | unix-status 1957/tcp # remstats unix-status server 294 | log-server 1958/tcp # remstats log server 295 | remoteping 1959/tcp # remstats remoteping server 296 | cisco-sccp 2000/tcp # Cisco SCCP 297 | cisco-sccp 2000/udp 298 | search 2010/tcp ndtp 299 | pipe-server 2010/tcp pipe_server 300 | nfs 2049/tcp # Network File System 301 | nfs 2049/udp # Network File System 302 | gnunet 2086/tcp 303 | gnunet 2086/udp 304 | rtcm-sc104 2101/tcp # RTCM SC-104 IANA 1/29/99 305 | rtcm-sc104 2101/udp 306 | gsigatekeeper 2119/tcp 307 | gsigatekeeper 2119/udp 308 | gris 2135/tcp # Grid Resource Information Server 309 | gris 2135/udp 310 | cvspserver 2401/tcp # CVS client/server operations 311 | cvspserver 2401/udp 312 | venus 2430/tcp # codacon port 313 | venus 2430/udp # Venus callback/wbc interface 314 | venus-se 2431/tcp # tcp side effects 315 | venus-se 2431/udp # udp sftp side effect 316 | codasrv 2432/tcp # not used 317 | codasrv 2432/udp # server port 318 | codasrv-se 2433/tcp # tcp side effects 319 | codasrv-se 2433/udp # udp sftp side effect 320 | mon 2583/tcp # MON traps 321 | mon 2583/udp 322 | dict 2628/tcp # Dictionary server 323 | dict 2628/udp 324 | f5-globalsite 2792/tcp 325 | f5-globalsite 2792/udp 326 | gsiftp 2811/tcp 327 | gsiftp 2811/udp 328 | gpsd 2947/tcp 329 | gpsd 2947/udp 330 | gds-db 3050/tcp gds_db # InterBase server 331 | gds-db 3050/udp gds_db 332 | icpv2 3130/tcp icp # Internet Cache Protocol 333 | icpv2 3130/udp icp 334 | mysql 3306/tcp 335 | mysql 3306/udp 336 | nut 3493/tcp # Network UPS Tools 337 | nut 3493/udp 338 | distcc 3632/tcp # distributed compiler 339 | distcc 3632/udp 340 | daap 3689/tcp # Digital Audio Access Protocol 341 | daap 3689/udp 342 | svn 3690/tcp subversion # Subversion protocol 343 | svn 3690/udp subversion 344 | suucp 4031/tcp # UUCP over SSL 345 | suucp 4031/udp 346 | sysrqd 4094/tcp # sysrq daemon 347 | sysrqd 4094/udp 348 | sieve 4190/tcp # ManageSieve Protocol 349 | epmd 4369/tcp # Erlang Port Mapper Daemon 350 | epmd 4369/udp 351 | remctl 4373/tcp # Remote Authenticated Command Service 352 | remctl 4373/udp 353 | f5-iquery 4353/tcp # F5 iQuery 354 | f5-iquery 4353/udp 355 | iax 4569/tcp # Inter-Asterisk eXchange 356 | iax 4569/udp 357 | mtn 4691/tcp # monotone Netsync Protocol 358 | mtn 4691/udp 359 | radmin-port 4899/tcp # RAdmin Port 360 | radmin-port 4899/udp 361 | rfe 5002/udp # Radio Free Ethernet 362 | rfe 5002/tcp 363 | mmcc 5050/tcp # multimedia conference control tool (Yahoo IM) 364 | mmcc 5050/udp 365 | sip 5060/tcp # Session Initiation Protocol 366 | sip 5060/udp 367 | sip-tls 5061/tcp 368 | sip-tls 5061/udp 369 | aol 5190/tcp # AIM 370 | aol 5190/udp 371 | xmpp-client 5222/tcp jabber-client # Jabber Client Connection 372 | xmpp-client 5222/udp jabber-client 373 | xmpp-server 5269/tcp jabber-server # Jabber Server Connection 374 | xmpp-server 5269/udp jabber-server 375 | cfengine 5308/tcp 376 | cfengine 5308/udp 377 | mdns 5353/tcp # Multicast DNS 378 | mdns 5353/udp 379 | postgresql 5432/tcp postgres # PostgreSQL Database 380 | postgresql 5432/udp postgres 381 | freeciv 5556/tcp rptp # Freeciv gameplay 382 | freeciv 5556/udp 383 | amqp 5672/tcp 384 | amqp 5672/udp 385 | amqp 5672/sctp 386 | ggz 5688/tcp # GGZ Gaming Zone 387 | ggz 5688/udp 388 | x11 6000/tcp x11-0 # X Window System 389 | x11 6000/udp x11-0 390 | x11-1 6001/tcp 391 | x11-1 6001/udp 392 | x11-2 6002/tcp 393 | x11-2 6002/udp 394 | x11-3 6003/tcp 395 | x11-3 6003/udp 396 | x11-4 6004/tcp 397 | x11-4 6004/udp 398 | x11-5 6005/tcp 399 | x11-5 6005/udp 400 | x11-6 6006/tcp 401 | x11-6 6006/udp 402 | x11-7 6007/tcp 403 | x11-7 6007/udp 404 | gnutella-svc 6346/tcp # gnutella 405 | gnutella-svc 6346/udp 406 | gnutella-rtr 6347/tcp # gnutella 407 | gnutella-rtr 6347/udp 408 | sge-qmaster 6444/tcp sge_qmaster # Grid Engine Qmaster Service 409 | sge-qmaster 6444/udp sge_qmaster 410 | sge-execd 6445/tcp sge_execd # Grid Engine Execution Service 411 | sge-execd 6445/udp sge_execd 412 | mysql-proxy 6446/tcp # MySQL Proxy 413 | mysql-proxy 6446/udp 414 | afs3-fileserver 7000/tcp bbs # file server itself 415 | afs3-fileserver 7000/udp bbs 416 | afs3-callback 7001/tcp # callbacks to cache managers 417 | afs3-callback 7001/udp 418 | afs3-prserver 7002/tcp # users & groups database 419 | afs3-prserver 7002/udp 420 | afs3-vlserver 7003/tcp # volume location database 421 | afs3-vlserver 7003/udp 422 | afs3-kaserver 7004/tcp # AFS/Kerberos authentication 423 | afs3-kaserver 7004/udp 424 | afs3-volser 7005/tcp # volume managment server 425 | afs3-volser 7005/udp 426 | afs3-errors 7006/tcp # error interpretation service 427 | afs3-errors 7006/udp 428 | afs3-bos 7007/tcp # basic overseer process 429 | afs3-bos 7007/udp 430 | afs3-update 7008/tcp # server-to-server updater 431 | afs3-update 7008/udp 432 | afs3-rmtsys 7009/tcp # remote cache manager service 433 | afs3-rmtsys 7009/udp 434 | font-service 7100/tcp xfs # X Font Service 435 | font-service 7100/udp xfs 436 | http-alt 8080/tcp webcache # WWW caching service 437 | http-alt 8080/udp 438 | bacula-dir 9101/tcp # Bacula Director 439 | bacula-dir 9101/udp 440 | bacula-fd 9102/tcp # Bacula File Daemon 441 | bacula-fd 9102/udp 442 | bacula-sd 9103/tcp # Bacula Storage Daemon 443 | bacula-sd 9103/udp 444 | xmms2 9667/tcp # Cross-platform Music Multiplexing System 445 | xmms2 9667/udp 446 | nbd 10809/tcp # Linux Network Block Device 447 | zabbix-agent 10050/tcp # Zabbix Agent 448 | zabbix-agent 10050/udp 449 | zabbix-trapper 10051/tcp # Zabbix Trapper 450 | zabbix-trapper 10051/udp 451 | amanda 10080/tcp # amanda backup services 452 | amanda 10080/udp 453 | hkp 11371/tcp # OpenPGP HTTP Keyserver 454 | hkp 11371/udp 455 | bprd 13720/tcp # VERITAS NetBackup 456 | bprd 13720/udp 457 | bpdbm 13721/tcp # VERITAS NetBackup 458 | bpdbm 13721/udp 459 | bpjava-msvc 13722/tcp # BP Java MSVC Protocol 460 | bpjava-msvc 13722/udp 461 | vnetd 13724/tcp # Veritas Network Utility 462 | vnetd 13724/udp 463 | bpcd 13782/tcp # VERITAS NetBackup 464 | bpcd 13782/udp 465 | vopied 13783/tcp # VERITAS NetBackup 466 | vopied 13783/udp 467 | dcap 22125/tcp # dCache Access Protocol 468 | gsidcap 22128/tcp # GSI dCache Access Protocol 469 | wnn6 22273/tcp # wnn6 470 | wnn6 22273/udp 471 | 472 | # 473 | # Datagram Delivery Protocol services 474 | # 475 | rtmp 1/ddp # Routing Table Maintenance Protocol 476 | nbp 2/ddp # Name Binding Protocol 477 | echo 4/ddp # AppleTalk Echo Protocol 478 | zip 6/ddp # Zone Information Protocol 479 | 480 | #========================================================================= 481 | # The remaining port numbers are not as allocated by IANA. 482 | #========================================================================= 483 | 484 | # Kerberos (Project Athena/MIT) services 485 | # Note that these are for Kerberos v4, and are unofficial. Sites running 486 | # v4 should uncomment these and comment out the v5 entries above. 487 | # 488 | kerberos4 750/udp kerberos-iv kdc # Kerberos (server) 489 | kerberos4 750/tcp kerberos-iv kdc 490 | kerberos-master 751/udp kerberos_master # Kerberos authentication 491 | kerberos-master 751/tcp 492 | passwd-server 752/udp passwd_server # Kerberos passwd server 493 | krb-prop 754/tcp krb_prop krb5_prop hprop # Kerberos slave propagation 494 | krbupdate 760/tcp kreg # Kerberos registration 495 | swat 901/tcp # swat 496 | kpop 1109/tcp # Pop with Kerberos 497 | knetd 2053/tcp # Kerberos de-multiplexor 498 | zephyr-srv 2102/udp # Zephyr server 499 | zephyr-clt 2103/udp # Zephyr serv-hm connection 500 | zephyr-hm 2104/udp # Zephyr hostmanager 501 | eklogin 2105/tcp # Kerberos encrypted rlogin 502 | # Hmmm. Are we using Kv4 or Kv5 now? Worrying. 503 | # The following is probably Kerberos v5 --- ajt@debian.org (11/02/2000) 504 | kx 2111/tcp # X over Kerberos 505 | iprop 2121/tcp # incremental propagation 506 | # 507 | # Unofficial but necessary (for NetBSD) services 508 | # 509 | supfilesrv 871/tcp # SUP server 510 | supfiledbg 1127/tcp # SUP debugging 511 | 512 | # 513 | # Services added for the Debian GNU/Linux distribution 514 | # 515 | linuxconf 98/tcp # LinuxConf 516 | poppassd 106/tcp # Eudora 517 | poppassd 106/udp 518 | ssmtp 465/tcp smtps # SMTP over SSL 519 | moira-db 775/tcp moira_db # Moira database 520 | moira-update 777/tcp moira_update # Moira update protocol 521 | moira-ureg 779/udp moira_ureg # Moira user registration 522 | spamd 783/tcp # spamassassin daemon 523 | omirr 808/tcp omirrd # online mirror 524 | omirr 808/udp omirrd 525 | customs 1001/tcp # pmake customs server 526 | customs 1001/udp 527 | skkserv 1178/tcp # skk jisho server port 528 | predict 1210/udp # predict -- satellite tracking 529 | rmtcfg 1236/tcp # Gracilis Packeten remote config server 530 | wipld 1300/tcp # Wipl network monitor 531 | xtel 1313/tcp # french minitel 532 | xtelw 1314/tcp # french minitel 533 | support 1529/tcp # GNATS 534 | cfinger 2003/tcp # GNU Finger 535 | frox 2121/tcp # frox: caching ftp proxy 536 | ninstall 2150/tcp # ninstall service 537 | ninstall 2150/udp 538 | zebrasrv 2600/tcp # zebra service 539 | zebra 2601/tcp # zebra vty 540 | ripd 2602/tcp # ripd vty (zebra) 541 | ripngd 2603/tcp # ripngd vty (zebra) 542 | ospfd 2604/tcp # ospfd vty (zebra) 543 | bgpd 2605/tcp # bgpd vty (zebra) 544 | ospf6d 2606/tcp # ospf6d vty (zebra) 545 | ospfapi 2607/tcp # OSPF-API 546 | isisd 2608/tcp # ISISd vty (zebra) 547 | afbackup 2988/tcp # Afbackup system 548 | afbackup 2988/udp 549 | afmbackup 2989/tcp # Afmbackup system 550 | afmbackup 2989/udp 551 | xtell 4224/tcp # xtell server 552 | fax 4557/tcp # FAX transmission service (old) 553 | hylafax 4559/tcp # HylaFAX client-server protocol (new) 554 | distmp3 4600/tcp # distmp3host daemon 555 | munin 4949/tcp lrrd # Munin 556 | enbd-cstatd 5051/tcp # ENBD client statd 557 | enbd-sstatd 5052/tcp # ENBD server statd 558 | pcrd 5151/tcp # PCR-1000 Daemon 559 | noclog 5354/tcp # noclogd with TCP (nocol) 560 | noclog 5354/udp # noclogd with UDP (nocol) 561 | hostmon 5355/tcp # hostmon uses TCP (nocol) 562 | hostmon 5355/udp # hostmon uses UDP (nocol) 563 | rplay 5555/udp # RPlay audio service 564 | nrpe 5666/tcp # Nagios Remote Plugin Executor 565 | nsca 5667/tcp # Nagios Agent - NSCA 566 | mrtd 5674/tcp # MRT Routing Daemon 567 | bgpsim 5675/tcp # MRT Routing Simulator 568 | canna 5680/tcp # cannaserver 569 | sane-port 6566/tcp sane saned # SANE network scanner daemon 570 | ircd 6667/tcp # Internet Relay Chat 571 | zope-ftp 8021/tcp # zope management by ftp 572 | tproxy 8081/tcp # Transparent Proxy 573 | omniorb 8088/tcp # OmniORB 574 | omniorb 8088/udp 575 | clc-build-daemon 8990/tcp # Common lisp build daemon 576 | xinetd 9098/tcp 577 | mandelspawn 9359/udp mandelbrot # network mandelbrot 578 | git 9418/tcp # Git Version Control System 579 | zope 9673/tcp # zope server 580 | webmin 10000/tcp 581 | kamanda 10081/tcp # amanda backup services (Kerberos) 582 | kamanda 10081/udp 583 | amandaidx 10082/tcp # amanda backup services 584 | amidxtape 10083/tcp # amanda backup services 585 | smsqp 11201/tcp # Alamin SMS gateway 586 | smsqp 11201/udp 587 | xpilot 15345/tcp # XPilot Contact Port 588 | xpilot 15345/udp 589 | sgi-cmsd 17001/udp # Cluster membership services daemon 590 | sgi-crsd 17002/udp 591 | sgi-gcd 17003/udp # SGI Group membership daemon 592 | sgi-cad 17004/tcp # Cluster Admin daemon 593 | isdnlog 20011/tcp # isdn logging system 594 | isdnlog 20011/udp 595 | vboxd 20012/tcp # voice box system 596 | vboxd 20012/udp 597 | binkp 24554/tcp # binkp fidonet protocol 598 | asp 27374/tcp # Address Search Protocol 599 | asp 27374/udp 600 | csync2 30865/tcp # cluster synchronization tool 601 | dircproxy 57000/tcp # Detachable IRC Proxy 602 | tfido 60177/tcp # fidonet EMSI over telnet 603 | fido 60179/tcp # fidonet EMSI over TCP 604 | 605 | # Local services 606 | -------------------------------------------------------------------------------- /static/client.js: -------------------------------------------------------------------------------- 1 | var socket = io.connect('/'); 2 | 3 | function formatNumber(num) { 4 | // formats 12345003 as "12,345,003" 5 | var ords = []; 6 | var s = ""; 7 | var i; 8 | while(num > 0) { 9 | s = (num % 1000).toString(); 10 | 11 | // makes sure all digit groups except the first are 12 | // 0-prefixed. 13 | if (num > 999) { 14 | for (i=s.length; i<3; i++) { 15 | s = "0" + s; 16 | } 17 | } 18 | ords.unshift(s); 19 | num = (num / 1000).toFixed(0); 20 | if (ords.length > 4) break; 21 | } 22 | // type casting to string ok 23 | return ords.join(','); 24 | } 25 | 26 | /* 27 | * receive messages from server. We can get one of three messages: 28 | * - memory sample (periodic memoryUsage() results) 29 | * - partial GC stats 30 | * - full GC stats 31 | */ 32 | 33 | 34 | socket.on('temporal-sample', function(data) { 35 | $('.RSS .data').text(formatNumber(data.rss)); 36 | $('.heapTotal .data').text(formatNumber(data.heapTotal)); 37 | $('.heapUsed .data').text(formatNumber(data.heapUsed)); 38 | Graph.addTimeSample(data); 39 | }); 40 | 41 | function updateGCDataList(stats) { 42 | $('.usageTrend .data').text(stats.usage_trend.toFixed(2)); 43 | $('.fullGCCount .data').text(formatNumber(stats.num_full_gc)); 44 | $('.incrGCCount .data').text(formatNumber(stats.num_inc_gc)); 45 | $('.heapCompactions .data').text(stats.heap_compactions); 46 | } 47 | socket.on('post-full-gc-sample', function(data) { 48 | $('.currentBase .data').text(formatNumber(data.current_base)); 49 | $('.estimatedBase .data').text(formatNumber(data.estimated_base)); 50 | updateGCDataList(data); 51 | Graph.addGcData('full', data); 52 | }); 53 | 54 | socket.on('post-incremental-gc-sample', function(data) { 55 | $('.currentBase .data').text(formatNumber(data.current_base)); 56 | $('.estimatedBase .data').text(formatNumber(data.estimated_base)); 57 | updateGCDataList(data); 58 | Graph.addGcData('incremental', data); 59 | }); 60 | 61 | socket.on('heap-allocations', function(data) { 62 | // fill the first six things in the heap allocations list 63 | var items = $(".allocations").find("ul").children(); 64 | for (var i=0; i<6; i++) { 65 | var alloc = data[i]; 66 | if (!alloc) break; 67 | var item = $(items[i]); 68 | item.find(".name").text(alloc[1][0]); 69 | item.find(".data").text(alloc[0]); 70 | } 71 | }); 72 | 73 | socket.on('pause', function(data) { 74 | if (data.paused) { 75 | $('.pause-button').addClass('paused').text('GO'); 76 | $('#add_load').addClass('disabled'); 77 | } else { 78 | $('.pause-button').removeClass('paused').text('STOP'); 79 | $('#add_load').removeClass('disabled'); 80 | } 81 | }); 82 | 83 | socket.on('configure', function(data) { 84 | if (data.show) { 85 | // csl of things to show 86 | data.show.split(',').forEach(function(thing) { 87 | $("." + thing.trim()).fadeIn(); 88 | }); 89 | } 90 | if (data.title) { 91 | $(".title").text(data.title); 92 | } 93 | }); 94 | 95 | /* 96 | * Interface - the operator can: 97 | * - choose "Force Compaction", which calls gc() on the gcstats obj 98 | * - choose "Make It Busy", which adds load to the server for a second or two 99 | */ 100 | $('#do_gc').on('click', function() { 101 | socket.send("do_gc"); 102 | }); 103 | 104 | $('#add_load').on('click', function() { 105 | socket.send("add_load"); 106 | }); 107 | 108 | $('#pause').on('click', function() { 109 | socket.send("pause"); 110 | }); -------------------------------------------------------------------------------- /static/graph.js: -------------------------------------------------------------------------------- 1 | window.Graph = {}; 2 | 3 | (function() { 4 | var MB = 1000 * 1000; // actual 1024*1024 makes the resulting text confusing to compare 5 | var w = 600, 6 | h = 300, 7 | margin = 100; 8 | 9 | var vis = d3.select( document.getElementById('graph') ) 10 | .append("svg:svg") 11 | .attr("width", w) 12 | .attr("height", h); 13 | 14 | var base = vis.append("svg:g").attr("transform", "translate(0, 300)"); 15 | var g = vis.append("svg:g").attr("transform", "translate(45, 300)"); 16 | 17 | // data sets we're collecting 18 | var timeSamples = [0]; 19 | var gcFullSamples = [0]; 20 | var nextFullSample = null; 21 | // var gcIncrementalSamples = [0]; 22 | var heapSize = 0; 23 | var heapLeast = Infinity; 24 | var currentBase = 0; 25 | var estimatedBase = 0; 26 | 27 | var MAX_HISTORY = 350; 28 | 29 | function updateData(arr, data) { 30 | arr.push(data); 31 | if (arr.length > MAX_HISTORY) arr.shift(); 32 | } 33 | 34 | function drawLine(data) { 35 | var y = d3.scale.linear().domain([0, heapSize]).range([0, h]), 36 | x = d3.scale.linear().domain([0, MAX_HISTORY]).range([0, w - margin]); 37 | 38 | var line = d3.svg.line() 39 | .x(function(d,i) { return x(i); }) 40 | .y(function(d) { return -1 * y(d); }); 41 | 42 | g.append("svg:path").attr("d", line(data)); 43 | 44 | // now for a max label 45 | base.append("svg:text") 46 | .attr("class", "linktext, data") 47 | .attr('x', 550) 48 | .attr('y', 16-h) 49 | .text(heapSize.toFixed(1)); 50 | // show the estimatedBase size, tracking in y with its curve 51 | base.append("svg:text") 52 | .attr("class", "linktext, data") 53 | .attr('x', 550) 54 | .attr('y', (currentBase/heapSize || 0) * (16 - h)) 55 | .text(currentBase.toFixed(1)); 56 | // base.append("svg:text").attr("class", "linktext, data") 57 | // .attr('x', 550) 58 | // .attr('y', (heapLeast/heapSize) * (16-h)) 59 | // .text(heapLeast.toFixed(1)); 60 | } 61 | 62 | Graph.addGcData = function(type, gcData) { 63 | // fields are: 64 | // compacted: bool 65 | // stats: { num_full_gc: int 66 | // num_inc_gc: int 67 | // heap_compactions: int 68 | // usage_trend: float 69 | // estimated_base: bytes 70 | // current_base: bytes 71 | // min: { bytes: bytes, when: Date } 72 | // max: { bytes: bytes, when: Date } } 73 | // 74 | // convert all units to MB 75 | currentBase = gcData.current_base / MB; 76 | estimatedBase = gcData.estimated_base / MB; 77 | var usage_trend = gcData.usageTrend; 78 | 79 | heapLeast = Math.min(heapLeast, gcData.current_base / MB); 80 | if (type === 'full') { 81 | nextFullSample = currentBase; 82 | } 83 | }; 84 | 85 | Graph.addFullGcData = function(gcData) { 86 | Graph.addGcData('full', gcData); 87 | }; 88 | 89 | Graph.addIncrementalGcData = function(gcData) { 90 | Graph.addGcData('incremental', gcData); 91 | }; 92 | 93 | Graph.addTimeSample = function(timeData) { 94 | // fields are: 95 | // rss: bytes 96 | // heapTotal: bytes 97 | // heapUsed: bytes 98 | // 99 | // Convert all units to MB 100 | var heapUsed = timeData.heapUsed / MB; 101 | heapSize = Math.max(heapUsed, heapSize); 102 | 103 | Graph.replot({timeSample: heapUsed}); 104 | }; 105 | 106 | Graph.replot = function(sample) { 107 | var numSamples = timeSamples.length; 108 | if (sample.timeSample) { 109 | updateData(timeSamples, sample.timeSample); 110 | if (nextFullSample !== null) { 111 | updateData(gcFullSamples, nextFullSample); 112 | nextFullSample = null; 113 | } else { 114 | updateData(gcFullSamples, gcFullSamples[numSamples-1]); 115 | } 116 | } 117 | 118 | d3.selectAll('svg path').remove(); 119 | d3.selectAll('svg text').remove(); 120 | 121 | drawLine(timeSamples, "MB"); 122 | // drawLine(gcIncrementalSamples, "MB"); 123 | drawLine(gcFullSamples, "MB"); 124 | }; 125 | })(); 126 | -------------------------------------------------------------------------------- /static/head.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | Head JS The only script in your 3 | Copyright Tero Piirainen (tipiirai) 4 | License MIT / http://bit.ly/mit-license 5 | Version 0.96 6 | 7 | http://headjs.com 8 | */(function(a){function l(){var a=window.outerWidth||b.clientWidth;b.className=b.className.replace(/ (w|lt)-\d+/g,""),f("w-"+Math.round(a/100)*100),h(c.screens,function(b){a<=b&&f("lt-"+b)}),i.feature()}function h(a,b){for(var c=0,d=a.length;c2&&this[d+1]!==undefined)d&&f(this.slice(1,d+1).join("-")+c.section);else{var e=a||"index",g=e.indexOf(".");g>0&&(e=e.substring(0,g)),b.id=e+c.page,d||f("root"+c.section)}}),l(),window.onresize=l,i.feature("js",!0).feature()})(document),function(){function h(a){var b=a.charAt(0).toUpperCase()+a.substr(1),c=(a+" "+d.join(b+" ")+b).split(" ");return!!g(c)}function g(a){for(var c in a)if(b[a[c]]!==undefined)return!0}var a=document.createElement("i"),b=a.style,c=" -o- -moz- -ms- -webkit- -khtml- ".split(" "),d="Webkit Moz O ms Khtml".split(" "),e=window.head_conf&&head_conf.head||"head",f=window[e],i={gradient:function(){var a="background-image:",d="gradient(linear,left top,right bottom,from(#9f9),to(#fff));",e="linear-gradient(left top,#eee,#fff);";b.cssText=(a+c.join(d+a)+c.join(e+a)).slice(0,-a.length);return!!b.backgroundImage},rgba:function(){b.cssText="background-color:rgba(0,0,0,0.5)";return!!b.backgroundColor},opacity:function(){return a.style.opacity===""},textshadow:function(){return b.textShadow===""},multiplebgs:function(){b.cssText="background:url(//:),url(//:),red url(//:)";return(new RegExp("(url\\s*\\(.*?){3}")).test(b.background)},boxshadow:function(){return h("boxShadow")},borderimage:function(){return h("borderImage")},borderradius:function(){return h("borderRadius")},cssreflections:function(){return h("boxReflect")},csstransforms:function(){return h("transform")},csstransitions:function(){return h("transition")},fontface:function(){var a=navigator.userAgent,b;if(0)return!0;if(b=a.match(/Chrome\/(\d+\.\d+\.\d+\.\d+)/))return b[1]>="4.0.249.4"||1*b[1].split(".")[0]>5;if((b=a.match(/Safari\/(\d+\.\d+)/))&&!/iPhone/.test(a))return b[1]>="525.13";if(/Opera/.test({}.toString.call(window.opera)))return opera.version()>="10.00";if(b=a.match(/rv:(\d+\.\d+\.\d+)[^b].*Gecko\//))return b[1]>="1.9.1";return!1}};for(var j in i)i[j]&&f.feature(j,i[j].call(),!0);f.feature()}(),function(a){function z(){d||(d=!0,s(e,function(a){p(a)}))}function y(c,d){var e=a.createElement("script");e.type="text/"+(c.type||"javascript"),e.src=c.src||c,e.async=!1,e.onreadystatechange=e.onload=function(){var a=e.readyState;!d.done&&(!a||/loaded|complete/.test(a))&&(d.done=!0,d())},(a.body||b).appendChild(e)}function x(a,b){if(a.state==o)return b&&b();if(a.state==n)return k.ready(a.name,b);if(a.state==m)return a.onpreload.push(function(){x(a,b)});a.state=n,y(a.url,function(){a.state=o,b&&b(),s(g[a.name],function(a){p(a)}),u()&&d&&s(g.ALL,function(a){p(a)})})}function w(a,b){a.state===undefined&&(a.state=m,a.onpreload=[],y({src:a.url,type:"cache"},function(){v(a)}))}function v(a){a.state=l,s(a.onpreload,function(a){a.call()})}function u(a){a=a||h;var b;for(var c in a){if(a.hasOwnProperty(c)&&a[c].state!=o)return!1;b=!0}return b}function t(a){return Object.prototype.toString.call(a)=="[object Function]"}function s(a,b){if(!!a){typeof a=="object"&&(a=[].slice.call(a));for(var c=0;c 2 | 3 | 4 | node-memwatch 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 18 | 19 |

 

20 | 21 |
    22 |
  • GO
  • 23 |
  • Force Compaction
  • 24 |
  • Make It Busy
  • 25 |
26 | 27 |
28 | 29 | 33 | 34 | 35 |
36 | 47 | 48 | 56 | 57 | 68 | 69 |
70 | 71 |
72 | 73 | 74 | 75 | 87 | 88 | -------------------------------------------------------------------------------- /static/jquery-1.7.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v1.7.1 jquery.com | jquery.org/license */ 2 | (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
"+""+"
",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
t
",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; 3 | f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() 4 | {for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); -------------------------------------------------------------------------------- /static/jquery.noisy.min.js: -------------------------------------------------------------------------------- 1 | (function(c){c.fn.noisy=function(b){var b=c.extend({},c.fn.noisy.defaults,b),d,h,a=!1;try{h=!0,a=localStorage.getItem(window.JSON.stringify(b))}catch(l){h=!1}if(a)d=a;else{a=document.createElement("canvas");if(a.getContext){a.width=a.height=b.size;for(var i=a.getContext("2d"),e=i.createImageData(a.width,a.height),j=b.intensity*Math.pow(b.size,2),k=255*b.opacity;j--;){var f=~~(Math.random()*a.width),g=~~(Math.random()*a.height),f=4*(f+g*e.width),g=j%255;e.data[f]=g;e.data[f+1]=b.monochrome?g:~~(255* 2 | Math.random());e.data[f+2]=b.monochrome?g:~~(255*Math.random());e.data[f+3]=~~(Math.random()*k)}i.putImageData(e,0,0);d=a.toDataURL("image/png");if(0!=d.indexOf("data:image/png")||c.browser.msie&&9>c.browser.version.substr(0,1)&&32768 li { 126 | position: relative; 127 | min-width: 260px; 128 | } 129 | 130 | .data { 131 | text-align: right; 132 | display: inline-block; 133 | right: 0; 134 | position: absolute; 135 | } 136 | 137 | .left { 138 | margin-right: 20px; 139 | } 140 | 141 | .right { 142 | top: 0px; 143 | position: absolute; 144 | } 145 | 146 | a { 147 | text-decoration: none; 148 | } 149 | 150 | code, pre, tt, .data { 151 | font-family: 'Cousine', sans-serif; 152 | font-weight: 400; 153 | } 154 | 155 | svg { 156 | border-radius: 12px; 157 | padding: 12px; 158 | } 159 | 160 | .display-box, 161 | svg { 162 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); 163 | background-color: #ccc; 164 | } 165 | 166 | svg path { 167 | stroke: black; 168 | stroke-width: 1; 169 | fill: none; 170 | } 171 | 172 | svg text { 173 | stroke: black; 174 | } 175 | 176 | svg line { 177 | stroke: black; 178 | } 179 | 180 | /* the current heap usage is green */ 181 | svg path:nth-of-type(1) { 182 | stroke: green; 183 | } 184 | svg text:nth-of-type(1) { 185 | stroke: green; 186 | } 187 | .heapUsed > .data { 188 | color: green; 189 | } 190 | 191 | /* heap base is red */ 192 | svg path:nth-of-type(2) { 193 | stroke: red; 194 | } 195 | svg text:nth-of-type(2) { 196 | stroke: red; 197 | } 198 | .currentBase > .data { 199 | color: red; 200 | } 201 | 202 | ul.buttons { 203 | text-align: center; 204 | margin: .5em 0em; 205 | margin-left: auto; 206 | margin-right: auto; 207 | } 208 | ul.buttons li.button { 209 | display: inline-block; 210 | text-align: center; 211 | line-height: 1.67em; 212 | padding: 2px 6px; 213 | color: #000; 214 | margin: 0px 6px; 215 | border-radius: .3em; 216 | text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); 217 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 218 | } 219 | .big-button { 220 | background-color: #eee; 221 | min-width: 12em; 222 | background: -moz-linear-gradient(top, #549fdc, #4384c4); 223 | } 224 | .pause-button { 225 | min-width: 3em; 226 | background: -moz-linear-gradient(top, #f32c1d, #cc2518); 227 | } 228 | .paused { 229 | background: -moz-linear-gradient(top, #31dc17, #20be16); 230 | } 231 | ul.buttons li:hover, 232 | ul.buttons li:active { 233 | cursor: pointer; 234 | } 235 | 236 | li.button:active { 237 | position: relative; 238 | top: 1px; /* slight push down on click */ 239 | } 240 | li.big-button:active, 241 | li.big-button:hover { 242 | background: -moz-linear-gradient(top, #679ef1, #538ad1); 243 | } 244 | 245 | li.pause-button:active, 246 | li.pause-button:hover { 247 | background: -moz-linear-gradient(top, #fa352d, #dc3528); 248 | } 249 | li.paused:active, 250 | li.paused:hover { 251 | background: -moz-linear-gradient(top, #41ec27, #20be16); 252 | } 253 | 254 | 255 | 256 | -------------------------------------------------------------------------------- /static/svg.css: -------------------------------------------------------------------------------- 1 | svg path { 2 | stroke: black; 3 | stroke-width: 1; 4 | fill: none; 5 | } 6 | 7 | svg text { 8 | stroke black; 9 | opacity: 0.5; 10 | } 11 | 12 | svg line { 13 | stroke: black; 14 | } 15 | 16 | svg { 17 | border: 1px solid green; 18 | border-radius: 12px; 19 | padding: 12px; 20 | margin: auto; 21 | } -------------------------------------------------------------------------------- /worker.js: -------------------------------------------------------------------------------- 1 | // A worker. Sometimes well-behaved, sometimes not. 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | 6 | var paused = true; 7 | var config = require('./config'); 8 | console.log("worker config: leak=" + config.leak); 9 | 10 | var numToSpawn = 100; 11 | var leak = []; 12 | 13 | var bigText = fs.readFileSync(path.join(__dirname, 'something.txt')); 14 | console.log("read %d bytes for bigText", bigText.length); 15 | 16 | function SlowTask() { 17 | this.stuff = bigText; 18 | } 19 | 20 | var doYourThing = module.exports.doYourThing = function doYourThing() { 21 | goFastWorkers(250); 22 | goSlowWorkers(400); 23 | if (config.leak) goLeakyWorkers(); 24 | }; 25 | 26 | var togglePause = module.exports.togglePause = function() { 27 | if (paused) { 28 | paused = false; 29 | doYourThing(); 30 | } else { 31 | paused = true; 32 | } 33 | return paused; 34 | }; 35 | 36 | var goSlowWorkers = function goSlowWorkers(interval) { 37 | if (paused) { 38 | return; 39 | } 40 | var obj = {}; 41 | 42 | // A non-leaking bunch of work that lasts a fairly long time 43 | if (Math.random() > 0.1) { 44 | //console.log("spawn slow workers. interval: " + interval); 45 | var spawned = 0; 46 | // make a huge object and hold onto it for 1/2 sec 47 | for (var i=0; i<100;i++) { 48 | obj[i] = new SlowTask; 49 | } 50 | setTimeout(function() { 51 | //console.log("freeing obj"); 52 | obj = undefined; 53 | setTimeout(function(){goSlowWorkers(Math.random()*200+200);}, interval); 54 | }, 100); 55 | } else { 56 | obj = undefined; 57 | setTimeout(function(){goSlowWorkers(Math.random()*200+200);}, interval); 58 | } 59 | }; 60 | 61 | var goFastWorkers = function goFastWorkers(interval) { 62 | if (paused) { 63 | return; 64 | } 65 | // A non-leaking bunch of work that lasts a short time 66 | if (Math.random() > .5) { 67 | //console.log("spawn fast workers. interval: " + interval); 68 | var workers = Math.floor(Math.random() * numToSpawn); 69 | var spawned = 0; 70 | function spawn() { 71 | spawned ++; 72 | var txt = ""; 73 | for (var i=0; i<100; i++) { 74 | txt += i + bigText; 75 | } 76 | } 77 | function spawnNext() { 78 | spawn(); 79 | if (spawned < workers) { 80 | setTimeout(spawnNext, 15); 81 | } else { 82 | setTimeout(function(){goFastWorkers(interval);}, Math.floor(Math.random()*interval)); 83 | } 84 | } 85 | spawnNext(); 86 | numToSpawn += Math.floor(numToSpawn / 72); 87 | } else { 88 | things = undefined; 89 | setTimeout(function(){goFastWorkers(Math.random()*100+100);}, Math.floor(Math.random()*interval)); 90 | } 91 | }; 92 | 93 | function DeathBunny(someInput) { 94 | this.info = Math.random(); 95 | this.foo = someInput; 96 | return this.foo + this.info; 97 | }; 98 | var goLeakyWorkers = function goLeakyWorkers() { 99 | if (paused) { 100 | return; 101 | } 102 | // A buncho of work that leaks periodically 103 | if (Math.random() > .995) { 104 | var max = Math.floor(Math.random() * 10); 105 | console.log("LEAKING " + max); 106 | var txt = ""; 107 | for (var i=0; i