##// END OF EJS Templates
use TextEncoding for string<->ArrayBuffer...
MinRK -
Show More
@@ -1,1026 +1,1026 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/utils',
8 'services/kernels/js/comm',
9 'widgets/js/init',
10 './serialize'
11 ], function(IPython, $, utils, comm, widgetmanager, serialize) {
8 './comm',
9 './serialize',
10 'widgets/js/init'
11 ], function(IPython, $, utils, comm, serialize, widgetmanager) {
12 12 "use strict";
13 13
14 14 /**
15 15 * A Kernel class to communicate with the Python kernel. This
16 16 * should generally not be constructed directly, but be created
17 17 * by. the `Session` object. Once created, this object should be
18 18 * used to communicate with the kernel.
19 19 *
20 20 * @class Kernel
21 21 * @param {string} kernel_service_url - the URL to access the kernel REST api
22 22 * @param {string} ws_url - the websockets URL
23 23 * @param {Notebook} notebook - notebook object
24 24 * @param {string} name - the kernel type (e.g. python3)
25 25 */
26 26 var Kernel = function (kernel_service_url, ws_url, notebook, name) {
27 27 this.events = notebook.events;
28 28
29 29 this.id = null;
30 30 this.name = name;
31 31
32 32 this.channels = {
33 33 'shell': null,
34 34 'iopub': null,
35 35 'stdin': null
36 36 };
37 37
38 38 this.kernel_service_url = kernel_service_url;
39 39 this.kernel_url = null;
40 40 this.ws_url = ws_url || IPython.utils.get_body_data("wsUrl");
41 41 if (!this.ws_url) {
42 42 // trailing 's' in https will become wss for secure web sockets
43 43 this.ws_url = location.protocol.replace('http', 'ws') + "//" + location.host;
44 44 }
45 45
46 46 this.username = "username";
47 47 this.session_id = utils.uuid();
48 48 this._msg_callbacks = {};
49 49
50 50 if (typeof(WebSocket) !== 'undefined') {
51 51 this.WebSocket = WebSocket;
52 52 } else if (typeof(MozWebSocket) !== 'undefined') {
53 53 this.WebSocket = MozWebSocket;
54 54 } else {
55 55 alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox β‰₯ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
56 56 }
57 57
58 58 this.bind_events();
59 59 this.init_iopub_handlers();
60 60 this.comm_manager = new comm.CommManager(this);
61 61 this.widget_manager = new widgetmanager.WidgetManager(this.comm_manager, notebook);
62 62
63 63 this.last_msg_id = null;
64 64 this.last_msg_callbacks = {};
65 65
66 66 this._autorestart_attempt = 0;
67 67 this._reconnect_attempt = 0;
68 68 };
69 69
70 70 /**
71 71 * @function _get_msg
72 72 */
73 73 Kernel.prototype._get_msg = function (msg_type, content, metadata, buffers) {
74 74 var msg = {
75 75 header : {
76 76 msg_id : utils.uuid(),
77 77 username : this.username,
78 78 session : this.session_id,
79 79 msg_type : msg_type,
80 80 version : "5.0"
81 81 },
82 82 metadata : metadata || {},
83 83 content : content,
84 84 buffers : buffers || [],
85 85 parent_header : {}
86 86 };
87 87 return msg;
88 88 };
89 89
90 90 /**
91 91 * @function bind_events
92 92 */
93 93 Kernel.prototype.bind_events = function () {
94 94 var that = this;
95 95 this.events.on('send_input_reply.Kernel', function(evt, data) {
96 96 that.send_input_reply(data);
97 97 });
98 98
99 99 var record_status = function (evt, info) {
100 100 console.log('Kernel: ' + evt.type + ' (' + info.kernel.id + ')');
101 101 };
102 102
103 103 this.events.on('kernel_created.Kernel', record_status);
104 104 this.events.on('kernel_reconnecting.Kernel', record_status);
105 105 this.events.on('kernel_connected.Kernel', record_status);
106 106 this.events.on('kernel_starting.Kernel', record_status);
107 107 this.events.on('kernel_restarting.Kernel', record_status);
108 108 this.events.on('kernel_autorestarting.Kernel', record_status);
109 109 this.events.on('kernel_interrupting.Kernel', record_status);
110 110 this.events.on('kernel_disconnected.Kernel', record_status);
111 111 // these are commented out because they are triggered a lot, but can
112 112 // be uncommented for debugging purposes
113 113 //this.events.on('kernel_idle.Kernel', record_status);
114 114 //this.events.on('kernel_busy.Kernel', record_status);
115 115 this.events.on('kernel_ready.Kernel', record_status);
116 116 this.events.on('kernel_killed.Kernel', record_status);
117 117 this.events.on('kernel_dead.Kernel', record_status);
118 118
119 119 this.events.on('kernel_ready.Kernel', function () {
120 120 that._autorestart_attempt = 0;
121 121 });
122 122 this.events.on('kernel_connected.Kernel', function () {
123 123 that._reconnect_attempt = 0;
124 124 });
125 125 };
126 126
127 127 /**
128 128 * Initialize the iopub handlers.
129 129 *
130 130 * @function init_iopub_handlers
131 131 */
132 132 Kernel.prototype.init_iopub_handlers = function () {
133 133 var output_msg_types = ['stream', 'display_data', 'execute_result', 'error'];
134 134 this._iopub_handlers = {};
135 135 this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
136 136 this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
137 137
138 138 for (var i=0; i < output_msg_types.length; i++) {
139 139 this.register_iopub_handler(output_msg_types[i], $.proxy(this._handle_output_message, this));
140 140 }
141 141 };
142 142
143 143 /**
144 144 * GET /api/kernels
145 145 *
146 146 * Get the list of running kernels.
147 147 *
148 148 * @function list
149 149 * @param {function} [success] - function executed on ajax success
150 150 * @param {function} [error] - functon executed on ajax error
151 151 */
152 152 Kernel.prototype.list = function (success, error) {
153 153 $.ajax(this.kernel_service_url, {
154 154 processData: false,
155 155 cache: false,
156 156 type: "GET",
157 157 dataType: "json",
158 158 success: success,
159 159 error: this._on_error(error)
160 160 });
161 161 };
162 162
163 163 /**
164 164 * POST /api/kernels
165 165 *
166 166 * Start a new kernel.
167 167 *
168 168 * In general this shouldn't be used -- the kernel should be
169 169 * started through the session API. If you use this function and
170 170 * are also using the session API then your session and kernel
171 171 * WILL be out of sync!
172 172 *
173 173 * @function start
174 174 * @param {params} [Object] - parameters to include in the query string
175 175 * @param {function} [success] - function executed on ajax success
176 176 * @param {function} [error] - functon executed on ajax error
177 177 */
178 178 Kernel.prototype.start = function (params, success, error) {
179 179 var url = this.kernel_service_url;
180 180 var qs = $.param(params || {}); // query string for sage math stuff
181 181 if (qs !== "") {
182 182 url = url + "?" + qs;
183 183 }
184 184
185 185 var that = this;
186 186 var on_success = function (data, status, xhr) {
187 187 that.events.trigger('kernel_created.Kernel', {kernel: that});
188 188 that._kernel_created(data);
189 189 if (success) {
190 190 success(data, status, xhr);
191 191 }
192 192 };
193 193
194 194 $.ajax(url, {
195 195 processData: false,
196 196 cache: false,
197 197 type: "POST",
198 198 data: JSON.stringify({name: this.name}),
199 199 dataType: "json",
200 200 success: this._on_success(on_success),
201 201 error: this._on_error(error)
202 202 });
203 203
204 204 return url;
205 205 };
206 206
207 207 /**
208 208 * GET /api/kernels/[:kernel_id]
209 209 *
210 210 * Get information about the kernel.
211 211 *
212 212 * @function get_info
213 213 * @param {function} [success] - function executed on ajax success
214 214 * @param {function} [error] - functon executed on ajax error
215 215 */
216 216 Kernel.prototype.get_info = function (success, error) {
217 217 $.ajax(this.kernel_url, {
218 218 processData: false,
219 219 cache: false,
220 220 type: "GET",
221 221 dataType: "json",
222 222 success: this._on_success(success),
223 223 error: this._on_error(error)
224 224 });
225 225 };
226 226
227 227 /**
228 228 * DELETE /api/kernels/[:kernel_id]
229 229 *
230 230 * Shutdown the kernel.
231 231 *
232 232 * If you are also using sessions, then this function shoul NOT be
233 233 * used. Instead, use Session.delete. Otherwise, the session and
234 234 * kernel WILL be out of sync.
235 235 *
236 236 * @function kill
237 237 * @param {function} [success] - function executed on ajax success
238 238 * @param {function} [error] - functon executed on ajax error
239 239 */
240 240 Kernel.prototype.kill = function (success, error) {
241 241 this.events.trigger('kernel_killed.Kernel', {kernel: this});
242 242 this._kernel_dead();
243 243 $.ajax(this.kernel_url, {
244 244 processData: false,
245 245 cache: false,
246 246 type: "DELETE",
247 247 dataType: "json",
248 248 success: this._on_success(success),
249 249 error: this._on_error(error)
250 250 });
251 251 };
252 252
253 253 /**
254 254 * POST /api/kernels/[:kernel_id]/interrupt
255 255 *
256 256 * Interrupt the kernel.
257 257 *
258 258 * @function interrupt
259 259 * @param {function} [success] - function executed on ajax success
260 260 * @param {function} [error] - functon executed on ajax error
261 261 */
262 262 Kernel.prototype.interrupt = function (success, error) {
263 263 this.events.trigger('kernel_interrupting.Kernel', {kernel: this});
264 264
265 265 var that = this;
266 266 var on_success = function (data, status, xhr) {
267 267 // get kernel info so we know what state the kernel is in
268 268 that.kernel_info();
269 269 if (success) {
270 270 success(data, status, xhr);
271 271 }
272 272 };
273 273
274 274 var url = utils.url_join_encode(this.kernel_url, 'interrupt');
275 275 $.ajax(url, {
276 276 processData: false,
277 277 cache: false,
278 278 type: "POST",
279 279 dataType: "json",
280 280 success: this._on_success(on_success),
281 281 error: this._on_error(error)
282 282 });
283 283 };
284 284
285 285 /**
286 286 * POST /api/kernels/[:kernel_id]/restart
287 287 *
288 288 * Restart the kernel.
289 289 *
290 290 * @function interrupt
291 291 * @param {function} [success] - function executed on ajax success
292 292 * @param {function} [error] - functon executed on ajax error
293 293 */
294 294 Kernel.prototype.restart = function (success, error) {
295 295 this.events.trigger('kernel_restarting.Kernel', {kernel: this});
296 296 this.stop_channels();
297 297
298 298 var that = this;
299 299 var on_success = function (data, status, xhr) {
300 300 that.events.trigger('kernel_created.Kernel', {kernel: that});
301 301 that._kernel_created(data);
302 302 if (success) {
303 303 success(data, status, xhr);
304 304 }
305 305 };
306 306
307 307 var on_error = function (xhr, status, err) {
308 308 that.events.trigger('kernel_dead.Kernel', {kernel: that});
309 309 that._kernel_dead();
310 310 if (error) {
311 311 error(xhr, status, err);
312 312 }
313 313 };
314 314
315 315 var url = utils.url_join_encode(this.kernel_url, 'restart');
316 316 $.ajax(url, {
317 317 processData: false,
318 318 cache: false,
319 319 type: "POST",
320 320 dataType: "json",
321 321 success: this._on_success(on_success),
322 322 error: this._on_error(on_error)
323 323 });
324 324 };
325 325
326 326 /**
327 327 * Reconnect to a disconnected kernel. This is not actually a
328 328 * standard HTTP request, but useful function nonetheless for
329 329 * reconnecting to the kernel if the connection is somehow lost.
330 330 *
331 331 * @function reconnect
332 332 */
333 333 Kernel.prototype.reconnect = function () {
334 334 this.events.trigger('kernel_reconnecting.Kernel', {kernel: this});
335 335 setTimeout($.proxy(this.start_channels, this), 3000);
336 336 };
337 337
338 338 /**
339 339 * Handle a successful AJAX request by updating the kernel id and
340 340 * name from the response, and then optionally calling a provided
341 341 * callback.
342 342 *
343 343 * @function _on_success
344 344 * @param {function} success - callback
345 345 */
346 346 Kernel.prototype._on_success = function (success) {
347 347 var that = this;
348 348 return function (data, status, xhr) {
349 349 if (data) {
350 350 that.id = data.id;
351 351 that.name = data.name;
352 352 }
353 353 that.kernel_url = utils.url_join_encode(that.kernel_service_url, that.id);
354 354 if (success) {
355 355 success(data, status, xhr);
356 356 }
357 357 };
358 358 };
359 359
360 360 /**
361 361 * Handle a failed AJAX request by logging the error message, and
362 362 * then optionally calling a provided callback.
363 363 *
364 364 * @function _on_error
365 365 * @param {function} error - callback
366 366 */
367 367 Kernel.prototype._on_error = function (error) {
368 368 return function (xhr, status, err) {
369 369 utils.log_ajax_error(xhr, status, err);
370 370 if (error) {
371 371 error(xhr, status, err);
372 372 }
373 373 };
374 374 };
375 375
376 376 /**
377 377 * Perform necessary tasks once the kernel has been started,
378 378 * including actually connecting to the kernel.
379 379 *
380 380 * @function _kernel_created
381 381 * @param {Object} data - information about the kernel including id
382 382 */
383 383 Kernel.prototype._kernel_created = function (data) {
384 384 this.id = data.id;
385 385 this.kernel_url = utils.url_join_encode(this.kernel_service_url, this.id);
386 386 this.start_channels();
387 387 };
388 388
389 389 /**
390 390 * Perform necessary tasks once the connection to the kernel has
391 391 * been established. This includes requesting information about
392 392 * the kernel.
393 393 *
394 394 * @function _kernel_connected
395 395 */
396 396 Kernel.prototype._kernel_connected = function () {
397 397 this.events.trigger('kernel_connected.Kernel', {kernel: this});
398 398 this.events.trigger('kernel_starting.Kernel', {kernel: this});
399 399 // get kernel info so we know what state the kernel is in
400 400 var that = this;
401 401 this.kernel_info(function () {
402 402 that.events.trigger('kernel_ready.Kernel', {kernel: that});
403 403 });
404 404 };
405 405
406 406 /**
407 407 * Perform necessary tasks after the kernel has died. This closing
408 408 * communication channels to the kernel if they are still somehow
409 409 * open.
410 410 *
411 411 * @function _kernel_dead
412 412 */
413 413 Kernel.prototype._kernel_dead = function () {
414 414 this.stop_channels();
415 415 };
416 416
417 417 /**
418 418 * Start the `shell`and `iopub` channels.
419 419 * Will stop and restart them if they already exist.
420 420 *
421 421 * @function start_channels
422 422 */
423 423 Kernel.prototype.start_channels = function () {
424 424 var that = this;
425 425 this.stop_channels();
426 426 var ws_host_url = this.ws_url + this.kernel_url;
427 427
428 428 console.log("Starting WebSockets:", ws_host_url);
429 429
430 430 var channel_url = function(channel) {
431 431 return [
432 432 that.ws_url,
433 433 utils.url_join_encode(that.kernel_url, channel),
434 434 "?session_id=" + that.session_id
435 435 ].join('');
436 436 };
437 437 this.channels.shell = new this.WebSocket(channel_url("shell"));
438 438 this.channels.stdin = new this.WebSocket(channel_url("stdin"));
439 439 this.channels.iopub = new this.WebSocket(channel_url("iopub"));
440 440
441 441 var already_called_onclose = false; // only alert once
442 442 var ws_closed_early = function(evt){
443 443 if (already_called_onclose){
444 444 return;
445 445 }
446 446 already_called_onclose = true;
447 447 if ( ! evt.wasClean ){
448 448 // If the websocket was closed early, that could mean
449 449 // that the kernel is actually dead. Try getting
450 450 // information about the kernel from the API call --
451 451 // if that fails, then assume the kernel is dead,
452 452 // otherwise just follow the typical websocket closed
453 453 // protocol.
454 454 that.get_info(function () {
455 455 that._ws_closed(ws_host_url, false);
456 456 }, function () {
457 457 that.events.trigger('kernel_dead.Kernel', {kernel: that});
458 458 that._kernel_dead();
459 459 });
460 460 }
461 461 };
462 462 var ws_closed_late = function(evt){
463 463 if (already_called_onclose){
464 464 return;
465 465 }
466 466 already_called_onclose = true;
467 467 if ( ! evt.wasClean ){
468 468 that._ws_closed(ws_host_url, false);
469 469 }
470 470 };
471 471 var ws_error = function(evt){
472 472 if (already_called_onclose){
473 473 return;
474 474 }
475 475 already_called_onclose = true;
476 476 that._ws_closed(ws_host_url, true);
477 477 };
478 478
479 479 for (var c in this.channels) {
480 480 this.channels[c].onopen = $.proxy(this._ws_opened, this);
481 481 this.channels[c].onclose = ws_closed_early;
482 482 this.channels[c].onerror = ws_error;
483 483 }
484 484 // switch from early-close to late-close message after 1s
485 485 setTimeout(function() {
486 486 for (var c in that.channels) {
487 487 if (that.channels[c] !== null) {
488 488 that.channels[c].onclose = ws_closed_late;
489 489 }
490 490 }
491 491 }, 1000);
492 492 this.channels.shell.onmessage = $.proxy(this._handle_shell_reply, this);
493 493 this.channels.iopub.onmessage = $.proxy(this._handle_iopub_message, this);
494 494 this.channels.stdin.onmessage = $.proxy(this._handle_input_request, this);
495 495 };
496 496
497 497 /**
498 498 * Handle a websocket entering the open state,
499 499 * signaling that the kernel is connected when all channels are open.
500 500 *
501 501 * @function _ws_opened
502 502 */
503 503 Kernel.prototype._ws_opened = function (evt) {
504 504 if (this.is_connected()) {
505 505 // all events ready, trigger started event.
506 506 this._kernel_connected();
507 507 }
508 508 };
509 509
510 510 /**
511 511 * Handle a websocket entering the closed state. This closes the
512 512 * other communication channels if they are open. If the websocket
513 513 * was not closed due to an error, try to reconnect to the kernel.
514 514 *
515 515 * @function _ws_closed
516 516 * @param {string} ws_url - the websocket url
517 517 * @param {bool} error - whether the connection was closed due to an error
518 518 */
519 519 Kernel.prototype._ws_closed = function(ws_url, error) {
520 520 this.stop_channels();
521 521
522 522 this.events.trigger('kernel_disconnected.Kernel', {kernel: this});
523 523 if (error) {
524 524 console.log('WebSocket connection failed: ', ws_url);
525 525 this._reconnect_attempt = this._reconnect_attempt + 1;
526 526 this.events.trigger('kernel_connection_failed.Kernel', {kernel: this, ws_url: ws_url, attempt: this._reconnect_attempt});
527 527 }
528 528 this.reconnect();
529 529 };
530 530
531 531 /**
532 532 * Close the websocket channels. After successful close, the value
533 533 * in `this.channels[channel_name]` will be null.
534 534 *
535 535 * @function stop_channels
536 536 */
537 537 Kernel.prototype.stop_channels = function () {
538 538 var that = this;
539 539 var close = function (c) {
540 540 return function () {
541 541 if (that.channels[c] && that.channels[c].readyState === WebSocket.CLOSED) {
542 542 that.channels[c] = null;
543 543 }
544 544 };
545 545 };
546 546 for (var c in this.channels) {
547 547 if ( this.channels[c] !== null ) {
548 548 if (this.channels[c].readyState === WebSocket.OPEN) {
549 549 this.channels[c].onclose = close(c);
550 550 this.channels[c].close();
551 551 } else {
552 552 close(c)();
553 553 }
554 554 }
555 555 }
556 556 };
557 557
558 558 /**
559 559 * Check whether there is a connection to the kernel. This
560 560 * function only returns true if all channel objects have been
561 561 * created and have a state of WebSocket.OPEN.
562 562 *
563 563 * @function is_connected
564 564 * @returns {bool} - whether there is a connection
565 565 */
566 566 Kernel.prototype.is_connected = function () {
567 567 for (var c in this.channels) {
568 568 // if any channel is not ready, then we're not connected
569 569 if (this.channels[c] === null) {
570 570 return false;
571 571 }
572 572 if (this.channels[c].readyState !== WebSocket.OPEN) {
573 573 return false;
574 574 }
575 575 }
576 576 return true;
577 577 };
578 578
579 579 /**
580 580 * Check whether the connection to the kernel has been completely
581 581 * severed. This function only returns true if all channel objects
582 582 * are null.
583 583 *
584 584 * @function is_fully_disconnected
585 585 * @returns {bool} - whether the kernel is fully disconnected
586 586 */
587 587 Kernel.prototype.is_fully_disconnected = function () {
588 588 for (var c in this.channels) {
589 589 if (this.channels[c] === null) {
590 590 return true;
591 591 }
592 592 }
593 593 return false;
594 594 };
595 595
596 596 /**
597 597 * Send a message on the Kernel's shell channel
598 598 *
599 599 * @function send_shell_message
600 600 */
601 601 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata, buffers) {
602 602 if (!this.is_connected()) {
603 603 throw new Error("kernel is not connected");
604 604 }
605 605 var msg = this._get_msg(msg_type, content, metadata, buffers);
606 606 this.channels.shell.send(serialize.serialize(msg));
607 607 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
608 608 return msg.header.msg_id;
609 609 };
610 610
611 611 /**
612 612 * Get kernel info
613 613 *
614 614 * @function kernel_info
615 615 * @param callback {function}
616 616 *
617 617 * When calling this method, pass a callback function that expects one argument.
618 618 * The callback will be passed the complete `kernel_info_reply` message documented
619 619 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info)
620 620 */
621 621 Kernel.prototype.kernel_info = function (callback) {
622 622 var callbacks;
623 623 if (callback) {
624 624 callbacks = { shell : { reply : callback } };
625 625 }
626 626 return this.send_shell_message("kernel_info_request", {}, callbacks);
627 627 };
628 628
629 629 /**
630 630 * Get info on an object
631 631 *
632 632 * When calling this method, pass a callback function that expects one argument.
633 633 * The callback will be passed the complete `inspect_reply` message documented
634 634 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
635 635 *
636 636 * @function inspect
637 637 * @param code {string}
638 638 * @param cursor_pos {integer}
639 639 * @param callback {function}
640 640 */
641 641 Kernel.prototype.inspect = function (code, cursor_pos, callback) {
642 642 var callbacks;
643 643 if (callback) {
644 644 callbacks = { shell : { reply : callback } };
645 645 }
646 646
647 647 var content = {
648 648 code : code,
649 649 cursor_pos : cursor_pos,
650 650 detail_level : 0
651 651 };
652 652 return this.send_shell_message("inspect_request", content, callbacks);
653 653 };
654 654
655 655 /**
656 656 * Execute given code into kernel, and pass result to callback.
657 657 *
658 658 * @async
659 659 * @function execute
660 660 * @param {string} code
661 661 * @param [callbacks] {Object} With the following keys (all optional)
662 662 * @param callbacks.shell.reply {function}
663 663 * @param callbacks.shell.payload.[payload_name] {function}
664 664 * @param callbacks.iopub.output {function}
665 665 * @param callbacks.iopub.clear_output {function}
666 666 * @param callbacks.input {function}
667 667 * @param {object} [options]
668 668 * @param [options.silent=false] {Boolean}
669 669 * @param [options.user_expressions=empty_dict] {Dict}
670 670 * @param [options.allow_stdin=false] {Boolean} true|false
671 671 *
672 672 * @example
673 673 *
674 674 * The options object should contain the options for the execute
675 675 * call. Its default values are:
676 676 *
677 677 * options = {
678 678 * silent : true,
679 679 * user_expressions : {},
680 680 * allow_stdin : false
681 681 * }
682 682 *
683 683 * When calling this method pass a callbacks structure of the
684 684 * form:
685 685 *
686 686 * callbacks = {
687 687 * shell : {
688 688 * reply : execute_reply_callback,
689 689 * payload : {
690 690 * set_next_input : set_next_input_callback,
691 691 * }
692 692 * },
693 693 * iopub : {
694 694 * output : output_callback,
695 695 * clear_output : clear_output_callback,
696 696 * },
697 697 * input : raw_input_callback
698 698 * }
699 699 *
700 700 * Each callback will be passed the entire message as a single
701 701 * arugment. Payload handlers will be passed the corresponding
702 702 * payload and the execute_reply message.
703 703 */
704 704 Kernel.prototype.execute = function (code, callbacks, options) {
705 705 var content = {
706 706 code : code,
707 707 silent : true,
708 708 store_history : false,
709 709 user_expressions : {},
710 710 allow_stdin : false
711 711 };
712 712 callbacks = callbacks || {};
713 713 if (callbacks.input !== undefined) {
714 714 content.allow_stdin = true;
715 715 }
716 716 $.extend(true, content, options);
717 717 this.events.trigger('execution_request.Kernel', {kernel: this, content: content});
718 718 return this.send_shell_message("execute_request", content, callbacks);
719 719 };
720 720
721 721 /**
722 722 * When calling this method, pass a function to be called with the
723 723 * `complete_reply` message as its only argument when it arrives.
724 724 *
725 725 * `complete_reply` is documented
726 726 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
727 727 *
728 728 * @function complete
729 729 * @param code {string}
730 730 * @param cursor_pos {integer}
731 731 * @param callback {function}
732 732 */
733 733 Kernel.prototype.complete = function (code, cursor_pos, callback) {
734 734 var callbacks;
735 735 if (callback) {
736 736 callbacks = { shell : { reply : callback } };
737 737 }
738 738 var content = {
739 739 code : code,
740 740 cursor_pos : cursor_pos
741 741 };
742 742 return this.send_shell_message("complete_request", content, callbacks);
743 743 };
744 744
745 745 /**
746 746 * @function send_input_reply
747 747 */
748 748 Kernel.prototype.send_input_reply = function (input) {
749 749 if (!this.is_connected()) {
750 750 throw new Error("kernel is not connected");
751 751 }
752 752 var content = {
753 753 value : input
754 754 };
755 755 this.events.trigger('input_reply.Kernel', {kernel: this, content: content});
756 756 var msg = this._get_msg("input_reply", content);
757 757 this.channels.stdin.send(serialize.serialize(msg));
758 758 return msg.header.msg_id;
759 759 };
760 760
761 761 /**
762 762 * @function register_iopub_handler
763 763 */
764 764 Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
765 765 this._iopub_handlers[msg_type] = callback;
766 766 };
767 767
768 768 /**
769 769 * Get the iopub handler for a specific message type.
770 770 *
771 771 * @function get_iopub_handler
772 772 */
773 773 Kernel.prototype.get_iopub_handler = function (msg_type) {
774 774 return this._iopub_handlers[msg_type];
775 775 };
776 776
777 777 /**
778 778 * Get callbacks for a specific message.
779 779 *
780 780 * @function get_callbacks_for_msg
781 781 */
782 782 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
783 783 if (msg_id == this.last_msg_id) {
784 784 return this.last_msg_callbacks;
785 785 } else {
786 786 return this._msg_callbacks[msg_id];
787 787 }
788 788 };
789 789
790 790 /**
791 791 * Clear callbacks for a specific message.
792 792 *
793 793 * @function clear_callbacks_for_msg
794 794 */
795 795 Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
796 796 if (this._msg_callbacks[msg_id] !== undefined ) {
797 797 delete this._msg_callbacks[msg_id];
798 798 }
799 799 };
800 800
801 801 /**
802 802 * @function _finish_shell
803 803 */
804 804 Kernel.prototype._finish_shell = function (msg_id) {
805 805 var callbacks = this._msg_callbacks[msg_id];
806 806 if (callbacks !== undefined) {
807 807 callbacks.shell_done = true;
808 808 if (callbacks.iopub_done) {
809 809 this.clear_callbacks_for_msg(msg_id);
810 810 }
811 811 }
812 812 };
813 813
814 814 /**
815 815 * @function _finish_iopub
816 816 */
817 817 Kernel.prototype._finish_iopub = function (msg_id) {
818 818 var callbacks = this._msg_callbacks[msg_id];
819 819 if (callbacks !== undefined) {
820 820 callbacks.iopub_done = true;
821 821 if (callbacks.shell_done) {
822 822 this.clear_callbacks_for_msg(msg_id);
823 823 }
824 824 }
825 825 };
826 826
827 827 /**
828 828 * Set callbacks for a particular message.
829 829 * Callbacks should be a struct of the following form:
830 830 * shell : {
831 831 *
832 832 * }
833 833 *
834 834 * @function set_callbacks_for_msg
835 835 */
836 836 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
837 837 this.last_msg_id = msg_id;
838 838 if (callbacks) {
839 839 // shallow-copy mapping, because we will modify it at the top level
840 840 var cbcopy = this._msg_callbacks[msg_id] = this.last_msg_callbacks = {};
841 841 cbcopy.shell = callbacks.shell;
842 842 cbcopy.iopub = callbacks.iopub;
843 843 cbcopy.input = callbacks.input;
844 844 cbcopy.shell_done = (!callbacks.shell);
845 845 cbcopy.iopub_done = (!callbacks.iopub);
846 846 } else {
847 847 this.last_msg_callbacks = {};
848 848 }
849 849 };
850 850
851 851 /**
852 852 * @function _handle_shell_reply
853 853 */
854 854 Kernel.prototype._handle_shell_reply = function (e) {
855 855 serialize.deserialize(e.data, $.proxy(this._finish_shell_reply, this));
856 856 };
857 857
858 858 Kernel.prototype._finish_shell_reply = function (reply) {
859 859 this.events.trigger('shell_reply.Kernel', {kernel: this, reply:reply});
860 860 var content = reply.content;
861 861 var metadata = reply.metadata;
862 862 var parent_id = reply.parent_header.msg_id;
863 863 var callbacks = this.get_callbacks_for_msg(parent_id);
864 864 if (!callbacks || !callbacks.shell) {
865 865 return;
866 866 }
867 867 var shell_callbacks = callbacks.shell;
868 868
869 869 // signal that shell callbacks are done
870 870 this._finish_shell(parent_id);
871 871
872 872 if (shell_callbacks.reply !== undefined) {
873 873 shell_callbacks.reply(reply);
874 874 }
875 875 if (content.payload && shell_callbacks.payload) {
876 876 this._handle_payloads(content.payload, shell_callbacks.payload, reply);
877 877 }
878 878 };
879 879
880 880 /**
881 881 * @function _handle_payloads
882 882 */
883 883 Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
884 884 var l = payloads.length;
885 885 // Payloads are handled by triggering events because we don't want the Kernel
886 886 // to depend on the Notebook or Pager classes.
887 887 for (var i=0; i<l; i++) {
888 888 var payload = payloads[i];
889 889 var callback = payload_callbacks[payload.source];
890 890 if (callback) {
891 891 callback(payload, msg);
892 892 }
893 893 }
894 894 };
895 895
896 896 /**
897 897 * @function _handle_status_message
898 898 */
899 899 Kernel.prototype._handle_status_message = function (msg) {
900 900 var execution_state = msg.content.execution_state;
901 901 var parent_id = msg.parent_header.msg_id;
902 902
903 903 // dispatch status msg callbacks, if any
904 904 var callbacks = this.get_callbacks_for_msg(parent_id);
905 905 if (callbacks && callbacks.iopub && callbacks.iopub.status) {
906 906 try {
907 907 callbacks.iopub.status(msg);
908 908 } catch (e) {
909 909 console.log("Exception in status msg handler", e, e.stack);
910 910 }
911 911 }
912 912
913 913 if (execution_state === 'busy') {
914 914 this.events.trigger('kernel_busy.Kernel', {kernel: this});
915 915
916 916 } else if (execution_state === 'idle') {
917 917 // signal that iopub callbacks are (probably) done
918 918 // async output may still arrive,
919 919 // but only for the most recent request
920 920 this._finish_iopub(parent_id);
921 921
922 922 // trigger status_idle event
923 923 this.events.trigger('kernel_idle.Kernel', {kernel: this});
924 924
925 925 } else if (execution_state === 'starting') {
926 926 this.events.trigger('kernel_starting.Kernel', {kernel: this});
927 927 var that = this;
928 928 this.kernel_info(function () {
929 929 that.events.trigger('kernel_ready.Kernel', {kernel: that});
930 930 });
931 931
932 932 } else if (execution_state === 'restarting') {
933 933 // autorestarting is distinct from restarting,
934 934 // in that it means the kernel died and the server is restarting it.
935 935 // kernel_restarting sets the notification widget,
936 936 // autorestart shows the more prominent dialog.
937 937 this._autorestart_attempt = this._autorestart_attempt + 1;
938 938 this.events.trigger('kernel_restarting.Kernel', {kernel: this});
939 939 this.events.trigger('kernel_autorestarting.Kernel', {kernel: this, attempt: this._autorestart_attempt});
940 940
941 941 } else if (execution_state === 'dead') {
942 942 this.events.trigger('kernel_dead.Kernel', {kernel: this});
943 943 this._kernel_dead();
944 944 }
945 945 };
946 946
947 947 /**
948 948 * Handle clear_output message
949 949 *
950 950 * @function _handle_clear_output
951 951 */
952 952 Kernel.prototype._handle_clear_output = function (msg) {
953 953 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
954 954 if (!callbacks || !callbacks.iopub) {
955 955 return;
956 956 }
957 957 var callback = callbacks.iopub.clear_output;
958 958 if (callback) {
959 959 callback(msg);
960 960 }
961 961 };
962 962
963 963 /**
964 964 * handle an output message (execute_result, display_data, etc.)
965 965 *
966 966 * @function _handle_output_message
967 967 */
968 968 Kernel.prototype._handle_output_message = function (msg) {
969 969 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
970 970 if (!callbacks || !callbacks.iopub) {
971 971 return;
972 972 }
973 973 var callback = callbacks.iopub.output;
974 974 if (callback) {
975 975 callback(msg);
976 976 }
977 977 };
978 978
979 979 /**
980 980 * Dispatch IOPub messages to respective handlers. Each message
981 981 * type should have a handler.
982 982 *
983 983 * @function _handle_iopub_message
984 984 */
985 985 Kernel.prototype._handle_iopub_message = function (e) {
986 986 serialize.deserialize(e.data, $.proxy(this._finish_iopub_message, this));
987 987 };
988 988
989 989
990 990 Kernel.prototype._finish_iopub_message = function (msg) {
991 991 var handler = this.get_iopub_handler(msg.header.msg_type);
992 992 if (handler !== undefined) {
993 993 handler(msg);
994 994 }
995 995 };
996 996
997 997 /**
998 998 * @function _handle_input_request
999 999 */
1000 1000 Kernel.prototype._handle_input_request = function (e) {
1001 1001 serialize.deserialize(e.data, $.proxy(this._finish_input_request, this));
1002 1002 };
1003 1003
1004 1004
1005 1005 Kernel.prototype._finish_input_request = function (request) {
1006 1006 var header = request.header;
1007 1007 var content = request.content;
1008 1008 var metadata = request.metadata;
1009 1009 var msg_type = header.msg_type;
1010 1010 if (msg_type !== 'input_request') {
1011 1011 console.log("Invalid input request!", request);
1012 1012 return;
1013 1013 }
1014 1014 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
1015 1015 if (callbacks) {
1016 1016 if (callbacks.input) {
1017 1017 callbacks.input(request);
1018 1018 }
1019 1019 }
1020 1020 };
1021 1021
1022 1022 // Backwards compatability.
1023 1023 IPython.Kernel = Kernel;
1024 1024
1025 1025 return {'Kernel': Kernel};
1026 1026 });
@@ -1,128 +1,111 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'jquery',
6 'components/utf8/utf8'
7 6 ], function ($, utf8) {
8 7 "use strict";
9 8
10 9 var _deserialize_array_buffer = function (buf) {
11 10 var data = new DataView(buf);
12 11 // read the header: 1 + nbufs 32b integers
13 12 var nbufs = data.getInt32(0);
14 13 var offsets = [];
15 14 var i;
16 15 for (i = 1; i <= nbufs; i++) {
17 16 offsets.push(data.getInt32(i * 4));
18 17 }
19 // have to convert array to string for utf8.js
20 var bytestring = String.fromCharCode.apply(null,
21 new Uint8Array(buf.slice(offsets[0], offsets[1]))
22 );
18 var json_bytes = new Uint8Array(buf.slice(offsets[0], offsets[1]));
23 19 var msg = $.parseJSON(
24 utf8.decode(
25 bytestring
26 )
20 (new TextDecoder('utf8')).decode(json_bytes)
27 21 );
28 22 // the remaining chunks are stored as DataViews in msg.buffers
29 23 msg.buffers = [];
30 24 var start, stop;
31 25 for (i = 1; i < nbufs; i++) {
32 26 start = offsets[i];
33 27 stop = offsets[i+1] || buf.byteLength;
34 28 msg.buffers.push(new DataView(buf.slice(start, stop)));
35 29 }
36 30 return msg;
37 31 };
38 32
39 33 var _deserialize_binary = function(data, callback) {
40 34 // deserialize the binary message format
41 35 // callback will be called with a message whose buffers attribute
42 36 // will be an array of DataViews.
43 37 if (data instanceof Blob) {
44 38 // data is Blob, have to deserialize from ArrayBuffer in reader callback
45 39 var reader = new FileReader();
46 40 reader.onload = function () {
47 41 var msg = _deserialize_array_buffer(this.result);
48 42 callback(msg);
49 43 };
50 44 reader.readAsArrayBuffer(data);
51 45 } else {
52 46 // data is ArrayBuffer, can deserialize directly
53 47 var msg = _deserialize_array_buffer(data);
54 48 callback(msg);
55 49 }
56 50 };
57 51
58 52 var deserialize = function (data, callback) {
59 53 // deserialize a message and pass the unpacked message object to callback
60 54 if (typeof data === "string") {
61 55 // text JSON message
62 56 callback($.parseJSON(data));
63 57 } else {
64 58 // binary message
65 59 _deserialize_binary(data, callback);
66 60 }
67 61 };
68 62
69 var _bytes2buf = function (bytestring) {
70 // convert bytestring to UInt8Array
71 var nbytes = bytestring.length;
72 var buf = new Uint8Array(nbytes);
73 for (var i = 0; i < nbytes; i++) {
74 buf[i] = bytestring.charCodeAt(i);
75 }
76 return buf;
77 };
78
79 63 var _serialize_binary = function (msg) {
80 64 // implement the binary serialization protocol
81 65 // serializes JSON message to ArrayBuffer
82 66 msg = $.extend({}, msg);
83 67 var offsets = [];
84 68 var buffers = msg.buffers;
85 69 delete msg.buffers;
86 var json_utf8 = _bytes2buf(utf8.encode(JSON.stringify(msg)));
70 var json_utf8 = (new TextEncoder('utf8')).encode(JSON.stringify(msg));
87 71 buffers.unshift(json_utf8);
88 72 var nbufs = buffers.length;
89 73 offsets.push(4 * (nbufs + 1));
90 74 var i;
91 75 for (i = 0; i + 1 < buffers.length; i++) {
92 76 offsets.push(offsets[offsets.length-1] + buffers[i].byteLength);
93 77 }
94 78 var msg_buf = new Uint8Array(
95 79 offsets[offsets.length-1] + buffers[buffers.length-1].byteLength
96 80 );
97 81 // use DataView.setInt32 for network byte-order
98 82 var view = new DataView(msg_buf.buffer);
99 83 // write nbufs to first 4 bytes
100 84 view.setInt32(0, nbufs);
101 85 // write offsets to next 4 * nbufs bytes
102 86 for (i = 0; i < offsets.length; i++) {
103 87 view.setInt32(4 * (i+1), offsets[i]);
104 88 }
105 89 // write all the buffers at their respective offsets
106 90 for (i = 0; i < buffers.length; i++) {
107 91 msg_buf.set(new Uint8Array(buffers[i].buffer), offsets[i]);
108 92 }
109 93
110 94 // return raw ArrayBuffer
111 95 return msg_buf.buffer;
112 96 };
113 97
114 98 var serialize = function (msg) {
115 console.log(msg.buffers, msg.buffers.length);
116 99 if (msg.buffers && msg.buffers.length) {
117 100 return _serialize_binary(msg);
118 101 } else {
119 102 return JSON.stringify(msg);
120 103 }
121 104 };
122 105
123 106 var exports = {
124 107 deserialize : deserialize,
125 108 serialize: serialize
126 109 };
127 110 return exports;
128 111 }); No newline at end of file
@@ -1,317 +1,318 b''
1 1 {% extends "page.html" %}
2 2
3 3 {% block stylesheet %}
4 4
5 5 {% if mathjax_url %}
6 6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
7 7 {% endif %}
8 8 <script type="text/javascript">
9 9 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 10 // where it will be undefined, and should prompt a dialog later.
11 11 window.mathjax_url = "{{mathjax_url}}";
12 12 </script>
13 13
14 14 <link rel="stylesheet" href="{{ static_url("components/bootstrap-tour/build/css/bootstrap-tour.min.css") }}" type="text/css" />
15 15 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
16 16
17 17 {{super()}}
18 18
19 19 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
20 20
21 21 {% endblock %}
22 22
23 23 {% block params %}
24 24
25 25 data-project="{{project}}"
26 26 data-base-url="{{base_url}}"
27 27 data-ws-url="{{ws_url}}"
28 28 data-notebook-name="{{notebook_name}}"
29 29 data-notebook-path="{{notebook_path}}"
30 30 class="notebook_app"
31 31
32 32 {% endblock %}
33 33
34 34
35 35 {% block header %}
36 36
37 37
38 38 <span id="save_widget" class="nav pull-left">
39 39 <span id="notebook_name"></span>
40 40 <span id="checkpoint_status"></span>
41 41 <span id="autosave_status"></span>
42 42 </span>
43 43
44 44 <span id="kernel_selector_widget" class="pull-right dropdown">
45 45 <button class="dropdown-toggle" data-toggle="dropdown" type='button' id="current_kernel_spec">
46 46 <span class='kernel_name'>Python</span>
47 47 <span class="caret"></span>
48 48 </button>
49 49 <ul id="kernel_selector" class="dropdown-menu">
50 50 </ul>
51 51 </span>
52 52
53 53 {% endblock %}
54 54
55 55
56 56 {% block site %}
57 57
58 58 <div id="menubar-container" class="container">
59 59 <div id="menubar">
60 60 <div id="menus" class="navbar navbar-default" role="navigation">
61 61 <div class="container-fluid">
62 62 <ul class="nav navbar-nav">
63 63 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
64 64 <ul id="file_menu" class="dropdown-menu">
65 65 <li id="new_notebook"
66 66 title="Make a new notebook (Opens a new window)">
67 67 <a href="#">New</a></li>
68 68 <li id="open_notebook"
69 69 title="Opens a new window with the Dashboard view">
70 70 <a href="#">Open...</a></li>
71 71 <!-- <hr/> -->
72 72 <li class="divider"></li>
73 73 <li id="copy_notebook"
74 74 title="Open a copy of this notebook's contents and start a new kernel">
75 75 <a href="#">Make a Copy...</a></li>
76 76 <li id="rename_notebook"><a href="#">Rename...</a></li>
77 77 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
78 78 <!-- <hr/> -->
79 79 <li class="divider"></li>
80 80 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
81 81 <ul class="dropdown-menu">
82 82 <li><a href="#"></a></li>
83 83 <li><a href="#"></a></li>
84 84 <li><a href="#"></a></li>
85 85 <li><a href="#"></a></li>
86 86 <li><a href="#"></a></li>
87 87 </ul>
88 88 </li>
89 89 <li class="divider"></li>
90 90 <li id="print_preview"><a href="#">Print Preview</a></li>
91 91 <li class="dropdown-submenu"><a href="#">Download as</a>
92 92 <ul class="dropdown-menu">
93 93 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
94 94 <li id="download_py"><a href="#">Python (.py)</a></li>
95 95 <li id="download_html"><a href="#">HTML (.html)</a></li>
96 96 <li id="download_rst"><a href="#">reST (.rst)</a></li>
97 97 <li id="download_pdf"><a href="#">PDF (.pdf)</a></li>
98 98 </ul>
99 99 </li>
100 100 <li class="divider"></li>
101 101 <li id="trust_notebook"
102 102 title="Trust the output of this notebook">
103 103 <a href="#" >Trust Notebook</a></li>
104 104 <li class="divider"></li>
105 105 <li id="kill_and_exit"
106 106 title="Shutdown this notebook's kernel, and close this window">
107 107 <a href="#" >Close and halt</a></li>
108 108 </ul>
109 109 </li>
110 110 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
111 111 <ul id="edit_menu" class="dropdown-menu">
112 112 <li id="cut_cell"><a href="#">Cut Cell</a></li>
113 113 <li id="copy_cell"><a href="#">Copy Cell</a></li>
114 114 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
115 115 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
116 116 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
117 117 <li id="delete_cell"><a href="#">Delete Cell</a></li>
118 118 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
119 119 <li class="divider"></li>
120 120 <li id="split_cell"><a href="#">Split Cell</a></li>
121 121 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
122 122 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
123 123 <li class="divider"></li>
124 124 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
125 125 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
126 126 <li class="divider"></li>
127 127 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
128 128 </ul>
129 129 </li>
130 130 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
131 131 <ul id="view_menu" class="dropdown-menu">
132 132 <li id="toggle_header"
133 133 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
134 134 <a href="#">Toggle Header</a></li>
135 135 <li id="toggle_toolbar"
136 136 title="Show/Hide the action icons (below menu bar)">
137 137 <a href="#">Toggle Toolbar</a></li>
138 138 </ul>
139 139 </li>
140 140 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
141 141 <ul id="insert_menu" class="dropdown-menu">
142 142 <li id="insert_cell_above"
143 143 title="Insert an empty Code cell above the currently active cell">
144 144 <a href="#">Insert Cell Above</a></li>
145 145 <li id="insert_cell_below"
146 146 title="Insert an empty Code cell below the currently active cell">
147 147 <a href="#">Insert Cell Below</a></li>
148 148 </ul>
149 149 </li>
150 150 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
151 151 <ul id="cell_menu" class="dropdown-menu">
152 152 <li id="run_cell" title="Run this cell, and move cursor to the next one">
153 153 <a href="#">Run</a></li>
154 154 <li id="run_cell_select_below" title="Run this cell, select below">
155 155 <a href="#">Run and Select Below</a></li>
156 156 <li id="run_cell_insert_below" title="Run this cell, insert below">
157 157 <a href="#">Run and Insert Below</a></li>
158 158 <li id="run_all_cells" title="Run all cells in the notebook">
159 159 <a href="#">Run All</a></li>
160 160 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
161 161 <a href="#">Run All Above</a></li>
162 162 <li id="run_all_cells_below" title="Run this cell and all cells below it">
163 163 <a href="#">Run All Below</a></li>
164 164 <li class="divider"></li>
165 165 <li id="change_cell_type" class="dropdown-submenu"
166 166 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
167 167 <a href="#">Cell Type</a>
168 168 <ul class="dropdown-menu">
169 169 <li id="to_code"
170 170 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
171 171 <a href="#">Code</a></li>
172 172 <li id="to_markdown"
173 173 title="Contents will be rendered as HTML and serve as explanatory text">
174 174 <a href="#">Markdown</a></li>
175 175 <li id="to_raw"
176 176 title="Contents will pass through nbconvert unmodified">
177 177 <a href="#">Raw NBConvert</a></li>
178 178 <li id="to_heading1"><a href="#">Heading 1</a></li>
179 179 <li id="to_heading2"><a href="#">Heading 2</a></li>
180 180 <li id="to_heading3"><a href="#">Heading 3</a></li>
181 181 <li id="to_heading4"><a href="#">Heading 4</a></li>
182 182 <li id="to_heading5"><a href="#">Heading 5</a></li>
183 183 <li id="to_heading6"><a href="#">Heading 6</a></li>
184 184 </ul>
185 185 </li>
186 186 <li class="divider"></li>
187 187 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
188 188 <ul class="dropdown-menu">
189 189 <li id="toggle_current_output"
190 190 title="Hide/Show the output of the current cell">
191 191 <a href="#">Toggle</a>
192 192 </li>
193 193 <li id="toggle_current_output_scroll"
194 194 title="Scroll the output of the current cell">
195 195 <a href="#">Toggle Scrolling</a>
196 196 </li>
197 197 <li id="clear_current_output"
198 198 title="Clear the output of the current cell">
199 199 <a href="#">Clear</a>
200 200 </li>
201 201 </ul>
202 202 </li>
203 203 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
204 204 <ul class="dropdown-menu">
205 205 <li id="toggle_all_output"
206 206 title="Hide/Show the output of all cells">
207 207 <a href="#">Toggle</a>
208 208 </li>
209 209 <li id="toggle_all_output_scroll"
210 210 title="Scroll the output of all cells">
211 211 <a href="#">Toggle Scrolling</a>
212 212 </li>
213 213 <li id="clear_all_output"
214 214 title="Clear the output of all cells">
215 215 <a href="#">Clear</a>
216 216 </li>
217 217 </ul>
218 218 </li>
219 219 </ul>
220 220 </li>
221 221 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
222 222 <ul id="kernel_menu" class="dropdown-menu">
223 223 <li id="int_kernel"
224 224 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
225 225 <a href="#">Interrupt</a></li>
226 226 <li id="restart_kernel"
227 227 title="Restart the Kernel">
228 228 <a href="#">Restart</a></li>
229 229 <li class="divider"></li>
230 230 <li id="menu-change-kernel" class="dropdown-submenu">
231 231 <a href="#">Change kernel</a>
232 232 <ul class="dropdown-menu" id="menu-change-kernel-submenu"></ul>
233 233 </li>
234 234 </ul>
235 235 </li>
236 236 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
237 237 <ul id="help_menu" class="dropdown-menu">
238 238 <li id="notebook_tour" title="A quick tour of the notebook user interface"><a href="#">User Interface Tour</a></li>
239 239 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
240 240 <li class="divider"></li>
241 241 {% set
242 242 sections = (
243 243 (
244 244 ("http://ipython.org/documentation.html","IPython Help",True),
245 245 ("http://nbviewer.ipython.org/github/ipython/ipython/tree/2.x/examples/Index.ipynb", "Notebook Help", True),
246 246 ),(
247 247 ("http://docs.python.org","Python",True),
248 248 ("http://help.github.com/articles/github-flavored-markdown","Markdown",True),
249 249 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
250 250 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
251 251 ("http://matplotlib.org/contents.html","Matplotlib",True),
252 252 ("http://docs.sympy.org/latest/index.html","SymPy",True),
253 253 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
254 254 )
255 255 )
256 256 %}
257 257
258 258 {% for helplinks in sections %}
259 259 {% for link in helplinks %}
260 260 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
261 261 {{'<i class="fa fa-external-link menu-icon pull-right"></i>' if link[2]}}
262 262 {{link[1]}}
263 263 </a></li>
264 264 {% endfor %}
265 265 {% if not loop.last %}
266 266 <li class="divider"></li>
267 267 {% endif %}
268 268 {% endfor %}
269 269 </li>
270 270 </ul>
271 271 </li>
272 272 </ul>
273 273 <ul class="nav navbar-nav navbar-right">
274 274 <li id="kernel_indicator">
275 275 <i id="kernel_indicator_icon"></i>
276 276 </li>
277 277 <li id="modal_indicator">
278 278 <i id="modal_indicator_icon"></i>
279 279 </li>
280 280 <li id="notification_area"></li>
281 281 </ul>
282 282 </div>
283 283 </div>
284 284 </div>
285 285 <div id="maintoolbar" class="navbar">
286 286 <div class="toolbar-inner navbar-inner navbar-nobg">
287 287 <div id="maintoolbar-container" class="container"></div>
288 288 </div>
289 289 </div>
290 290 </div>
291 291
292 292 <div id="ipython-main-app">
293 293
294 294 <div id="notebook_panel">
295 295 <div id="notebook"></div>
296 296 <div id="pager_splitter"></div>
297 297 <div id="pager">
298 298 <div id='pager_button_area'>
299 299 </div>
300 300 <div id="pager-container" class="container"></div>
301 301 </div>
302 302 </div>
303 303
304 304 </div>
305 305 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
306 306
307 307
308 308 {% endblock %}
309 309
310 310
311 311 {% block script %}
312 312 {{super()}}
313 313
314 <script src="{{ static_url("components/text-encoding/lib/encoding.js") }}" charset="utf-8"></script>
314 315
315 316 <script src="{{ static_url("notebook/js/main.js") }}" charset="utf-8"></script>
316 317
317 318 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now