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