##// END OF EJS Templates
Add event to kernel execution/shell reply....
Matthias BUSSONNIER -
Show More
@@ -1,391 +1,393 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Kernel
9 // Kernel
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15
15
16 // Initialization and connection.
16 // Initialization and connection.
17
17
18 var Kernel = function (base_url) {
18 var Kernel = function (base_url) {
19 this.kernel_id = null;
19 this.kernel_id = null;
20 this.shell_channel = null;
20 this.shell_channel = null;
21 this.iopub_channel = null;
21 this.iopub_channel = null;
22 this.base_url = base_url;
22 this.base_url = base_url;
23 this.running = false;
23 this.running = false;
24 this.username = "username";
24 this.username = "username";
25 this.session_id = utils.uuid();
25 this.session_id = utils.uuid();
26 this._msg_callbacks = {};
26 this._msg_callbacks = {};
27
27
28 if (typeof(WebSocket) !== 'undefined') {
28 if (typeof(WebSocket) !== 'undefined') {
29 this.WebSocket = WebSocket;
29 this.WebSocket = WebSocket;
30 } else if (typeof(MozWebSocket) !== 'undefined') {
30 } else if (typeof(MozWebSocket) !== 'undefined') {
31 this.WebSocket = MozWebSocket;
31 this.WebSocket = MozWebSocket;
32 } else {
32 } else {
33 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.');
33 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.');
34 };
34 };
35 };
35 };
36
36
37
37
38 Kernel.prototype._get_msg = function (msg_type, content) {
38 Kernel.prototype._get_msg = function (msg_type, content) {
39 var msg = {
39 var msg = {
40 header : {
40 header : {
41 msg_id : utils.uuid(),
41 msg_id : utils.uuid(),
42 username : this.username,
42 username : this.username,
43 session : this.session_id,
43 session : this.session_id,
44 msg_type : msg_type
44 msg_type : msg_type
45 },
45 },
46 metadata : {},
46 metadata : {},
47 content : content,
47 content : content,
48 parent_header : {}
48 parent_header : {}
49 };
49 };
50 return msg;
50 return msg;
51 };
51 };
52
52
53 Kernel.prototype.start = function (notebook_id) {
53 Kernel.prototype.start = function (notebook_id) {
54 var that = this;
54 var that = this;
55 if (!this.running) {
55 if (!this.running) {
56 var qs = $.param({notebook:notebook_id});
56 var qs = $.param({notebook:notebook_id});
57 var url = this.base_url + '?' + qs;
57 var url = this.base_url + '?' + qs;
58 $.post(url,
58 $.post(url,
59 $.proxy(that._kernel_started,that),
59 $.proxy(that._kernel_started,that),
60 'json'
60 'json'
61 );
61 );
62 };
62 };
63 };
63 };
64
64
65
65
66 Kernel.prototype.restart = function () {
66 Kernel.prototype.restart = function () {
67 $([IPython.events]).trigger({type: 'status_restarting.Kernel', kernel: this});
67 $([IPython.events]).trigger({type: 'status_restarting.Kernel', kernel: this});
68 var that = this;
68 var that = this;
69 if (this.running) {
69 if (this.running) {
70 this.stop_channels();
70 this.stop_channels();
71 var url = this.kernel_url + "/restart";
71 var url = this.kernel_url + "/restart";
72 $.post(url,
72 $.post(url,
73 $.proxy(that._kernel_started, that),
73 $.proxy(that._kernel_started, that),
74 'json'
74 'json'
75 );
75 );
76 };
76 };
77 };
77 };
78
78
79
79
80 Kernel.prototype._kernel_started = function (json) {
80 Kernel.prototype._kernel_started = function (json) {
81 console.log("Kernel started: ", json.kernel_id);
81 console.log("Kernel started: ", json.kernel_id);
82 this.running = true;
82 this.running = true;
83 this.kernel_id = json.kernel_id;
83 this.kernel_id = json.kernel_id;
84 this.ws_url = json.ws_url;
84 this.ws_url = json.ws_url;
85 this.kernel_url = this.base_url + "/" + this.kernel_id;
85 this.kernel_url = this.base_url + "/" + this.kernel_id;
86 this.start_channels();
86 this.start_channels();
87 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this);
87 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this);
88 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this);
88 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this);
89 };
89 };
90
90
91
91
92 Kernel.prototype._websocket_closed = function(ws_url, early){
92 Kernel.prototype._websocket_closed = function(ws_url, early){
93 var msg;
93 var msg;
94 var parent_item = $('body');
94 var parent_item = $('body');
95 if (early) {
95 if (early) {
96 msg = "Websocket connection to " + ws_url + " could not be established." +
96 msg = "Websocket connection to " + ws_url + " could not be established." +
97 " You will NOT be able to run code." +
97 " You will NOT be able to run code." +
98 " Your browser may not be compatible with the websocket version in the server," +
98 " Your browser may not be compatible with the websocket version in the server," +
99 " or if the url does not look right, there could be an error in the" +
99 " or if the url does not look right, there could be an error in the" +
100 " server's configuration.";
100 " server's configuration.";
101 } else {
101 } else {
102 IPython.notification_area.widget('kernel').set_message('Reconnecting Websockets', 1000);
102 IPython.notification_area.widget('kernel').set_message('Reconnecting Websockets', 1000);
103 this.start_channels();
103 this.start_channels();
104 return;
104 return;
105 }
105 }
106 var dialog = $('<div/>');
106 var dialog = $('<div/>');
107 dialog.html(msg);
107 dialog.html(msg);
108 parent_item.append(dialog);
108 parent_item.append(dialog);
109 dialog.dialog({
109 dialog.dialog({
110 resizable: false,
110 resizable: false,
111 modal: true,
111 modal: true,
112 title: "Websocket closed",
112 title: "Websocket closed",
113 closeText: "",
113 closeText: "",
114 close: function(event, ui) {$(this).dialog('destroy').remove();},
114 close: function(event, ui) {$(this).dialog('destroy').remove();},
115 buttons : {
115 buttons : {
116 "OK": function () {
116 "OK": function () {
117 $(this).dialog('close');
117 $(this).dialog('close');
118 }
118 }
119 }
119 }
120 });
120 });
121
121
122 };
122 };
123
123
124 Kernel.prototype.start_channels = function () {
124 Kernel.prototype.start_channels = function () {
125 var that = this;
125 var that = this;
126 this.stop_channels();
126 this.stop_channels();
127 var ws_url = this.ws_url + this.kernel_url;
127 var ws_url = this.ws_url + this.kernel_url;
128 console.log("Starting WS:", ws_url);
128 console.log("Starting WS:", ws_url);
129 this.shell_channel = new this.WebSocket(ws_url + "/shell");
129 this.shell_channel = new this.WebSocket(ws_url + "/shell");
130 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
130 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
131 send_cookie = function(){
131 send_cookie = function(){
132 this.send(document.cookie);
132 this.send(document.cookie);
133 };
133 };
134 var already_called_onclose = false; // only alert once
134 var already_called_onclose = false; // only alert once
135 ws_closed_early = function(evt){
135 ws_closed_early = function(evt){
136 if (already_called_onclose){
136 if (already_called_onclose){
137 return;
137 return;
138 }
138 }
139 already_called_onclose = true;
139 already_called_onclose = true;
140 if ( ! evt.wasClean ){
140 if ( ! evt.wasClean ){
141 that._websocket_closed(ws_url, true);
141 that._websocket_closed(ws_url, true);
142 }
142 }
143 };
143 };
144 ws_closed_late = function(evt){
144 ws_closed_late = function(evt){
145 if (already_called_onclose){
145 if (already_called_onclose){
146 return;
146 return;
147 }
147 }
148 already_called_onclose = true;
148 already_called_onclose = true;
149 if ( ! evt.wasClean ){
149 if ( ! evt.wasClean ){
150 that._websocket_closed(ws_url, false);
150 that._websocket_closed(ws_url, false);
151 }
151 }
152 };
152 };
153 this.shell_channel.onopen = send_cookie;
153 this.shell_channel.onopen = send_cookie;
154 this.shell_channel.onclose = ws_closed_early;
154 this.shell_channel.onclose = ws_closed_early;
155 this.iopub_channel.onopen = send_cookie;
155 this.iopub_channel.onopen = send_cookie;
156 this.iopub_channel.onclose = ws_closed_early;
156 this.iopub_channel.onclose = ws_closed_early;
157 // switch from early-close to late-close message after 1s
157 // switch from early-close to late-close message after 1s
158 setTimeout(function(){
158 setTimeout(function(){
159 that.shell_channel.onclose = ws_closed_late;
159 that.shell_channel.onclose = ws_closed_late;
160 that.iopub_channel.onclose = ws_closed_late;
160 that.iopub_channel.onclose = ws_closed_late;
161 }, 1000);
161 }, 1000);
162 };
162 };
163
163
164
164
165 Kernel.prototype.stop_channels = function () {
165 Kernel.prototype.stop_channels = function () {
166 if (this.shell_channel !== null) {
166 if (this.shell_channel !== null) {
167 this.shell_channel.onclose = function (evt) {};
167 this.shell_channel.onclose = function (evt) {};
168 this.shell_channel.close();
168 this.shell_channel.close();
169 this.shell_channel = null;
169 this.shell_channel = null;
170 };
170 };
171 if (this.iopub_channel !== null) {
171 if (this.iopub_channel !== null) {
172 this.iopub_channel.onclose = function (evt) {};
172 this.iopub_channel.onclose = function (evt) {};
173 this.iopub_channel.close();
173 this.iopub_channel.close();
174 this.iopub_channel = null;
174 this.iopub_channel = null;
175 };
175 };
176 };
176 };
177
177
178 // Main public methods.
178 // Main public methods.
179
179
180 Kernel.prototype.object_info_request = function (objname, callbacks) {
180 Kernel.prototype.object_info_request = function (objname, callbacks) {
181 // When calling this method pass a callbacks structure of the form:
181 // When calling this method pass a callbacks structure of the form:
182 //
182 //
183 // callbacks = {
183 // callbacks = {
184 // 'object_info_reply': object_into_reply_callback
184 // 'object_info_reply': object_into_reply_callback
185 // }
185 // }
186 //
186 //
187 // The object_info_reply_callback will be passed the content object of the
187 // The object_info_reply_callback will be passed the content object of the
188 // object_into_reply message documented here:
188 // object_into_reply message documented here:
189 //
189 //
190 // http://ipython.org/ipython-doc/dev/development/messaging.html#object-information
190 // http://ipython.org/ipython-doc/dev/development/messaging.html#object-information
191 if(typeof(objname)!=null && objname!=null)
191 if(typeof(objname)!=null && objname!=null)
192 {
192 {
193 var content = {
193 var content = {
194 oname : objname.toString(),
194 oname : objname.toString(),
195 };
195 };
196 var msg = this._get_msg("object_info_request", content);
196 var msg = this._get_msg("object_info_request", content);
197 this.shell_channel.send(JSON.stringify(msg));
197 this.shell_channel.send(JSON.stringify(msg));
198 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
198 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
199 return msg.header.msg_id;
199 return msg.header.msg_id;
200 }
200 }
201 return;
201 return;
202 }
202 }
203
203
204 Kernel.prototype.execute = function (code, callbacks, options) {
204 Kernel.prototype.execute = function (code, callbacks, options) {
205 // The options object should contain the options for the execute call. Its default
205 // The options object should contain the options for the execute call. Its default
206 // values are:
206 // values are:
207 //
207 //
208 // options = {
208 // options = {
209 // silent : true,
209 // silent : true,
210 // user_variables : [],
210 // user_variables : [],
211 // user_expressions : {},
211 // user_expressions : {},
212 // allow_stdin : false
212 // allow_stdin : false
213 // }
213 // }
214 //
214 //
215 // When calling this method pass a callbacks structure of the form:
215 // When calling this method pass a callbacks structure of the form:
216 //
216 //
217 // callbacks = {
217 // callbacks = {
218 // 'execute_reply': execute_reply_callback,
218 // 'execute_reply': execute_reply_callback,
219 // 'output': output_callback,
219 // 'output': output_callback,
220 // 'clear_output': clear_output_callback,
220 // 'clear_output': clear_output_callback,
221 // 'set_next_input': set_next_input_callback
221 // 'set_next_input': set_next_input_callback
222 // }
222 // }
223 //
223 //
224 // The execute_reply_callback will be passed the content and metadata objects of the execute_reply
224 // The execute_reply_callback will be passed the content and metadata objects of the execute_reply
225 // message documented here:
225 // message documented here:
226 //
226 //
227 // http://ipython.org/ipython-doc/dev/development/messaging.html#execute
227 // http://ipython.org/ipython-doc/dev/development/messaging.html#execute
228 //
228 //
229 // The output_callback will be passed msg_type ('stream','display_data','pyout','pyerr')
229 // The output_callback will be passed msg_type ('stream','display_data','pyout','pyerr')
230 // of the output and the content and metadata objects of the PUB/SUB channel that contains the
230 // of the output and the content and metadata objects of the PUB/SUB channel that contains the
231 // output:
231 // output:
232 //
232 //
233 // http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket
233 // http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket
234 //
234 //
235 // The clear_output_callback will be passed a content object that contains
235 // The clear_output_callback will be passed a content object that contains
236 // stdout, stderr and other fields that are booleans, as well as the metadata object.
236 // stdout, stderr and other fields that are booleans, as well as the metadata object.
237 //
237 //
238 // The set_next_input_callback will be passed the text that should become the next
238 // The set_next_input_callback will be passed the text that should become the next
239 // input cell.
239 // input cell.
240
240
241 var content = {
241 var content = {
242 code : code,
242 code : code,
243 silent : true,
243 silent : true,
244 user_variables : [],
244 user_variables : [],
245 user_expressions : {},
245 user_expressions : {},
246 allow_stdin : false
246 allow_stdin : false
247 };
247 };
248 $.extend(true, content, options)
248 $.extend(true, content, options)
249 $([IPython.events]).trigger({type: 'Kernel.execution_request', kernel: this, content:content});
249 var msg = this._get_msg("execute_request", content);
250 var msg = this._get_msg("execute_request", content);
250 this.shell_channel.send(JSON.stringify(msg));
251 this.shell_channel.send(JSON.stringify(msg));
251 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
252 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
252 return msg.header.msg_id;
253 return msg.header.msg_id;
253 };
254 };
254
255
255
256
256 Kernel.prototype.complete = function (line, cursor_pos, callbacks) {
257 Kernel.prototype.complete = function (line, cursor_pos, callbacks) {
257 // When calling this method pass a callbacks structure of the form:
258 // When calling this method pass a callbacks structure of the form:
258 //
259 //
259 // callbacks = {
260 // callbacks = {
260 // 'complete_reply': complete_reply_callback
261 // 'complete_reply': complete_reply_callback
261 // }
262 // }
262 //
263 //
263 // The complete_reply_callback will be passed the content object of the
264 // The complete_reply_callback will be passed the content object of the
264 // complete_reply message documented here:
265 // complete_reply message documented here:
265 //
266 //
266 // http://ipython.org/ipython-doc/dev/development/messaging.html#complete
267 // http://ipython.org/ipython-doc/dev/development/messaging.html#complete
267 callbacks = callbacks || {};
268 callbacks = callbacks || {};
268 var content = {
269 var content = {
269 text : '',
270 text : '',
270 line : line,
271 line : line,
271 cursor_pos : cursor_pos
272 cursor_pos : cursor_pos
272 };
273 };
273 var msg = this._get_msg("complete_request", content);
274 var msg = this._get_msg("complete_request", content);
274 this.shell_channel.send(JSON.stringify(msg));
275 this.shell_channel.send(JSON.stringify(msg));
275 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
276 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
276 return msg.header.msg_id;
277 return msg.header.msg_id;
277 };
278 };
278
279
279
280
280 Kernel.prototype.interrupt = function () {
281 Kernel.prototype.interrupt = function () {
281 if (this.running) {
282 if (this.running) {
282 $([IPython.events]).trigger({type: 'status_interrupting.Kernel', kernel: this});
283 $([IPython.events]).trigger({type: 'status_interrupting.Kernel', kernel: this});
283 $.post(this.kernel_url + "/interrupt");
284 $.post(this.kernel_url + "/interrupt");
284 };
285 };
285 };
286 };
286
287
287
288
288 Kernel.prototype.kill = function () {
289 Kernel.prototype.kill = function () {
289 if (this.running) {
290 if (this.running) {
290 this.running = false;
291 this.running = false;
291 var settings = {
292 var settings = {
292 cache : false,
293 cache : false,
293 type : "DELETE"
294 type : "DELETE"
294 };
295 };
295 $.ajax(this.kernel_url, settings);
296 $.ajax(this.kernel_url, settings);
296 };
297 };
297 };
298 };
298
299
299
300
300 // Reply handlers.
301 // Reply handlers.
301
302
302 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
303 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
303 var callbacks = this._msg_callbacks[msg_id];
304 var callbacks = this._msg_callbacks[msg_id];
304 return callbacks;
305 return callbacks;
305 };
306 };
306
307
307
308
308 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
309 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
309 this._msg_callbacks[msg_id] = callbacks || {};
310 this._msg_callbacks[msg_id] = callbacks || {};
310 }
311 }
311
312
312
313
313 Kernel.prototype._handle_shell_reply = function (e) {
314 Kernel.prototype._handle_shell_reply = function (e) {
314 reply = $.parseJSON(e.data);
315 reply = $.parseJSON(e.data);
316 $([IPython.events]).trigger({type: 'Kernel.shell_reply', kernel: this, reply:reply});
315 var header = reply.header;
317 var header = reply.header;
316 var content = reply.content;
318 var content = reply.content;
317 var metadata = reply.metadata;
319 var metadata = reply.metadata;
318 var msg_type = header.msg_type;
320 var msg_type = header.msg_type;
319 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
321 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
320 if (callbacks !== undefined) {
322 if (callbacks !== undefined) {
321 var cb = callbacks[msg_type];
323 var cb = callbacks[msg_type];
322 if (cb !== undefined) {
324 if (cb !== undefined) {
323 cb(content, metadata);
325 cb(content, metadata);
324 }
326 }
325 };
327 };
326
328
327 if (content.payload !== undefined) {
329 if (content.payload !== undefined) {
328 var payload = content.payload || [];
330 var payload = content.payload || [];
329 this._handle_payload(callbacks, payload);
331 this._handle_payload(callbacks, payload);
330 }
332 }
331 };
333 };
332
334
333
335
334 Kernel.prototype._handle_payload = function (callbacks, payload) {
336 Kernel.prototype._handle_payload = function (callbacks, payload) {
335 var l = payload.length;
337 var l = payload.length;
336 // Payloads are handled by triggering events because we don't want the Kernel
338 // Payloads are handled by triggering events because we don't want the Kernel
337 // to depend on the Notebook or Pager classes.
339 // to depend on the Notebook or Pager classes.
338 for (var i=0; i<l; i++) {
340 for (var i=0; i<l; i++) {
339 if (payload[i].source === 'IPython.zmq.page.page') {
341 if (payload[i].source === 'IPython.zmq.page.page') {
340 var data = {'text':payload[i].text}
342 var data = {'text':payload[i].text}
341 $([IPython.events]).trigger('open_with_text.Pager', data);
343 $([IPython.events]).trigger('open_with_text.Pager', data);
342 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
344 } else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
343 if (callbacks.set_next_input !== undefined) {
345 if (callbacks.set_next_input !== undefined) {
344 callbacks.set_next_input(payload[i].text)
346 callbacks.set_next_input(payload[i].text)
345 }
347 }
346 }
348 }
347 };
349 };
348 };
350 };
349
351
350
352
351 Kernel.prototype._handle_iopub_reply = function (e) {
353 Kernel.prototype._handle_iopub_reply = function (e) {
352 var reply = $.parseJSON(e.data);
354 var reply = $.parseJSON(e.data);
353 var content = reply.content;
355 var content = reply.content;
354 var msg_type = reply.header.msg_type;
356 var msg_type = reply.header.msg_type;
355 var metadata = reply.metadata;
357 var metadata = reply.metadata;
356 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
358 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
357 if (msg_type !== 'status' && callbacks === undefined) {
359 if (msg_type !== 'status' && callbacks === undefined) {
358 // Message not from one of this notebook's cells and there are no
360 // Message not from one of this notebook's cells and there are no
359 // callbacks to handle it.
361 // callbacks to handle it.
360 return;
362 return;
361 }
363 }
362 var output_types = ['stream','display_data','pyout','pyerr'];
364 var output_types = ['stream','display_data','pyout','pyerr'];
363 if (output_types.indexOf(msg_type) >= 0) {
365 if (output_types.indexOf(msg_type) >= 0) {
364 var cb = callbacks['output'];
366 var cb = callbacks['output'];
365 if (cb !== undefined) {
367 if (cb !== undefined) {
366 cb(msg_type, content, metadata);
368 cb(msg_type, content, metadata);
367 }
369 }
368 } else if (msg_type === 'status') {
370 } else if (msg_type === 'status') {
369 if (content.execution_state === 'busy') {
371 if (content.execution_state === 'busy') {
370 $([IPython.events]).trigger({type: 'status_busy.Kernel', kernel: this});
372 $([IPython.events]).trigger({type: 'status_busy.Kernel', kernel: this});
371 } else if (content.execution_state === 'idle') {
373 } else if (content.execution_state === 'idle') {
372 $([IPython.events]).trigger({type: 'status_idle.Kernel', kernel: this});
374 $([IPython.events]).trigger({type: 'status_idle.Kernel', kernel: this});
373 } else if (content.execution_state === 'dead') {
375 } else if (content.execution_state === 'dead') {
374 this.stop_channels();
376 this.stop_channels();
375 $([IPython.events]).trigger({type: 'status_dead.Kernel', kernel: this});
377 $([IPython.events]).trigger({type: 'status_dead.Kernel', kernel: this});
376 };
378 };
377 } else if (msg_type === 'clear_output') {
379 } else if (msg_type === 'clear_output') {
378 var cb = callbacks['clear_output'];
380 var cb = callbacks['clear_output'];
379 if (cb !== undefined) {
381 if (cb !== undefined) {
380 cb(content, metadata);
382 cb(content, metadata);
381 }
383 }
382 };
384 };
383 };
385 };
384
386
385
387
386 IPython.Kernel = Kernel;
388 IPython.Kernel = Kernel;
387
389
388 return IPython;
390 return IPython;
389
391
390 }(IPython));
392 }(IPython));
391
393
General Comments 0
You need to be logged in to leave comments. Login now