##// END OF EJS Templates
s/prompt_number/execution_count in nbformat 4
MinRK -
Show More
@@ -1,131 +1,131 b''
1 # coding: utf-8
1 # coding: utf-8
2 import base64
2 import base64
3 import io
3 import io
4 import json
4 import json
5 import os
5 import os
6 from os.path import join as pjoin
6 from os.path import join as pjoin
7 import shutil
7 import shutil
8
8
9 import requests
9 import requests
10
10
11 from IPython.html.utils import url_path_join
11 from IPython.html.utils import url_path_join
12 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
12 from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error
13 from IPython.nbformat.current import (new_notebook, write,
13 from IPython.nbformat.current import (new_notebook, write,
14 new_heading_cell, new_code_cell,
14 new_heading_cell, new_code_cell,
15 new_output)
15 new_output)
16
16
17 from IPython.testing.decorators import onlyif_cmds_exist
17 from IPython.testing.decorators import onlyif_cmds_exist
18
18
19
19
20 class NbconvertAPI(object):
20 class NbconvertAPI(object):
21 """Wrapper for nbconvert API calls."""
21 """Wrapper for nbconvert API calls."""
22 def __init__(self, base_url):
22 def __init__(self, base_url):
23 self.base_url = base_url
23 self.base_url = base_url
24
24
25 def _req(self, verb, path, body=None, params=None):
25 def _req(self, verb, path, body=None, params=None):
26 response = requests.request(verb,
26 response = requests.request(verb,
27 url_path_join(self.base_url, 'nbconvert', path),
27 url_path_join(self.base_url, 'nbconvert', path),
28 data=body, params=params,
28 data=body, params=params,
29 )
29 )
30 response.raise_for_status()
30 response.raise_for_status()
31 return response
31 return response
32
32
33 def from_file(self, format, path, name, download=False):
33 def from_file(self, format, path, name, download=False):
34 return self._req('GET', url_path_join(format, path, name),
34 return self._req('GET', url_path_join(format, path, name),
35 params={'download':download})
35 params={'download':download})
36
36
37 def from_post(self, format, nbmodel):
37 def from_post(self, format, nbmodel):
38 body = json.dumps(nbmodel)
38 body = json.dumps(nbmodel)
39 return self._req('POST', format, body)
39 return self._req('POST', format, body)
40
40
41 def list_formats(self):
41 def list_formats(self):
42 return self._req('GET', '')
42 return self._req('GET', '')
43
43
44 png_green_pixel = base64.encodestring(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00'
44 png_green_pixel = base64.encodestring(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00'
45 b'\x00\x00\x01\x00\x00x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDAT'
45 b'\x00\x00\x01\x00\x00x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDAT'
46 b'\x08\xd7c\x90\xfb\xcf\x00\x00\x02\\\x01\x1e.~d\x87\x00\x00\x00\x00IEND\xaeB`\x82'
46 b'\x08\xd7c\x90\xfb\xcf\x00\x00\x02\\\x01\x1e.~d\x87\x00\x00\x00\x00IEND\xaeB`\x82'
47 ).decode('ascii')
47 ).decode('ascii')
48
48
49 class APITest(NotebookTestBase):
49 class APITest(NotebookTestBase):
50 def setUp(self):
50 def setUp(self):
51 nbdir = self.notebook_dir.name
51 nbdir = self.notebook_dir.name
52
52
53 if not os.path.isdir(pjoin(nbdir, 'foo')):
53 if not os.path.isdir(pjoin(nbdir, 'foo')):
54 os.mkdir(pjoin(nbdir, 'foo'))
54 os.mkdir(pjoin(nbdir, 'foo'))
55
55
56 nb = new_notebook()
56 nb = new_notebook()
57
57
58 nb.cells.append(new_heading_cell(u'Created by test ³'))
58 nb.cells.append(new_heading_cell(u'Created by test ³'))
59 cc1 = new_code_cell(source=u'print(2*6)')
59 cc1 = new_code_cell(source=u'print(2*6)')
60 cc1.outputs.append(new_output(output_type="stream", data=u'12'))
60 cc1.outputs.append(new_output(output_type="stream", data=u'12'))
61 cc1.outputs.append(new_output(output_type="execute_result",
61 cc1.outputs.append(new_output(output_type="execute_result",
62 mime_bundle={'image/png' : png_green_pixel},
62 mime_bundle={'image/png' : png_green_pixel},
63 prompt_number=1,
63 execution_count=1,
64 ))
64 ))
65 nb.cells.append(cc1)
65 nb.cells.append(cc1)
66
66
67 with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w',
67 with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w',
68 encoding='utf-8') as f:
68 encoding='utf-8') as f:
69 write(nb, f)
69 write(nb, f)
70
70
71 self.nbconvert_api = NbconvertAPI(self.base_url())
71 self.nbconvert_api = NbconvertAPI(self.base_url())
72
72
73 def tearDown(self):
73 def tearDown(self):
74 nbdir = self.notebook_dir.name
74 nbdir = self.notebook_dir.name
75
75
76 for dname in ['foo']:
76 for dname in ['foo']:
77 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
77 shutil.rmtree(pjoin(nbdir, dname), ignore_errors=True)
78
78
79 @onlyif_cmds_exist('pandoc')
79 @onlyif_cmds_exist('pandoc')
80 def test_from_file(self):
80 def test_from_file(self):
81 r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb')
81 r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb')
82 self.assertEqual(r.status_code, 200)
82 self.assertEqual(r.status_code, 200)
83 self.assertIn(u'text/html', r.headers['Content-Type'])
83 self.assertIn(u'text/html', r.headers['Content-Type'])
84 self.assertIn(u'Created by test', r.text)
84 self.assertIn(u'Created by test', r.text)
85 self.assertIn(u'print', r.text)
85 self.assertIn(u'print', r.text)
86
86
87 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb')
87 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb')
88 self.assertIn(u'text/x-python', r.headers['Content-Type'])
88 self.assertIn(u'text/x-python', r.headers['Content-Type'])
89 self.assertIn(u'print(2*6)', r.text)
89 self.assertIn(u'print(2*6)', r.text)
90
90
91 @onlyif_cmds_exist('pandoc')
91 @onlyif_cmds_exist('pandoc')
92 def test_from_file_404(self):
92 def test_from_file_404(self):
93 with assert_http_error(404):
93 with assert_http_error(404):
94 self.nbconvert_api.from_file('html', 'foo', 'thisdoesntexist.ipynb')
94 self.nbconvert_api.from_file('html', 'foo', 'thisdoesntexist.ipynb')
95
95
96 @onlyif_cmds_exist('pandoc')
96 @onlyif_cmds_exist('pandoc')
97 def test_from_file_download(self):
97 def test_from_file_download(self):
98 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True)
98 r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True)
99 content_disposition = r.headers['Content-Disposition']
99 content_disposition = r.headers['Content-Disposition']
100 self.assertIn('attachment', content_disposition)
100 self.assertIn('attachment', content_disposition)
101 self.assertIn('testnb.py', content_disposition)
101 self.assertIn('testnb.py', content_disposition)
102
102
103 @onlyif_cmds_exist('pandoc')
103 @onlyif_cmds_exist('pandoc')
104 def test_from_file_zip(self):
104 def test_from_file_zip(self):
105 r = self.nbconvert_api.from_file('latex', 'foo', 'testnb.ipynb', download=True)
105 r = self.nbconvert_api.from_file('latex', 'foo', 'testnb.ipynb', download=True)
106 self.assertIn(u'application/zip', r.headers['Content-Type'])
106 self.assertIn(u'application/zip', r.headers['Content-Type'])
107 self.assertIn(u'.zip', r.headers['Content-Disposition'])
107 self.assertIn(u'.zip', r.headers['Content-Disposition'])
108
108
109 @onlyif_cmds_exist('pandoc')
109 @onlyif_cmds_exist('pandoc')
110 def test_from_post(self):
110 def test_from_post(self):
111 nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb')
111 nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb')
112 nbmodel = requests.get(nbmodel_url).json()
112 nbmodel = requests.get(nbmodel_url).json()
113
113
114 r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel)
114 r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel)
115 self.assertEqual(r.status_code, 200)
115 self.assertEqual(r.status_code, 200)
116 self.assertIn(u'text/html', r.headers['Content-Type'])
116 self.assertIn(u'text/html', r.headers['Content-Type'])
117 self.assertIn(u'Created by test', r.text)
117 self.assertIn(u'Created by test', r.text)
118 self.assertIn(u'print', r.text)
118 self.assertIn(u'print', r.text)
119
119
120 r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel)
120 r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel)
121 self.assertIn(u'text/x-python', r.headers['Content-Type'])
121 self.assertIn(u'text/x-python', r.headers['Content-Type'])
122 self.assertIn(u'print(2*6)', r.text)
122 self.assertIn(u'print(2*6)', r.text)
123
123
124 @onlyif_cmds_exist('pandoc')
124 @onlyif_cmds_exist('pandoc')
125 def test_from_post_zip(self):
125 def test_from_post_zip(self):
126 nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb')
126 nbmodel_url = url_path_join(self.base_url(), 'api/contents/foo/testnb.ipynb')
127 nbmodel = requests.get(nbmodel_url).json()
127 nbmodel = requests.get(nbmodel_url).json()
128
128
129 r = self.nbconvert_api.from_post(format='latex', nbmodel=nbmodel)
129 r = self.nbconvert_api.from_post(format='latex', nbmodel=nbmodel)
130 self.assertIn(u'application/zip', r.headers['Content-Type'])
130 self.assertIn(u'application/zip', r.headers['Content-Type'])
131 self.assertIn(u'.zip', r.headers['Content-Disposition'])
131 self.assertIn(u'.zip', r.headers['Content-Disposition'])
@@ -1,526 +1,526 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 *
4 *
5 *
5 *
6 * @module codecell
6 * @module codecell
7 * @namespace codecell
7 * @namespace codecell
8 * @class CodeCell
8 * @class CodeCell
9 */
9 */
10
10
11
11
12 define([
12 define([
13 'base/js/namespace',
13 'base/js/namespace',
14 'jquery',
14 'jquery',
15 'base/js/utils',
15 'base/js/utils',
16 'base/js/keyboard',
16 'base/js/keyboard',
17 'notebook/js/cell',
17 'notebook/js/cell',
18 'notebook/js/outputarea',
18 'notebook/js/outputarea',
19 'notebook/js/completer',
19 'notebook/js/completer',
20 'notebook/js/celltoolbar',
20 'notebook/js/celltoolbar',
21 'codemirror/lib/codemirror',
21 'codemirror/lib/codemirror',
22 'codemirror/mode/python/python',
22 'codemirror/mode/python/python',
23 'notebook/js/codemirror-ipython'
23 'notebook/js/codemirror-ipython'
24 ], function(IPython, $, utils, keyboard, cell, outputarea, completer, celltoolbar, CodeMirror, cmpython, cmip) {
24 ], function(IPython, $, utils, keyboard, cell, outputarea, completer, celltoolbar, CodeMirror, cmpython, cmip) {
25 "use strict";
25 "use strict";
26 var Cell = cell.Cell;
26 var Cell = cell.Cell;
27
27
28 /* local util for codemirror */
28 /* local util for codemirror */
29 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
29 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
30
30
31 /**
31 /**
32 *
32 *
33 * function to delete until previous non blanking space character
33 * function to delete until previous non blanking space character
34 * or first multiple of 4 tabstop.
34 * or first multiple of 4 tabstop.
35 * @private
35 * @private
36 */
36 */
37 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
37 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
38 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
38 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
39 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
39 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
40 var cur = cm.getCursor(), line = cm.getLine(cur.line);
40 var cur = cm.getCursor(), line = cm.getLine(cur.line);
41 var tabsize = cm.getOption('tabSize');
41 var tabsize = cm.getOption('tabSize');
42 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
42 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
43 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
43 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
44 var select = cm.getRange(from,cur);
44 var select = cm.getRange(from,cur);
45 if( select.match(/^\ +$/) !== null){
45 if( select.match(/^\ +$/) !== null){
46 cm.replaceRange("",from,cur);
46 cm.replaceRange("",from,cur);
47 } else {
47 } else {
48 cm.deleteH(-1,"char");
48 cm.deleteH(-1,"char");
49 }
49 }
50 };
50 };
51
51
52 var keycodes = keyboard.keycodes;
52 var keycodes = keyboard.keycodes;
53
53
54 var CodeCell = function (kernel, options) {
54 var CodeCell = function (kernel, options) {
55 // Constructor
55 // Constructor
56 //
56 //
57 // A Cell conceived to write code.
57 // A Cell conceived to write code.
58 //
58 //
59 // Parameters:
59 // Parameters:
60 // kernel: Kernel instance
60 // kernel: Kernel instance
61 // The kernel doesn't have to be set at creation time, in that case
61 // The kernel doesn't have to be set at creation time, in that case
62 // it will be null and set_kernel has to be called later.
62 // it will be null and set_kernel has to be called later.
63 // options: dictionary
63 // options: dictionary
64 // Dictionary of keyword arguments.
64 // Dictionary of keyword arguments.
65 // events: $(Events) instance
65 // events: $(Events) instance
66 // config: dictionary
66 // config: dictionary
67 // keyboard_manager: KeyboardManager instance
67 // keyboard_manager: KeyboardManager instance
68 // notebook: Notebook instance
68 // notebook: Notebook instance
69 // tooltip: Tooltip instance
69 // tooltip: Tooltip instance
70 this.kernel = kernel || null;
70 this.kernel = kernel || null;
71 this.notebook = options.notebook;
71 this.notebook = options.notebook;
72 this.collapsed = false;
72 this.collapsed = false;
73 this.events = options.events;
73 this.events = options.events;
74 this.tooltip = options.tooltip;
74 this.tooltip = options.tooltip;
75 this.config = options.config;
75 this.config = options.config;
76
76
77 // create all attributed in constructor function
77 // create all attributed in constructor function
78 // even if null for V8 VM optimisation
78 // even if null for V8 VM optimisation
79 this.input_prompt_number = null;
79 this.input_prompt_number = null;
80 this.celltoolbar = null;
80 this.celltoolbar = null;
81 this.output_area = null;
81 this.output_area = null;
82 this.last_msg_id = null;
82 this.last_msg_id = null;
83 this.completer = null;
83 this.completer = null;
84
84
85
85
86 var config = utils.mergeopt(CodeCell, this.config);
86 var config = utils.mergeopt(CodeCell, this.config);
87 Cell.apply(this,[{
87 Cell.apply(this,[{
88 config: config,
88 config: config,
89 keyboard_manager: options.keyboard_manager,
89 keyboard_manager: options.keyboard_manager,
90 events: this.events}]);
90 events: this.events}]);
91
91
92 // Attributes we want to override in this subclass.
92 // Attributes we want to override in this subclass.
93 this.cell_type = "code";
93 this.cell_type = "code";
94
94
95 var that = this;
95 var that = this;
96 this.element.focusout(
96 this.element.focusout(
97 function() { that.auto_highlight(); }
97 function() { that.auto_highlight(); }
98 );
98 );
99 };
99 };
100
100
101 CodeCell.options_default = {
101 CodeCell.options_default = {
102 cm_config : {
102 cm_config : {
103 extraKeys: {
103 extraKeys: {
104 "Tab" : "indentMore",
104 "Tab" : "indentMore",
105 "Shift-Tab" : "indentLess",
105 "Shift-Tab" : "indentLess",
106 "Backspace" : "delSpaceToPrevTabStop",
106 "Backspace" : "delSpaceToPrevTabStop",
107 "Cmd-/" : "toggleComment",
107 "Cmd-/" : "toggleComment",
108 "Ctrl-/" : "toggleComment"
108 "Ctrl-/" : "toggleComment"
109 },
109 },
110 mode: 'ipython',
110 mode: 'ipython',
111 theme: 'ipython',
111 theme: 'ipython',
112 matchBrackets: true
112 matchBrackets: true
113 }
113 }
114 };
114 };
115
115
116 CodeCell.msg_cells = {};
116 CodeCell.msg_cells = {};
117
117
118 CodeCell.prototype = Object.create(Cell.prototype);
118 CodeCell.prototype = Object.create(Cell.prototype);
119
119
120 /**
120 /**
121 * @method auto_highlight
121 * @method auto_highlight
122 */
122 */
123 CodeCell.prototype.auto_highlight = function () {
123 CodeCell.prototype.auto_highlight = function () {
124 this._auto_highlight(this.config.cell_magic_highlight);
124 this._auto_highlight(this.config.cell_magic_highlight);
125 };
125 };
126
126
127 /** @method create_element */
127 /** @method create_element */
128 CodeCell.prototype.create_element = function () {
128 CodeCell.prototype.create_element = function () {
129 Cell.prototype.create_element.apply(this, arguments);
129 Cell.prototype.create_element.apply(this, arguments);
130
130
131 var cell = $('<div></div>').addClass('cell code_cell');
131 var cell = $('<div></div>').addClass('cell code_cell');
132 cell.attr('tabindex','2');
132 cell.attr('tabindex','2');
133
133
134 var input = $('<div></div>').addClass('input');
134 var input = $('<div></div>').addClass('input');
135 var prompt = $('<div/>').addClass('prompt input_prompt');
135 var prompt = $('<div/>').addClass('prompt input_prompt');
136 var inner_cell = $('<div/>').addClass('inner_cell');
136 var inner_cell = $('<div/>').addClass('inner_cell');
137 this.celltoolbar = new celltoolbar.CellToolbar({
137 this.celltoolbar = new celltoolbar.CellToolbar({
138 cell: this,
138 cell: this,
139 notebook: this.notebook});
139 notebook: this.notebook});
140 inner_cell.append(this.celltoolbar.element);
140 inner_cell.append(this.celltoolbar.element);
141 var input_area = $('<div/>').addClass('input_area');
141 var input_area = $('<div/>').addClass('input_area');
142 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
142 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
143 this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this))
143 this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this))
144 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
144 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
145 inner_cell.append(input_area);
145 inner_cell.append(input_area);
146 input.append(prompt).append(inner_cell);
146 input.append(prompt).append(inner_cell);
147
147
148 var widget_area = $('<div/>')
148 var widget_area = $('<div/>')
149 .addClass('widget-area')
149 .addClass('widget-area')
150 .hide();
150 .hide();
151 this.widget_area = widget_area;
151 this.widget_area = widget_area;
152 var widget_prompt = $('<div/>')
152 var widget_prompt = $('<div/>')
153 .addClass('prompt')
153 .addClass('prompt')
154 .appendTo(widget_area);
154 .appendTo(widget_area);
155 var widget_subarea = $('<div/>')
155 var widget_subarea = $('<div/>')
156 .addClass('widget-subarea')
156 .addClass('widget-subarea')
157 .appendTo(widget_area);
157 .appendTo(widget_area);
158 this.widget_subarea = widget_subarea;
158 this.widget_subarea = widget_subarea;
159 var widget_clear_buton = $('<button />')
159 var widget_clear_buton = $('<button />')
160 .addClass('close')
160 .addClass('close')
161 .html('&times;')
161 .html('&times;')
162 .click(function() {
162 .click(function() {
163 widget_area.slideUp('', function(){ widget_subarea.html(''); });
163 widget_area.slideUp('', function(){ widget_subarea.html(''); });
164 })
164 })
165 .appendTo(widget_prompt);
165 .appendTo(widget_prompt);
166
166
167 var output = $('<div></div>');
167 var output = $('<div></div>');
168 cell.append(input).append(widget_area).append(output);
168 cell.append(input).append(widget_area).append(output);
169 this.element = cell;
169 this.element = cell;
170 this.output_area = new outputarea.OutputArea({
170 this.output_area = new outputarea.OutputArea({
171 selector: output,
171 selector: output,
172 prompt_area: true,
172 prompt_area: true,
173 events: this.events,
173 events: this.events,
174 keyboard_manager: this.keyboard_manager});
174 keyboard_manager: this.keyboard_manager});
175 this.completer = new completer.Completer(this, this.events);
175 this.completer = new completer.Completer(this, this.events);
176 };
176 };
177
177
178 /** @method bind_events */
178 /** @method bind_events */
179 CodeCell.prototype.bind_events = function () {
179 CodeCell.prototype.bind_events = function () {
180 Cell.prototype.bind_events.apply(this);
180 Cell.prototype.bind_events.apply(this);
181 var that = this;
181 var that = this;
182
182
183 this.element.focusout(
183 this.element.focusout(
184 function() { that.auto_highlight(); }
184 function() { that.auto_highlight(); }
185 );
185 );
186 };
186 };
187
187
188
188
189 /**
189 /**
190 * This method gets called in CodeMirror's onKeyDown/onKeyPress
190 * This method gets called in CodeMirror's onKeyDown/onKeyPress
191 * handlers and is used to provide custom key handling. Its return
191 * handlers and is used to provide custom key handling. Its return
192 * value is used to determine if CodeMirror should ignore the event:
192 * value is used to determine if CodeMirror should ignore the event:
193 * true = ignore, false = don't ignore.
193 * true = ignore, false = don't ignore.
194 * @method handle_codemirror_keyevent
194 * @method handle_codemirror_keyevent
195 */
195 */
196 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
196 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
197
197
198 var that = this;
198 var that = this;
199 // whatever key is pressed, first, cancel the tooltip request before
199 // whatever key is pressed, first, cancel the tooltip request before
200 // they are sent, and remove tooltip if any, except for tab again
200 // they are sent, and remove tooltip if any, except for tab again
201 var tooltip_closed = null;
201 var tooltip_closed = null;
202 if (event.type === 'keydown' && event.which != keycodes.tab ) {
202 if (event.type === 'keydown' && event.which != keycodes.tab ) {
203 tooltip_closed = this.tooltip.remove_and_cancel_tooltip();
203 tooltip_closed = this.tooltip.remove_and_cancel_tooltip();
204 }
204 }
205
205
206 var cur = editor.getCursor();
206 var cur = editor.getCursor();
207 if (event.keyCode === keycodes.enter){
207 if (event.keyCode === keycodes.enter){
208 this.auto_highlight();
208 this.auto_highlight();
209 }
209 }
210
210
211 if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) {
211 if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) {
212 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
212 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
213 // browser and keyboard layout !
213 // browser and keyboard layout !
214 // Pressing '(' , request tooltip, don't forget to reappend it
214 // Pressing '(' , request tooltip, don't forget to reappend it
215 // The second argument says to hide the tooltip if the docstring
215 // The second argument says to hide the tooltip if the docstring
216 // is actually empty
216 // is actually empty
217 this.tooltip.pending(that, true);
217 this.tooltip.pending(that, true);
218 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
218 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
219 // If tooltip is active, cancel it. The call to
219 // If tooltip is active, cancel it. The call to
220 // remove_and_cancel_tooltip above doesn't pass, force=true.
220 // remove_and_cancel_tooltip above doesn't pass, force=true.
221 // Because of this it won't actually close the tooltip
221 // Because of this it won't actually close the tooltip
222 // if it is in sticky mode. Thus, we have to check again if it is open
222 // if it is in sticky mode. Thus, we have to check again if it is open
223 // and close it with force=true.
223 // and close it with force=true.
224 if (!this.tooltip._hidden) {
224 if (!this.tooltip._hidden) {
225 this.tooltip.remove_and_cancel_tooltip(true);
225 this.tooltip.remove_and_cancel_tooltip(true);
226 }
226 }
227 // If we closed the tooltip, don't let CM or the global handlers
227 // If we closed the tooltip, don't let CM or the global handlers
228 // handle this event.
228 // handle this event.
229 event.codemirrorIgnore = true;
229 event.codemirrorIgnore = true;
230 event.preventDefault();
230 event.preventDefault();
231 return true;
231 return true;
232 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
232 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
233 if (editor.somethingSelected() || editor.getSelections().length !== 1){
233 if (editor.somethingSelected() || editor.getSelections().length !== 1){
234 var anchor = editor.getCursor("anchor");
234 var anchor = editor.getCursor("anchor");
235 var head = editor.getCursor("head");
235 var head = editor.getCursor("head");
236 if( anchor.line != head.line){
236 if( anchor.line != head.line){
237 return false;
237 return false;
238 }
238 }
239 }
239 }
240 this.tooltip.request(that);
240 this.tooltip.request(that);
241 event.codemirrorIgnore = true;
241 event.codemirrorIgnore = true;
242 event.preventDefault();
242 event.preventDefault();
243 return true;
243 return true;
244 } else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
244 } else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
245 // Tab completion.
245 // Tab completion.
246 this.tooltip.remove_and_cancel_tooltip();
246 this.tooltip.remove_and_cancel_tooltip();
247
247
248 // completion does not work on multicursor, it might be possible though in some cases
248 // completion does not work on multicursor, it might be possible though in some cases
249 if (editor.somethingSelected() || editor.getSelections().length > 1) {
249 if (editor.somethingSelected() || editor.getSelections().length > 1) {
250 return false;
250 return false;
251 }
251 }
252 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
252 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
253 if (pre_cursor.trim() === "") {
253 if (pre_cursor.trim() === "") {
254 // Don't autocomplete if the part of the line before the cursor
254 // Don't autocomplete if the part of the line before the cursor
255 // is empty. In this case, let CodeMirror handle indentation.
255 // is empty. In this case, let CodeMirror handle indentation.
256 return false;
256 return false;
257 } else {
257 } else {
258 event.codemirrorIgnore = true;
258 event.codemirrorIgnore = true;
259 event.preventDefault();
259 event.preventDefault();
260 this.completer.startCompletion();
260 this.completer.startCompletion();
261 return true;
261 return true;
262 }
262 }
263 }
263 }
264
264
265 // keyboard event wasn't one of those unique to code cells, let's see
265 // keyboard event wasn't one of those unique to code cells, let's see
266 // if it's one of the generic ones (i.e. check edit mode shortcuts)
266 // if it's one of the generic ones (i.e. check edit mode shortcuts)
267 return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
267 return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
268 };
268 };
269
269
270 // Kernel related calls.
270 // Kernel related calls.
271
271
272 CodeCell.prototype.set_kernel = function (kernel) {
272 CodeCell.prototype.set_kernel = function (kernel) {
273 this.kernel = kernel;
273 this.kernel = kernel;
274 };
274 };
275
275
276 /**
276 /**
277 * Execute current code cell to the kernel
277 * Execute current code cell to the kernel
278 * @method execute
278 * @method execute
279 */
279 */
280 CodeCell.prototype.execute = function () {
280 CodeCell.prototype.execute = function () {
281 this.output_area.clear_output();
281 this.output_area.clear_output();
282
282
283 // Clear widget area
283 // Clear widget area
284 this.widget_subarea.html('');
284 this.widget_subarea.html('');
285 this.widget_subarea.height('');
285 this.widget_subarea.height('');
286 this.widget_area.height('');
286 this.widget_area.height('');
287 this.widget_area.hide();
287 this.widget_area.hide();
288
288
289 this.set_input_prompt('*');
289 this.set_input_prompt('*');
290 this.element.addClass("running");
290 this.element.addClass("running");
291 if (this.last_msg_id) {
291 if (this.last_msg_id) {
292 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
292 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
293 }
293 }
294 var callbacks = this.get_callbacks();
294 var callbacks = this.get_callbacks();
295
295
296 var old_msg_id = this.last_msg_id;
296 var old_msg_id = this.last_msg_id;
297 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
297 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
298 if (old_msg_id) {
298 if (old_msg_id) {
299 delete CodeCell.msg_cells[old_msg_id];
299 delete CodeCell.msg_cells[old_msg_id];
300 }
300 }
301 CodeCell.msg_cells[this.last_msg_id] = this;
301 CodeCell.msg_cells[this.last_msg_id] = this;
302 this.render();
302 this.render();
303 };
303 };
304
304
305 /**
305 /**
306 * Construct the default callbacks for
306 * Construct the default callbacks for
307 * @method get_callbacks
307 * @method get_callbacks
308 */
308 */
309 CodeCell.prototype.get_callbacks = function () {
309 CodeCell.prototype.get_callbacks = function () {
310 return {
310 return {
311 shell : {
311 shell : {
312 reply : $.proxy(this._handle_execute_reply, this),
312 reply : $.proxy(this._handle_execute_reply, this),
313 payload : {
313 payload : {
314 set_next_input : $.proxy(this._handle_set_next_input, this),
314 set_next_input : $.proxy(this._handle_set_next_input, this),
315 page : $.proxy(this._open_with_pager, this)
315 page : $.proxy(this._open_with_pager, this)
316 }
316 }
317 },
317 },
318 iopub : {
318 iopub : {
319 output : $.proxy(this.output_area.handle_output, this.output_area),
319 output : $.proxy(this.output_area.handle_output, this.output_area),
320 clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area),
320 clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area),
321 },
321 },
322 input : $.proxy(this._handle_input_request, this)
322 input : $.proxy(this._handle_input_request, this)
323 };
323 };
324 };
324 };
325
325
326 CodeCell.prototype._open_with_pager = function (payload) {
326 CodeCell.prototype._open_with_pager = function (payload) {
327 this.events.trigger('open_with_text.Pager', payload);
327 this.events.trigger('open_with_text.Pager', payload);
328 };
328 };
329
329
330 /**
330 /**
331 * @method _handle_execute_reply
331 * @method _handle_execute_reply
332 * @private
332 * @private
333 */
333 */
334 CodeCell.prototype._handle_execute_reply = function (msg) {
334 CodeCell.prototype._handle_execute_reply = function (msg) {
335 this.set_input_prompt(msg.content.execution_count);
335 this.set_input_prompt(msg.content.execution_count);
336 this.element.removeClass("running");
336 this.element.removeClass("running");
337 this.events.trigger('set_dirty.Notebook', {value: true});
337 this.events.trigger('set_dirty.Notebook', {value: true});
338 };
338 };
339
339
340 /**
340 /**
341 * @method _handle_set_next_input
341 * @method _handle_set_next_input
342 * @private
342 * @private
343 */
343 */
344 CodeCell.prototype._handle_set_next_input = function (payload) {
344 CodeCell.prototype._handle_set_next_input = function (payload) {
345 var data = {'cell': this, 'text': payload.text};
345 var data = {'cell': this, 'text': payload.text};
346 this.events.trigger('set_next_input.Notebook', data);
346 this.events.trigger('set_next_input.Notebook', data);
347 };
347 };
348
348
349 /**
349 /**
350 * @method _handle_input_request
350 * @method _handle_input_request
351 * @private
351 * @private
352 */
352 */
353 CodeCell.prototype._handle_input_request = function (msg) {
353 CodeCell.prototype._handle_input_request = function (msg) {
354 this.output_area.append_raw_input(msg);
354 this.output_area.append_raw_input(msg);
355 };
355 };
356
356
357
357
358 // Basic cell manipulation.
358 // Basic cell manipulation.
359
359
360 CodeCell.prototype.select = function () {
360 CodeCell.prototype.select = function () {
361 var cont = Cell.prototype.select.apply(this);
361 var cont = Cell.prototype.select.apply(this);
362 if (cont) {
362 if (cont) {
363 this.code_mirror.refresh();
363 this.code_mirror.refresh();
364 this.auto_highlight();
364 this.auto_highlight();
365 }
365 }
366 return cont;
366 return cont;
367 };
367 };
368
368
369 CodeCell.prototype.render = function () {
369 CodeCell.prototype.render = function () {
370 var cont = Cell.prototype.render.apply(this);
370 var cont = Cell.prototype.render.apply(this);
371 // Always execute, even if we are already in the rendered state
371 // Always execute, even if we are already in the rendered state
372 return cont;
372 return cont;
373 };
373 };
374
374
375 CodeCell.prototype.select_all = function () {
375 CodeCell.prototype.select_all = function () {
376 var start = {line: 0, ch: 0};
376 var start = {line: 0, ch: 0};
377 var nlines = this.code_mirror.lineCount();
377 var nlines = this.code_mirror.lineCount();
378 var last_line = this.code_mirror.getLine(nlines-1);
378 var last_line = this.code_mirror.getLine(nlines-1);
379 var end = {line: nlines-1, ch: last_line.length};
379 var end = {line: nlines-1, ch: last_line.length};
380 this.code_mirror.setSelection(start, end);
380 this.code_mirror.setSelection(start, end);
381 };
381 };
382
382
383
383
384 CodeCell.prototype.collapse_output = function () {
384 CodeCell.prototype.collapse_output = function () {
385 this.output_area.collapse();
385 this.output_area.collapse();
386 };
386 };
387
387
388
388
389 CodeCell.prototype.expand_output = function () {
389 CodeCell.prototype.expand_output = function () {
390 this.output_area.expand();
390 this.output_area.expand();
391 this.output_area.unscroll_area();
391 this.output_area.unscroll_area();
392 };
392 };
393
393
394 CodeCell.prototype.scroll_output = function () {
394 CodeCell.prototype.scroll_output = function () {
395 this.output_area.expand();
395 this.output_area.expand();
396 this.output_area.scroll_if_long();
396 this.output_area.scroll_if_long();
397 };
397 };
398
398
399 CodeCell.prototype.toggle_output = function () {
399 CodeCell.prototype.toggle_output = function () {
400 this.output_area.toggle_output();
400 this.output_area.toggle_output();
401 };
401 };
402
402
403 CodeCell.prototype.toggle_output_scroll = function () {
403 CodeCell.prototype.toggle_output_scroll = function () {
404 this.output_area.toggle_scroll();
404 this.output_area.toggle_scroll();
405 };
405 };
406
406
407
407
408 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
408 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
409 var ns;
409 var ns;
410 if (prompt_value === undefined || prompt_value === null) {
410 if (prompt_value === undefined || prompt_value === null) {
411 ns = "&nbsp;";
411 ns = "&nbsp;";
412 } else {
412 } else {
413 ns = encodeURIComponent(prompt_value);
413 ns = encodeURIComponent(prompt_value);
414 }
414 }
415 return 'In&nbsp;[' + ns + ']:';
415 return 'In&nbsp;[' + ns + ']:';
416 };
416 };
417
417
418 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
418 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
419 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
419 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
420 for(var i=1; i < lines_number; i++) {
420 for(var i=1; i < lines_number; i++) {
421 html.push(['...:']);
421 html.push(['...:']);
422 }
422 }
423 return html.join('<br/>');
423 return html.join('<br/>');
424 };
424 };
425
425
426 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
426 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
427
427
428
428
429 CodeCell.prototype.set_input_prompt = function (number) {
429 CodeCell.prototype.set_input_prompt = function (number) {
430 var nline = 1;
430 var nline = 1;
431 if (this.code_mirror !== undefined) {
431 if (this.code_mirror !== undefined) {
432 nline = this.code_mirror.lineCount();
432 nline = this.code_mirror.lineCount();
433 }
433 }
434 this.input_prompt_number = number;
434 this.input_prompt_number = number;
435 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
435 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
436 // This HTML call is okay because the user contents are escaped.
436 // This HTML call is okay because the user contents are escaped.
437 this.element.find('div.input_prompt').html(prompt_html);
437 this.element.find('div.input_prompt').html(prompt_html);
438 };
438 };
439
439
440
440
441 CodeCell.prototype.clear_input = function () {
441 CodeCell.prototype.clear_input = function () {
442 this.code_mirror.setValue('');
442 this.code_mirror.setValue('');
443 };
443 };
444
444
445
445
446 CodeCell.prototype.get_text = function () {
446 CodeCell.prototype.get_text = function () {
447 return this.code_mirror.getValue();
447 return this.code_mirror.getValue();
448 };
448 };
449
449
450
450
451 CodeCell.prototype.set_text = function (code) {
451 CodeCell.prototype.set_text = function (code) {
452 return this.code_mirror.setValue(code);
452 return this.code_mirror.setValue(code);
453 };
453 };
454
454
455
455
456 CodeCell.prototype.clear_output = function (wait) {
456 CodeCell.prototype.clear_output = function (wait) {
457 this.output_area.clear_output(wait);
457 this.output_area.clear_output(wait);
458 this.set_input_prompt();
458 this.set_input_prompt();
459 };
459 };
460
460
461
461
462 // JSON serialization
462 // JSON serialization
463
463
464 CodeCell.prototype.fromJSON = function (data) {
464 CodeCell.prototype.fromJSON = function (data) {
465 Cell.prototype.fromJSON.apply(this, arguments);
465 Cell.prototype.fromJSON.apply(this, arguments);
466 if (data.cell_type === 'code') {
466 if (data.cell_type === 'code') {
467 if (data.source !== undefined) {
467 if (data.source !== undefined) {
468 this.set_text(data.source);
468 this.set_text(data.source);
469 // make this value the starting point, so that we can only undo
469 // make this value the starting point, so that we can only undo
470 // to this state, instead of a blank cell
470 // to this state, instead of a blank cell
471 this.code_mirror.clearHistory();
471 this.code_mirror.clearHistory();
472 this.auto_highlight();
472 this.auto_highlight();
473 }
473 }
474 this.set_input_prompt(data.prompt_number);
474 this.set_input_prompt(data.execution_count);
475 this.output_area.trusted = data.metadata.trusted || false;
475 this.output_area.trusted = data.metadata.trusted || false;
476 this.output_area.fromJSON(data.outputs);
476 this.output_area.fromJSON(data.outputs);
477 if (data.metadata.collapsed !== undefined) {
477 if (data.metadata.collapsed !== undefined) {
478 if (data.metadata.collapsed) {
478 if (data.metadata.collapsed) {
479 this.collapse_output();
479 this.collapse_output();
480 } else {
480 } else {
481 this.expand_output();
481 this.expand_output();
482 }
482 }
483 }
483 }
484 }
484 }
485 };
485 };
486
486
487
487
488 CodeCell.prototype.toJSON = function () {
488 CodeCell.prototype.toJSON = function () {
489 var data = Cell.prototype.toJSON.apply(this);
489 var data = Cell.prototype.toJSON.apply(this);
490 data.source = this.get_text();
490 data.source = this.get_text();
491 // is finite protect against undefined and '*' value
491 // is finite protect against undefined and '*' value
492 if (isFinite(this.input_prompt_number)) {
492 if (isFinite(this.input_prompt_number)) {
493 data.prompt_number = this.input_prompt_number;
493 data.execution_count = this.input_prompt_number;
494 } else {
494 } else {
495 data.prompt_number = null;
495 data.execution_count = null;
496 }
496 }
497 var outputs = this.output_area.toJSON();
497 var outputs = this.output_area.toJSON();
498 data.outputs = outputs;
498 data.outputs = outputs;
499 data.metadata.trusted = this.output_area.trusted;
499 data.metadata.trusted = this.output_area.trusted;
500 data.metadata.collapsed = this.output_area.collapsed;
500 data.metadata.collapsed = this.output_area.collapsed;
501 return data;
501 return data;
502 };
502 };
503
503
504 /**
504 /**
505 * handle cell level logic when a cell is unselected
505 * handle cell level logic when a cell is unselected
506 * @method unselect
506 * @method unselect
507 * @return is the action being taken
507 * @return is the action being taken
508 */
508 */
509 CodeCell.prototype.unselect = function () {
509 CodeCell.prototype.unselect = function () {
510 var cont = Cell.prototype.unselect.apply(this);
510 var cont = Cell.prototype.unselect.apply(this);
511 if (cont) {
511 if (cont) {
512 // When a code cell is usnelected, make sure that the corresponding
512 // When a code cell is usnelected, make sure that the corresponding
513 // tooltip and completer to that cell is closed.
513 // tooltip and completer to that cell is closed.
514 this.tooltip.remove_and_cancel_tooltip(true);
514 this.tooltip.remove_and_cancel_tooltip(true);
515 if (this.completer !== null) {
515 if (this.completer !== null) {
516 this.completer.close();
516 this.completer.close();
517 }
517 }
518 }
518 }
519 return cont;
519 return cont;
520 };
520 };
521
521
522 // Backwards compatability.
522 // Backwards compatability.
523 IPython.CodeCell = CodeCell;
523 IPython.CodeCell = CodeCell;
524
524
525 return {'CodeCell': CodeCell};
525 return {'CodeCell': CodeCell};
526 });
526 });
@@ -1,941 +1,941 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 'jqueryui',
6 'jqueryui',
7 'base/js/utils',
7 'base/js/utils',
8 'base/js/security',
8 'base/js/security',
9 'base/js/keyboard',
9 'base/js/keyboard',
10 'notebook/js/mathjaxutils',
10 'notebook/js/mathjaxutils',
11 'components/marked/lib/marked',
11 'components/marked/lib/marked',
12 ], function(IPython, $, utils, security, keyboard, mathjaxutils, marked) {
12 ], function(IPython, $, utils, security, keyboard, mathjaxutils, marked) {
13 "use strict";
13 "use strict";
14
14
15 /**
15 /**
16 * @class OutputArea
16 * @class OutputArea
17 *
17 *
18 * @constructor
18 * @constructor
19 */
19 */
20
20
21 var OutputArea = function (options) {
21 var OutputArea = function (options) {
22 this.selector = options.selector;
22 this.selector = options.selector;
23 this.events = options.events;
23 this.events = options.events;
24 this.keyboard_manager = options.keyboard_manager;
24 this.keyboard_manager = options.keyboard_manager;
25 this.wrapper = $(options.selector);
25 this.wrapper = $(options.selector);
26 this.outputs = [];
26 this.outputs = [];
27 this.collapsed = false;
27 this.collapsed = false;
28 this.scrolled = false;
28 this.scrolled = false;
29 this.trusted = true;
29 this.trusted = true;
30 this.clear_queued = null;
30 this.clear_queued = null;
31 if (options.prompt_area === undefined) {
31 if (options.prompt_area === undefined) {
32 this.prompt_area = true;
32 this.prompt_area = true;
33 } else {
33 } else {
34 this.prompt_area = options.prompt_area;
34 this.prompt_area = options.prompt_area;
35 }
35 }
36 this.create_elements();
36 this.create_elements();
37 this.style();
37 this.style();
38 this.bind_events();
38 this.bind_events();
39 };
39 };
40
40
41
41
42 /**
42 /**
43 * Class prototypes
43 * Class prototypes
44 **/
44 **/
45
45
46 OutputArea.prototype.create_elements = function () {
46 OutputArea.prototype.create_elements = function () {
47 this.element = $("<div/>");
47 this.element = $("<div/>");
48 this.collapse_button = $("<div/>");
48 this.collapse_button = $("<div/>");
49 this.prompt_overlay = $("<div/>");
49 this.prompt_overlay = $("<div/>");
50 this.wrapper.append(this.prompt_overlay);
50 this.wrapper.append(this.prompt_overlay);
51 this.wrapper.append(this.element);
51 this.wrapper.append(this.element);
52 this.wrapper.append(this.collapse_button);
52 this.wrapper.append(this.collapse_button);
53 };
53 };
54
54
55
55
56 OutputArea.prototype.style = function () {
56 OutputArea.prototype.style = function () {
57 this.collapse_button.hide();
57 this.collapse_button.hide();
58 this.prompt_overlay.hide();
58 this.prompt_overlay.hide();
59
59
60 this.wrapper.addClass('output_wrapper');
60 this.wrapper.addClass('output_wrapper');
61 this.element.addClass('output');
61 this.element.addClass('output');
62
62
63 this.collapse_button.addClass("btn btn-default output_collapsed");
63 this.collapse_button.addClass("btn btn-default output_collapsed");
64 this.collapse_button.attr('title', 'click to expand output');
64 this.collapse_button.attr('title', 'click to expand output');
65 this.collapse_button.text('. . .');
65 this.collapse_button.text('. . .');
66
66
67 this.prompt_overlay.addClass('out_prompt_overlay prompt');
67 this.prompt_overlay.addClass('out_prompt_overlay prompt');
68 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
68 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
69
69
70 this.collapse();
70 this.collapse();
71 };
71 };
72
72
73 /**
73 /**
74 * Should the OutputArea scroll?
74 * Should the OutputArea scroll?
75 * Returns whether the height (in lines) exceeds a threshold.
75 * Returns whether the height (in lines) exceeds a threshold.
76 *
76 *
77 * @private
77 * @private
78 * @method _should_scroll
78 * @method _should_scroll
79 * @param [lines=100]{Integer}
79 * @param [lines=100]{Integer}
80 * @return {Bool}
80 * @return {Bool}
81 *
81 *
82 */
82 */
83 OutputArea.prototype._should_scroll = function (lines) {
83 OutputArea.prototype._should_scroll = function (lines) {
84 if (lines <=0 ){ return }
84 if (lines <=0 ){ return }
85 if (!lines) {
85 if (!lines) {
86 lines = 100;
86 lines = 100;
87 }
87 }
88 // line-height from http://stackoverflow.com/questions/1185151
88 // line-height from http://stackoverflow.com/questions/1185151
89 var fontSize = this.element.css('font-size');
89 var fontSize = this.element.css('font-size');
90 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
90 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
91
91
92 return (this.element.height() > lines * lineHeight);
92 return (this.element.height() > lines * lineHeight);
93 };
93 };
94
94
95
95
96 OutputArea.prototype.bind_events = function () {
96 OutputArea.prototype.bind_events = function () {
97 var that = this;
97 var that = this;
98 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
98 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
99 this.prompt_overlay.click(function () { that.toggle_scroll(); });
99 this.prompt_overlay.click(function () { that.toggle_scroll(); });
100
100
101 this.element.resize(function () {
101 this.element.resize(function () {
102 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
102 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
103 if ( utils.browser[0] === "Firefox" ) {
103 if ( utils.browser[0] === "Firefox" ) {
104 return;
104 return;
105 }
105 }
106 // maybe scroll output,
106 // maybe scroll output,
107 // if it's grown large enough and hasn't already been scrolled.
107 // if it's grown large enough and hasn't already been scrolled.
108 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
108 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
109 that.scroll_area();
109 that.scroll_area();
110 }
110 }
111 });
111 });
112 this.collapse_button.click(function () {
112 this.collapse_button.click(function () {
113 that.expand();
113 that.expand();
114 });
114 });
115 };
115 };
116
116
117
117
118 OutputArea.prototype.collapse = function () {
118 OutputArea.prototype.collapse = function () {
119 if (!this.collapsed) {
119 if (!this.collapsed) {
120 this.element.hide();
120 this.element.hide();
121 this.prompt_overlay.hide();
121 this.prompt_overlay.hide();
122 if (this.element.html()){
122 if (this.element.html()){
123 this.collapse_button.show();
123 this.collapse_button.show();
124 }
124 }
125 this.collapsed = true;
125 this.collapsed = true;
126 }
126 }
127 };
127 };
128
128
129
129
130 OutputArea.prototype.expand = function () {
130 OutputArea.prototype.expand = function () {
131 if (this.collapsed) {
131 if (this.collapsed) {
132 this.collapse_button.hide();
132 this.collapse_button.hide();
133 this.element.show();
133 this.element.show();
134 this.prompt_overlay.show();
134 this.prompt_overlay.show();
135 this.collapsed = false;
135 this.collapsed = false;
136 }
136 }
137 };
137 };
138
138
139
139
140 OutputArea.prototype.toggle_output = function () {
140 OutputArea.prototype.toggle_output = function () {
141 if (this.collapsed) {
141 if (this.collapsed) {
142 this.expand();
142 this.expand();
143 } else {
143 } else {
144 this.collapse();
144 this.collapse();
145 }
145 }
146 };
146 };
147
147
148
148
149 OutputArea.prototype.scroll_area = function () {
149 OutputArea.prototype.scroll_area = function () {
150 this.element.addClass('output_scroll');
150 this.element.addClass('output_scroll');
151 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
151 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
152 this.scrolled = true;
152 this.scrolled = true;
153 };
153 };
154
154
155
155
156 OutputArea.prototype.unscroll_area = function () {
156 OutputArea.prototype.unscroll_area = function () {
157 this.element.removeClass('output_scroll');
157 this.element.removeClass('output_scroll');
158 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
158 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
159 this.scrolled = false;
159 this.scrolled = false;
160 };
160 };
161
161
162 /**
162 /**
163 *
163 *
164 * Scroll OutputArea if height supperior than a threshold (in lines).
164 * Scroll OutputArea if height supperior than a threshold (in lines).
165 *
165 *
166 * Threshold is a maximum number of lines. If unspecified, defaults to
166 * Threshold is a maximum number of lines. If unspecified, defaults to
167 * OutputArea.minimum_scroll_threshold.
167 * OutputArea.minimum_scroll_threshold.
168 *
168 *
169 * Negative threshold will prevent the OutputArea from ever scrolling.
169 * Negative threshold will prevent the OutputArea from ever scrolling.
170 *
170 *
171 * @method scroll_if_long
171 * @method scroll_if_long
172 *
172 *
173 * @param [lines=20]{Number} Default to 20 if not set,
173 * @param [lines=20]{Number} Default to 20 if not set,
174 * behavior undefined for value of `0`.
174 * behavior undefined for value of `0`.
175 *
175 *
176 **/
176 **/
177 OutputArea.prototype.scroll_if_long = function (lines) {
177 OutputArea.prototype.scroll_if_long = function (lines) {
178 var n = lines | OutputArea.minimum_scroll_threshold;
178 var n = lines | OutputArea.minimum_scroll_threshold;
179 if(n <= 0){
179 if(n <= 0){
180 return
180 return
181 }
181 }
182
182
183 if (this._should_scroll(n)) {
183 if (this._should_scroll(n)) {
184 // only allow scrolling long-enough output
184 // only allow scrolling long-enough output
185 this.scroll_area();
185 this.scroll_area();
186 }
186 }
187 };
187 };
188
188
189
189
190 OutputArea.prototype.toggle_scroll = function () {
190 OutputArea.prototype.toggle_scroll = function () {
191 if (this.scrolled) {
191 if (this.scrolled) {
192 this.unscroll_area();
192 this.unscroll_area();
193 } else {
193 } else {
194 // only allow scrolling long-enough output
194 // only allow scrolling long-enough output
195 this.scroll_if_long();
195 this.scroll_if_long();
196 }
196 }
197 };
197 };
198
198
199
199
200 // typeset with MathJax if MathJax is available
200 // typeset with MathJax if MathJax is available
201 OutputArea.prototype.typeset = function () {
201 OutputArea.prototype.typeset = function () {
202 if (window.MathJax){
202 if (window.MathJax){
203 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
203 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
204 }
204 }
205 };
205 };
206
206
207
207
208 OutputArea.prototype.handle_output = function (msg) {
208 OutputArea.prototype.handle_output = function (msg) {
209 var json = {};
209 var json = {};
210 var msg_type = json.output_type = msg.header.msg_type;
210 var msg_type = json.output_type = msg.header.msg_type;
211 var content = msg.content;
211 var content = msg.content;
212 if (msg_type === "stream") {
212 if (msg_type === "stream") {
213 json.text = content.text;
213 json.text = content.text;
214 json.name = content.name;
214 json.name = content.name;
215 } else if (msg_type === "display_data") {
215 } else if (msg_type === "display_data") {
216 json = content.data;
216 json = content.data;
217 json.output_type = msg_type;
217 json.output_type = msg_type;
218 json.metadata = content.metadata;
218 json.metadata = content.metadata;
219 } else if (msg_type === "execute_result") {
219 } else if (msg_type === "execute_result") {
220 json = content.data;
220 json = content.data;
221 json.output_type = msg_type;
221 json.output_type = msg_type;
222 json.metadata = content.metadata;
222 json.metadata = content.metadata;
223 json.prompt_number = content.execution_count;
223 json.execution_count = content.execution_count;
224 } else if (msg_type === "error") {
224 } else if (msg_type === "error") {
225 json.ename = content.ename;
225 json.ename = content.ename;
226 json.evalue = content.evalue;
226 json.evalue = content.evalue;
227 json.traceback = content.traceback;
227 json.traceback = content.traceback;
228 } else {
228 } else {
229 console.log("unhandled output message", msg);
229 console.log("unhandled output message", msg);
230 return;
230 return;
231 }
231 }
232 this.append_output(json);
232 this.append_output(json);
233 };
233 };
234
234
235
235
236 OutputArea.prototype.rename_keys = function (data, key_map) {
236 OutputArea.prototype.rename_keys = function (data, key_map) {
237 // TODO: This is now unused, should it be removed?
237 // TODO: This is now unused, should it be removed?
238 var remapped = {};
238 var remapped = {};
239 for (var key in data) {
239 for (var key in data) {
240 var new_key = key_map[key] || key;
240 var new_key = key_map[key] || key;
241 remapped[new_key] = data[key];
241 remapped[new_key] = data[key];
242 }
242 }
243 return remapped;
243 return remapped;
244 };
244 };
245
245
246
246
247 OutputArea.output_types = [
247 OutputArea.output_types = [
248 'application/javascript',
248 'application/javascript',
249 'text/html',
249 'text/html',
250 'text/markdown',
250 'text/markdown',
251 'text/latex',
251 'text/latex',
252 'image/svg+xml',
252 'image/svg+xml',
253 'image/png',
253 'image/png',
254 'image/jpeg',
254 'image/jpeg',
255 'application/pdf',
255 'application/pdf',
256 'text/plain'
256 'text/plain'
257 ];
257 ];
258
258
259 OutputArea.prototype.validate_output = function (json) {
259 OutputArea.prototype.validate_output = function (json) {
260 // scrub invalid outputs
260 // scrub invalid outputs
261 // TODO: right now everything is a string, but JSON really shouldn't be.
261 // TODO: right now everything is a string, but JSON really shouldn't be.
262 // nbformat 4 will fix that.
262 // nbformat 4 will fix that.
263 $.map(OutputArea.output_types, function(key){
263 $.map(OutputArea.output_types, function(key){
264 if (key !== 'application/json' &&
264 if (key !== 'application/json' &&
265 json[key] !== undefined &&
265 json[key] !== undefined &&
266 typeof json[key] !== 'string'
266 typeof json[key] !== 'string'
267 ) {
267 ) {
268 console.log("Invalid type for " + key, json[key]);
268 console.log("Invalid type for " + key, json[key]);
269 delete json[key];
269 delete json[key];
270 }
270 }
271 });
271 });
272 return json;
272 return json;
273 };
273 };
274
274
275 OutputArea.prototype.append_output = function (json) {
275 OutputArea.prototype.append_output = function (json) {
276 this.expand();
276 this.expand();
277
277
278 // validate output data types
278 // validate output data types
279 json = this.validate_output(json);
279 json = this.validate_output(json);
280
280
281 // Clear the output if clear is queued.
281 // Clear the output if clear is queued.
282 var needs_height_reset = false;
282 var needs_height_reset = false;
283 if (this.clear_queued) {
283 if (this.clear_queued) {
284 this.clear_output(false);
284 this.clear_output(false);
285 needs_height_reset = true;
285 needs_height_reset = true;
286 }
286 }
287
287
288 var record_output = true;
288 var record_output = true;
289
289
290 if (json.output_type === 'execute_result') {
290 if (json.output_type === 'execute_result') {
291 this.append_execute_result(json);
291 this.append_execute_result(json);
292 } else if (json.output_type === 'error') {
292 } else if (json.output_type === 'error') {
293 this.append_error(json);
293 this.append_error(json);
294 } else if (json.output_type === 'stream') {
294 } else if (json.output_type === 'stream') {
295 // append_stream might have merged the output with earlier stream output
295 // append_stream might have merged the output with earlier stream output
296 record_output = this.append_stream(json);
296 record_output = this.append_stream(json);
297 }
297 }
298
298
299 // We must release the animation fixed height in a callback since Gecko
299 // We must release the animation fixed height in a callback since Gecko
300 // (FireFox) doesn't render the image immediately as the data is
300 // (FireFox) doesn't render the image immediately as the data is
301 // available.
301 // available.
302 var that = this;
302 var that = this;
303 var handle_appended = function ($el) {
303 var handle_appended = function ($el) {
304 // Only reset the height to automatic if the height is currently
304 // Only reset the height to automatic if the height is currently
305 // fixed (done by wait=True flag on clear_output).
305 // fixed (done by wait=True flag on clear_output).
306 if (needs_height_reset) {
306 if (needs_height_reset) {
307 that.element.height('');
307 that.element.height('');
308 }
308 }
309 that.element.trigger('resize');
309 that.element.trigger('resize');
310 };
310 };
311 if (json.output_type === 'display_data') {
311 if (json.output_type === 'display_data') {
312 this.append_display_data(json, handle_appended);
312 this.append_display_data(json, handle_appended);
313 } else {
313 } else {
314 handle_appended();
314 handle_appended();
315 }
315 }
316
316
317 if (record_output) {
317 if (record_output) {
318 this.outputs.push(json);
318 this.outputs.push(json);
319 }
319 }
320 };
320 };
321
321
322
322
323 OutputArea.prototype.create_output_area = function () {
323 OutputArea.prototype.create_output_area = function () {
324 var oa = $("<div/>").addClass("output_area");
324 var oa = $("<div/>").addClass("output_area");
325 if (this.prompt_area) {
325 if (this.prompt_area) {
326 oa.append($('<div/>').addClass('prompt'));
326 oa.append($('<div/>').addClass('prompt'));
327 }
327 }
328 return oa;
328 return oa;
329 };
329 };
330
330
331
331
332 function _get_metadata_key(metadata, key, mime) {
332 function _get_metadata_key(metadata, key, mime) {
333 var mime_md = metadata[mime];
333 var mime_md = metadata[mime];
334 // mime-specific higher priority
334 // mime-specific higher priority
335 if (mime_md && mime_md[key] !== undefined) {
335 if (mime_md && mime_md[key] !== undefined) {
336 return mime_md[key];
336 return mime_md[key];
337 }
337 }
338 // fallback on global
338 // fallback on global
339 return metadata[key];
339 return metadata[key];
340 }
340 }
341
341
342 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
342 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
343 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
343 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
344 if (_get_metadata_key(md, 'isolated', mime)) {
344 if (_get_metadata_key(md, 'isolated', mime)) {
345 // Create an iframe to isolate the subarea from the rest of the
345 // Create an iframe to isolate the subarea from the rest of the
346 // document
346 // document
347 var iframe = $('<iframe/>').addClass('box-flex1');
347 var iframe = $('<iframe/>').addClass('box-flex1');
348 iframe.css({'height':1, 'width':'100%', 'display':'block'});
348 iframe.css({'height':1, 'width':'100%', 'display':'block'});
349 iframe.attr('frameborder', 0);
349 iframe.attr('frameborder', 0);
350 iframe.attr('scrolling', 'auto');
350 iframe.attr('scrolling', 'auto');
351
351
352 // Once the iframe is loaded, the subarea is dynamically inserted
352 // Once the iframe is loaded, the subarea is dynamically inserted
353 iframe.on('load', function() {
353 iframe.on('load', function() {
354 // Workaround needed by Firefox, to properly render svg inside
354 // Workaround needed by Firefox, to properly render svg inside
355 // iframes, see http://stackoverflow.com/questions/10177190/
355 // iframes, see http://stackoverflow.com/questions/10177190/
356 // svg-dynamically-added-to-iframe-does-not-render-correctly
356 // svg-dynamically-added-to-iframe-does-not-render-correctly
357 this.contentDocument.open();
357 this.contentDocument.open();
358
358
359 // Insert the subarea into the iframe
359 // Insert the subarea into the iframe
360 // We must directly write the html. When using Jquery's append
360 // We must directly write the html. When using Jquery's append
361 // method, javascript is evaluated in the parent document and
361 // method, javascript is evaluated in the parent document and
362 // not in the iframe document. At this point, subarea doesn't
362 // not in the iframe document. At this point, subarea doesn't
363 // contain any user content.
363 // contain any user content.
364 this.contentDocument.write(subarea.html());
364 this.contentDocument.write(subarea.html());
365
365
366 this.contentDocument.close();
366 this.contentDocument.close();
367
367
368 var body = this.contentDocument.body;
368 var body = this.contentDocument.body;
369 // Adjust the iframe height automatically
369 // Adjust the iframe height automatically
370 iframe.height(body.scrollHeight + 'px');
370 iframe.height(body.scrollHeight + 'px');
371 });
371 });
372
372
373 // Elements should be appended to the inner subarea and not to the
373 // Elements should be appended to the inner subarea and not to the
374 // iframe
374 // iframe
375 iframe.append = function(that) {
375 iframe.append = function(that) {
376 subarea.append(that);
376 subarea.append(that);
377 };
377 };
378
378
379 return iframe;
379 return iframe;
380 } else {
380 } else {
381 return subarea;
381 return subarea;
382 }
382 }
383 }
383 }
384
384
385
385
386 OutputArea.prototype._append_javascript_error = function (err, element) {
386 OutputArea.prototype._append_javascript_error = function (err, element) {
387 // display a message when a javascript error occurs in display output
387 // display a message when a javascript error occurs in display output
388 var msg = "Javascript error adding output!"
388 var msg = "Javascript error adding output!"
389 if ( element === undefined ) return;
389 if ( element === undefined ) return;
390 element
390 element
391 .append($('<div/>').text(msg).addClass('js-error'))
391 .append($('<div/>').text(msg).addClass('js-error'))
392 .append($('<div/>').text(err.toString()).addClass('js-error'))
392 .append($('<div/>').text(err.toString()).addClass('js-error'))
393 .append($('<div/>').text('See your browser Javascript console for more details.').addClass('js-error'));
393 .append($('<div/>').text('See your browser Javascript console for more details.').addClass('js-error'));
394 };
394 };
395
395
396 OutputArea.prototype._safe_append = function (toinsert) {
396 OutputArea.prototype._safe_append = function (toinsert) {
397 // safely append an item to the document
397 // safely append an item to the document
398 // this is an object created by user code,
398 // this is an object created by user code,
399 // and may have errors, which should not be raised
399 // and may have errors, which should not be raised
400 // under any circumstances.
400 // under any circumstances.
401 try {
401 try {
402 this.element.append(toinsert);
402 this.element.append(toinsert);
403 } catch(err) {
403 } catch(err) {
404 console.log(err);
404 console.log(err);
405 // Create an actual output_area and output_subarea, which creates
405 // Create an actual output_area and output_subarea, which creates
406 // the prompt area and the proper indentation.
406 // the prompt area and the proper indentation.
407 var toinsert = this.create_output_area();
407 var toinsert = this.create_output_area();
408 var subarea = $('<div/>').addClass('output_subarea');
408 var subarea = $('<div/>').addClass('output_subarea');
409 toinsert.append(subarea);
409 toinsert.append(subarea);
410 this._append_javascript_error(err, subarea);
410 this._append_javascript_error(err, subarea);
411 this.element.append(toinsert);
411 this.element.append(toinsert);
412 }
412 }
413 };
413 };
414
414
415
415
416 OutputArea.prototype.append_execute_result = function (json) {
416 OutputArea.prototype.append_execute_result = function (json) {
417 var n = json.prompt_number || ' ';
417 var n = json.execution_count || ' ';
418 var toinsert = this.create_output_area();
418 var toinsert = this.create_output_area();
419 if (this.prompt_area) {
419 if (this.prompt_area) {
420 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
420 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
421 }
421 }
422 var inserted = this.append_mime_type(json, toinsert);
422 var inserted = this.append_mime_type(json, toinsert);
423 if (inserted) {
423 if (inserted) {
424 inserted.addClass('output_result');
424 inserted.addClass('output_result');
425 }
425 }
426 this._safe_append(toinsert);
426 this._safe_append(toinsert);
427 // If we just output latex, typeset it.
427 // If we just output latex, typeset it.
428 if ((json['text/latex'] !== undefined) ||
428 if ((json['text/latex'] !== undefined) ||
429 (json['text/html'] !== undefined) ||
429 (json['text/html'] !== undefined) ||
430 (json['text/markdown'] !== undefined)) {
430 (json['text/markdown'] !== undefined)) {
431 this.typeset();
431 this.typeset();
432 }
432 }
433 };
433 };
434
434
435
435
436 OutputArea.prototype.append_error = function (json) {
436 OutputArea.prototype.append_error = function (json) {
437 var tb = json.traceback;
437 var tb = json.traceback;
438 if (tb !== undefined && tb.length > 0) {
438 if (tb !== undefined && tb.length > 0) {
439 var s = '';
439 var s = '';
440 var len = tb.length;
440 var len = tb.length;
441 for (var i=0; i<len; i++) {
441 for (var i=0; i<len; i++) {
442 s = s + tb[i] + '\n';
442 s = s + tb[i] + '\n';
443 }
443 }
444 s = s + '\n';
444 s = s + '\n';
445 var toinsert = this.create_output_area();
445 var toinsert = this.create_output_area();
446 var append_text = OutputArea.append_map['text/plain'];
446 var append_text = OutputArea.append_map['text/plain'];
447 if (append_text) {
447 if (append_text) {
448 append_text.apply(this, [s, {}, toinsert]).addClass('output_error');
448 append_text.apply(this, [s, {}, toinsert]).addClass('output_error');
449 }
449 }
450 this._safe_append(toinsert);
450 this._safe_append(toinsert);
451 }
451 }
452 };
452 };
453
453
454
454
455 OutputArea.prototype.append_stream = function (json) {
455 OutputArea.prototype.append_stream = function (json) {
456 var text = json.data;
456 var text = json.data;
457 var subclass = "output_"+json.name;
457 var subclass = "output_"+json.name;
458 if (this.outputs.length > 0){
458 if (this.outputs.length > 0){
459 // have at least one output to consider
459 // have at least one output to consider
460 var last = this.outputs[this.outputs.length-1];
460 var last = this.outputs[this.outputs.length-1];
461 if (last.output_type == 'stream' && json.name == last.name){
461 if (last.output_type == 'stream' && json.name == last.name){
462 // latest output was in the same stream,
462 // latest output was in the same stream,
463 // so append directly into its pre tag
463 // so append directly into its pre tag
464 // escape ANSI & HTML specials:
464 // escape ANSI & HTML specials:
465 last.data = utils.fixCarriageReturn(last.data + json.data);
465 last.data = utils.fixCarriageReturn(last.data + json.data);
466 var pre = this.element.find('div.'+subclass).last().find('pre');
466 var pre = this.element.find('div.'+subclass).last().find('pre');
467 var html = utils.fixConsole(last.data);
467 var html = utils.fixConsole(last.data);
468 // The only user content injected with this HTML call is
468 // The only user content injected with this HTML call is
469 // escaped by the fixConsole() method.
469 // escaped by the fixConsole() method.
470 pre.html(html);
470 pre.html(html);
471 // return false signals that we merged this output with the previous one,
471 // return false signals that we merged this output with the previous one,
472 // and the new output shouldn't be recorded.
472 // and the new output shouldn't be recorded.
473 return false;
473 return false;
474 }
474 }
475 }
475 }
476
476
477 if (!text.replace("\r", "")) {
477 if (!text.replace("\r", "")) {
478 // text is nothing (empty string, \r, etc.)
478 // text is nothing (empty string, \r, etc.)
479 // so don't append any elements, which might add undesirable space
479 // so don't append any elements, which might add undesirable space
480 // return true to indicate the output should be recorded.
480 // return true to indicate the output should be recorded.
481 return true;
481 return true;
482 }
482 }
483
483
484 // If we got here, attach a new div
484 // If we got here, attach a new div
485 var toinsert = this.create_output_area();
485 var toinsert = this.create_output_area();
486 var append_text = OutputArea.append_map['text/plain'];
486 var append_text = OutputArea.append_map['text/plain'];
487 if (append_text) {
487 if (append_text) {
488 append_text.apply(this, [text, {}, toinsert]).addClass("output_stream " + subclass);
488 append_text.apply(this, [text, {}, toinsert]).addClass("output_stream " + subclass);
489 }
489 }
490 this._safe_append(toinsert);
490 this._safe_append(toinsert);
491 return true;
491 return true;
492 };
492 };
493
493
494
494
495 OutputArea.prototype.append_display_data = function (json, handle_inserted) {
495 OutputArea.prototype.append_display_data = function (json, handle_inserted) {
496 var toinsert = this.create_output_area();
496 var toinsert = this.create_output_area();
497 if (this.append_mime_type(json, toinsert, handle_inserted)) {
497 if (this.append_mime_type(json, toinsert, handle_inserted)) {
498 this._safe_append(toinsert);
498 this._safe_append(toinsert);
499 // If we just output latex, typeset it.
499 // If we just output latex, typeset it.
500 if ((json['text/latex'] !== undefined) ||
500 if ((json['text/latex'] !== undefined) ||
501 (json['text/html'] !== undefined) ||
501 (json['text/html'] !== undefined) ||
502 (json['text/markdown'] !== undefined)) {
502 (json['text/markdown'] !== undefined)) {
503 this.typeset();
503 this.typeset();
504 }
504 }
505 }
505 }
506 };
506 };
507
507
508
508
509 OutputArea.safe_outputs = {
509 OutputArea.safe_outputs = {
510 'text/plain' : true,
510 'text/plain' : true,
511 'text/latex' : true,
511 'text/latex' : true,
512 'image/png' : true,
512 'image/png' : true,
513 'image/jpeg' : true
513 'image/jpeg' : true
514 };
514 };
515
515
516 OutputArea.prototype.append_mime_type = function (json, element, handle_inserted) {
516 OutputArea.prototype.append_mime_type = function (json, element, handle_inserted) {
517 for (var i=0; i < OutputArea.display_order.length; i++) {
517 for (var i=0; i < OutputArea.display_order.length; i++) {
518 var type = OutputArea.display_order[i];
518 var type = OutputArea.display_order[i];
519 var append = OutputArea.append_map[type];
519 var append = OutputArea.append_map[type];
520 if ((json[type] !== undefined) && append) {
520 if ((json[type] !== undefined) && append) {
521 var value = json[type];
521 var value = json[type];
522 if (!this.trusted && !OutputArea.safe_outputs[type]) {
522 if (!this.trusted && !OutputArea.safe_outputs[type]) {
523 // not trusted, sanitize HTML
523 // not trusted, sanitize HTML
524 if (type==='text/html' || type==='text/svg') {
524 if (type==='text/html' || type==='text/svg') {
525 value = security.sanitize_html(value);
525 value = security.sanitize_html(value);
526 } else {
526 } else {
527 // don't display if we don't know how to sanitize it
527 // don't display if we don't know how to sanitize it
528 console.log("Ignoring untrusted " + type + " output.");
528 console.log("Ignoring untrusted " + type + " output.");
529 continue;
529 continue;
530 }
530 }
531 }
531 }
532 var md = json.metadata || {};
532 var md = json.metadata || {};
533 var toinsert = append.apply(this, [value, md, element, handle_inserted]);
533 var toinsert = append.apply(this, [value, md, element, handle_inserted]);
534 // Since only the png and jpeg mime types call the inserted
534 // Since only the png and jpeg mime types call the inserted
535 // callback, if the mime type is something other we must call the
535 // callback, if the mime type is something other we must call the
536 // inserted callback only when the element is actually inserted
536 // inserted callback only when the element is actually inserted
537 // into the DOM. Use a timeout of 0 to do this.
537 // into the DOM. Use a timeout of 0 to do this.
538 if (['image/png', 'image/jpeg'].indexOf(type) < 0 && handle_inserted !== undefined) {
538 if (['image/png', 'image/jpeg'].indexOf(type) < 0 && handle_inserted !== undefined) {
539 setTimeout(handle_inserted, 0);
539 setTimeout(handle_inserted, 0);
540 }
540 }
541 this.events.trigger('output_appended.OutputArea', [type, value, md, toinsert]);
541 this.events.trigger('output_appended.OutputArea', [type, value, md, toinsert]);
542 return toinsert;
542 return toinsert;
543 }
543 }
544 }
544 }
545 return null;
545 return null;
546 };
546 };
547
547
548
548
549 var append_html = function (html, md, element) {
549 var append_html = function (html, md, element) {
550 var type = 'text/html';
550 var type = 'text/html';
551 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
551 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
552 this.keyboard_manager.register_events(toinsert);
552 this.keyboard_manager.register_events(toinsert);
553 toinsert.append(html);
553 toinsert.append(html);
554 element.append(toinsert);
554 element.append(toinsert);
555 return toinsert;
555 return toinsert;
556 };
556 };
557
557
558
558
559 var append_markdown = function(markdown, md, element) {
559 var append_markdown = function(markdown, md, element) {
560 var type = 'text/markdown';
560 var type = 'text/markdown';
561 var toinsert = this.create_output_subarea(md, "output_markdown", type);
561 var toinsert = this.create_output_subarea(md, "output_markdown", type);
562 var text_and_math = mathjaxutils.remove_math(markdown);
562 var text_and_math = mathjaxutils.remove_math(markdown);
563 var text = text_and_math[0];
563 var text = text_and_math[0];
564 var math = text_and_math[1];
564 var math = text_and_math[1];
565 var html = marked.parser(marked.lexer(text));
565 var html = marked.parser(marked.lexer(text));
566 html = mathjaxutils.replace_math(html, math);
566 html = mathjaxutils.replace_math(html, math);
567 toinsert.append(html);
567 toinsert.append(html);
568 element.append(toinsert);
568 element.append(toinsert);
569 return toinsert;
569 return toinsert;
570 };
570 };
571
571
572
572
573 var append_javascript = function (js, md, element) {
573 var append_javascript = function (js, md, element) {
574 // We just eval the JS code, element appears in the local scope.
574 // We just eval the JS code, element appears in the local scope.
575 var type = 'application/javascript';
575 var type = 'application/javascript';
576 var toinsert = this.create_output_subarea(md, "output_javascript", type);
576 var toinsert = this.create_output_subarea(md, "output_javascript", type);
577 this.keyboard_manager.register_events(toinsert);
577 this.keyboard_manager.register_events(toinsert);
578 element.append(toinsert);
578 element.append(toinsert);
579
579
580 // Fix for ipython/issues/5293, make sure `element` is the area which
580 // Fix for ipython/issues/5293, make sure `element` is the area which
581 // output can be inserted into at the time of JS execution.
581 // output can be inserted into at the time of JS execution.
582 element = toinsert;
582 element = toinsert;
583 try {
583 try {
584 eval(js);
584 eval(js);
585 } catch(err) {
585 } catch(err) {
586 console.log(err);
586 console.log(err);
587 this._append_javascript_error(err, toinsert);
587 this._append_javascript_error(err, toinsert);
588 }
588 }
589 return toinsert;
589 return toinsert;
590 };
590 };
591
591
592
592
593 var append_text = function (data, md, element) {
593 var append_text = function (data, md, element) {
594 var type = 'text/plain';
594 var type = 'text/plain';
595 var toinsert = this.create_output_subarea(md, "output_text", type);
595 var toinsert = this.create_output_subarea(md, "output_text", type);
596 // escape ANSI & HTML specials in plaintext:
596 // escape ANSI & HTML specials in plaintext:
597 data = utils.fixConsole(data);
597 data = utils.fixConsole(data);
598 data = utils.fixCarriageReturn(data);
598 data = utils.fixCarriageReturn(data);
599 data = utils.autoLinkUrls(data);
599 data = utils.autoLinkUrls(data);
600 // The only user content injected with this HTML call is
600 // The only user content injected with this HTML call is
601 // escaped by the fixConsole() method.
601 // escaped by the fixConsole() method.
602 toinsert.append($("<pre/>").html(data));
602 toinsert.append($("<pre/>").html(data));
603 element.append(toinsert);
603 element.append(toinsert);
604 return toinsert;
604 return toinsert;
605 };
605 };
606
606
607
607
608 var append_svg = function (svg_html, md, element) {
608 var append_svg = function (svg_html, md, element) {
609 var type = 'image/svg+xml';
609 var type = 'image/svg+xml';
610 var toinsert = this.create_output_subarea(md, "output_svg", type);
610 var toinsert = this.create_output_subarea(md, "output_svg", type);
611
611
612 // Get the svg element from within the HTML.
612 // Get the svg element from within the HTML.
613 var svg = $('<div />').html(svg_html).find('svg');
613 var svg = $('<div />').html(svg_html).find('svg');
614 var svg_area = $('<div />');
614 var svg_area = $('<div />');
615 var width = svg.attr('width');
615 var width = svg.attr('width');
616 var height = svg.attr('height');
616 var height = svg.attr('height');
617 svg
617 svg
618 .width('100%')
618 .width('100%')
619 .height('100%');
619 .height('100%');
620 svg_area
620 svg_area
621 .width(width)
621 .width(width)
622 .height(height);
622 .height(height);
623
623
624 // The jQuery resize handlers don't seem to work on the svg element.
624 // The jQuery resize handlers don't seem to work on the svg element.
625 // When the svg renders completely, measure it's size and set the parent
625 // When the svg renders completely, measure it's size and set the parent
626 // div to that size. Then set the svg to 100% the size of the parent
626 // div to that size. Then set the svg to 100% the size of the parent
627 // div and make the parent div resizable.
627 // div and make the parent div resizable.
628 this._dblclick_to_reset_size(svg_area, true, false);
628 this._dblclick_to_reset_size(svg_area, true, false);
629
629
630 svg_area.append(svg);
630 svg_area.append(svg);
631 toinsert.append(svg_area);
631 toinsert.append(svg_area);
632 element.append(toinsert);
632 element.append(toinsert);
633
633
634 return toinsert;
634 return toinsert;
635 };
635 };
636
636
637 OutputArea.prototype._dblclick_to_reset_size = function (img, immediately, resize_parent) {
637 OutputArea.prototype._dblclick_to_reset_size = function (img, immediately, resize_parent) {
638 // Add a resize handler to an element
638 // Add a resize handler to an element
639 //
639 //
640 // img: jQuery element
640 // img: jQuery element
641 // immediately: bool=False
641 // immediately: bool=False
642 // Wait for the element to load before creating the handle.
642 // Wait for the element to load before creating the handle.
643 // resize_parent: bool=True
643 // resize_parent: bool=True
644 // Should the parent of the element be resized when the element is
644 // Should the parent of the element be resized when the element is
645 // reset (by double click).
645 // reset (by double click).
646 var callback = function (){
646 var callback = function (){
647 var h0 = img.height();
647 var h0 = img.height();
648 var w0 = img.width();
648 var w0 = img.width();
649 if (!(h0 && w0)) {
649 if (!(h0 && w0)) {
650 // zero size, don't make it resizable
650 // zero size, don't make it resizable
651 return;
651 return;
652 }
652 }
653 img.resizable({
653 img.resizable({
654 aspectRatio: true,
654 aspectRatio: true,
655 autoHide: true
655 autoHide: true
656 });
656 });
657 img.dblclick(function () {
657 img.dblclick(function () {
658 // resize wrapper & image together for some reason:
658 // resize wrapper & image together for some reason:
659 img.height(h0);
659 img.height(h0);
660 img.width(w0);
660 img.width(w0);
661 if (resize_parent === undefined || resize_parent) {
661 if (resize_parent === undefined || resize_parent) {
662 img.parent().height(h0);
662 img.parent().height(h0);
663 img.parent().width(w0);
663 img.parent().width(w0);
664 }
664 }
665 });
665 });
666 };
666 };
667
667
668 if (immediately) {
668 if (immediately) {
669 callback();
669 callback();
670 } else {
670 } else {
671 img.on("load", callback);
671 img.on("load", callback);
672 }
672 }
673 };
673 };
674
674
675 var set_width_height = function (img, md, mime) {
675 var set_width_height = function (img, md, mime) {
676 // set width and height of an img element from metadata
676 // set width and height of an img element from metadata
677 var height = _get_metadata_key(md, 'height', mime);
677 var height = _get_metadata_key(md, 'height', mime);
678 if (height !== undefined) img.attr('height', height);
678 if (height !== undefined) img.attr('height', height);
679 var width = _get_metadata_key(md, 'width', mime);
679 var width = _get_metadata_key(md, 'width', mime);
680 if (width !== undefined) img.attr('width', width);
680 if (width !== undefined) img.attr('width', width);
681 };
681 };
682
682
683 var append_png = function (png, md, element, handle_inserted) {
683 var append_png = function (png, md, element, handle_inserted) {
684 var type = 'image/png';
684 var type = 'image/png';
685 var toinsert = this.create_output_subarea(md, "output_png", type);
685 var toinsert = this.create_output_subarea(md, "output_png", type);
686 var img = $("<img/>");
686 var img = $("<img/>");
687 if (handle_inserted !== undefined) {
687 if (handle_inserted !== undefined) {
688 img.on('load', function(){
688 img.on('load', function(){
689 handle_inserted(img);
689 handle_inserted(img);
690 });
690 });
691 }
691 }
692 img[0].src = 'data:image/png;base64,'+ png;
692 img[0].src = 'data:image/png;base64,'+ png;
693 set_width_height(img, md, 'image/png');
693 set_width_height(img, md, 'image/png');
694 this._dblclick_to_reset_size(img);
694 this._dblclick_to_reset_size(img);
695 toinsert.append(img);
695 toinsert.append(img);
696 element.append(toinsert);
696 element.append(toinsert);
697 return toinsert;
697 return toinsert;
698 };
698 };
699
699
700
700
701 var append_jpeg = function (jpeg, md, element, handle_inserted) {
701 var append_jpeg = function (jpeg, md, element, handle_inserted) {
702 var type = 'image/jpeg';
702 var type = 'image/jpeg';
703 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
703 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
704 var img = $("<img/>");
704 var img = $("<img/>");
705 if (handle_inserted !== undefined) {
705 if (handle_inserted !== undefined) {
706 img.on('load', function(){
706 img.on('load', function(){
707 handle_inserted(img);
707 handle_inserted(img);
708 });
708 });
709 }
709 }
710 img[0].src = 'data:image/jpeg;base64,'+ jpeg;
710 img[0].src = 'data:image/jpeg;base64,'+ jpeg;
711 set_width_height(img, md, 'image/jpeg');
711 set_width_height(img, md, 'image/jpeg');
712 this._dblclick_to_reset_size(img);
712 this._dblclick_to_reset_size(img);
713 toinsert.append(img);
713 toinsert.append(img);
714 element.append(toinsert);
714 element.append(toinsert);
715 return toinsert;
715 return toinsert;
716 };
716 };
717
717
718
718
719 var append_pdf = function (pdf, md, element) {
719 var append_pdf = function (pdf, md, element) {
720 var type = 'application/pdf';
720 var type = 'application/pdf';
721 var toinsert = this.create_output_subarea(md, "output_pdf", type);
721 var toinsert = this.create_output_subarea(md, "output_pdf", type);
722 var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf);
722 var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf);
723 a.attr('target', '_blank');
723 a.attr('target', '_blank');
724 a.text('View PDF')
724 a.text('View PDF')
725 toinsert.append(a);
725 toinsert.append(a);
726 element.append(toinsert);
726 element.append(toinsert);
727 return toinsert;
727 return toinsert;
728 }
728 }
729
729
730 var append_latex = function (latex, md, element) {
730 var append_latex = function (latex, md, element) {
731 // This method cannot do the typesetting because the latex first has to
731 // This method cannot do the typesetting because the latex first has to
732 // be on the page.
732 // be on the page.
733 var type = 'text/latex';
733 var type = 'text/latex';
734 var toinsert = this.create_output_subarea(md, "output_latex", type);
734 var toinsert = this.create_output_subarea(md, "output_latex", type);
735 toinsert.append(latex);
735 toinsert.append(latex);
736 element.append(toinsert);
736 element.append(toinsert);
737 return toinsert;
737 return toinsert;
738 };
738 };
739
739
740
740
741 OutputArea.prototype.append_raw_input = function (msg) {
741 OutputArea.prototype.append_raw_input = function (msg) {
742 var that = this;
742 var that = this;
743 this.expand();
743 this.expand();
744 var content = msg.content;
744 var content = msg.content;
745 var area = this.create_output_area();
745 var area = this.create_output_area();
746
746
747 // disable any other raw_inputs, if they are left around
747 // disable any other raw_inputs, if they are left around
748 $("div.output_subarea.raw_input_container").remove();
748 $("div.output_subarea.raw_input_container").remove();
749
749
750 var input_type = content.password ? 'password' : 'text';
750 var input_type = content.password ? 'password' : 'text';
751
751
752 area.append(
752 area.append(
753 $("<div/>")
753 $("<div/>")
754 .addClass("box-flex1 output_subarea raw_input_container")
754 .addClass("box-flex1 output_subarea raw_input_container")
755 .append(
755 .append(
756 $("<span/>")
756 $("<span/>")
757 .addClass("raw_input_prompt")
757 .addClass("raw_input_prompt")
758 .text(content.prompt)
758 .text(content.prompt)
759 )
759 )
760 .append(
760 .append(
761 $("<input/>")
761 $("<input/>")
762 .addClass("raw_input")
762 .addClass("raw_input")
763 .attr('type', input_type)
763 .attr('type', input_type)
764 .attr("size", 47)
764 .attr("size", 47)
765 .keydown(function (event, ui) {
765 .keydown(function (event, ui) {
766 // make sure we submit on enter,
766 // make sure we submit on enter,
767 // and don't re-execute the *cell* on shift-enter
767 // and don't re-execute the *cell* on shift-enter
768 if (event.which === keyboard.keycodes.enter) {
768 if (event.which === keyboard.keycodes.enter) {
769 that._submit_raw_input();
769 that._submit_raw_input();
770 return false;
770 return false;
771 }
771 }
772 })
772 })
773 )
773 )
774 );
774 );
775
775
776 this.element.append(area);
776 this.element.append(area);
777 var raw_input = area.find('input.raw_input');
777 var raw_input = area.find('input.raw_input');
778 // Register events that enable/disable the keyboard manager while raw
778 // Register events that enable/disable the keyboard manager while raw
779 // input is focused.
779 // input is focused.
780 this.keyboard_manager.register_events(raw_input);
780 this.keyboard_manager.register_events(raw_input);
781 // Note, the following line used to read raw_input.focus().focus().
781 // Note, the following line used to read raw_input.focus().focus().
782 // This seemed to be needed otherwise only the cell would be focused.
782 // This seemed to be needed otherwise only the cell would be focused.
783 // But with the modal UI, this seems to work fine with one call to focus().
783 // But with the modal UI, this seems to work fine with one call to focus().
784 raw_input.focus();
784 raw_input.focus();
785 }
785 }
786
786
787 OutputArea.prototype._submit_raw_input = function (evt) {
787 OutputArea.prototype._submit_raw_input = function (evt) {
788 var container = this.element.find("div.raw_input_container");
788 var container = this.element.find("div.raw_input_container");
789 var theprompt = container.find("span.raw_input_prompt");
789 var theprompt = container.find("span.raw_input_prompt");
790 var theinput = container.find("input.raw_input");
790 var theinput = container.find("input.raw_input");
791 var value = theinput.val();
791 var value = theinput.val();
792 var echo = value;
792 var echo = value;
793 // don't echo if it's a password
793 // don't echo if it's a password
794 if (theinput.attr('type') == 'password') {
794 if (theinput.attr('type') == 'password') {
795 echo = '········';
795 echo = '········';
796 }
796 }
797 var content = {
797 var content = {
798 output_type : 'stream',
798 output_type : 'stream',
799 stream : 'stdout',
799 stream : 'stdout',
800 text : theprompt.text() + echo + '\n'
800 text : theprompt.text() + echo + '\n'
801 }
801 }
802 // remove form container
802 // remove form container
803 container.parent().remove();
803 container.parent().remove();
804 // replace with plaintext version in stdout
804 // replace with plaintext version in stdout
805 this.append_output(content, false);
805 this.append_output(content, false);
806 this.events.trigger('send_input_reply.Kernel', value);
806 this.events.trigger('send_input_reply.Kernel', value);
807 }
807 }
808
808
809
809
810 OutputArea.prototype.handle_clear_output = function (msg) {
810 OutputArea.prototype.handle_clear_output = function (msg) {
811 // msg spec v4 had stdout, stderr, display keys
811 // msg spec v4 had stdout, stderr, display keys
812 // v4.1 replaced these with just wait
812 // v4.1 replaced these with just wait
813 // The default behavior is the same (stdout=stderr=display=True, wait=False),
813 // The default behavior is the same (stdout=stderr=display=True, wait=False),
814 // so v4 messages will still be properly handled,
814 // so v4 messages will still be properly handled,
815 // except for the rarely used clearing less than all output.
815 // except for the rarely used clearing less than all output.
816 this.clear_output(msg.content.wait || false);
816 this.clear_output(msg.content.wait || false);
817 };
817 };
818
818
819
819
820 OutputArea.prototype.clear_output = function(wait) {
820 OutputArea.prototype.clear_output = function(wait) {
821 if (wait) {
821 if (wait) {
822
822
823 // If a clear is queued, clear before adding another to the queue.
823 // If a clear is queued, clear before adding another to the queue.
824 if (this.clear_queued) {
824 if (this.clear_queued) {
825 this.clear_output(false);
825 this.clear_output(false);
826 };
826 };
827
827
828 this.clear_queued = true;
828 this.clear_queued = true;
829 } else {
829 } else {
830
830
831 // Fix the output div's height if the clear_output is waiting for
831 // Fix the output div's height if the clear_output is waiting for
832 // new output (it is being used in an animation).
832 // new output (it is being used in an animation).
833 if (this.clear_queued) {
833 if (this.clear_queued) {
834 var height = this.element.height();
834 var height = this.element.height();
835 this.element.height(height);
835 this.element.height(height);
836 this.clear_queued = false;
836 this.clear_queued = false;
837 }
837 }
838
838
839 // Clear all
839 // Clear all
840 // Remove load event handlers from img tags because we don't want
840 // Remove load event handlers from img tags because we don't want
841 // them to fire if the image is never added to the page.
841 // them to fire if the image is never added to the page.
842 this.element.find('img').off('load');
842 this.element.find('img').off('load');
843 this.element.html("");
843 this.element.html("");
844 this.outputs = [];
844 this.outputs = [];
845 this.trusted = true;
845 this.trusted = true;
846 this.unscroll_area();
846 this.unscroll_area();
847 return;
847 return;
848 };
848 };
849 };
849 };
850
850
851
851
852 // JSON serialization
852 // JSON serialization
853
853
854 OutputArea.prototype.fromJSON = function (outputs, metadata) {
854 OutputArea.prototype.fromJSON = function (outputs, metadata) {
855 var len = outputs.length;
855 var len = outputs.length;
856 metadata = metadata || {};
856 metadata = metadata || {};
857
857
858 for (var i=0; i<len; i++) {
858 for (var i=0; i<len; i++) {
859 this.append_output(outputs[i]);
859 this.append_output(outputs[i]);
860 }
860 }
861
861
862 if (metadata.collapsed !== undefined) {
862 if (metadata.collapsed !== undefined) {
863 this.collapsed = metadata.collapsed;
863 this.collapsed = metadata.collapsed;
864 if (metadata.collapsed) {
864 if (metadata.collapsed) {
865 this.collapse_output();
865 this.collapse_output();
866 }
866 }
867 }
867 }
868 if (metadata.autoscroll !== undefined) {
868 if (metadata.autoscroll !== undefined) {
869 this.collapsed = metadata.collapsed;
869 this.collapsed = metadata.collapsed;
870 if (metadata.collapsed) {
870 if (metadata.collapsed) {
871 this.collapse_output();
871 this.collapse_output();
872 } else {
872 } else {
873 this.expand_output();
873 this.expand_output();
874 }
874 }
875 }
875 }
876 };
876 };
877
877
878
878
879 OutputArea.prototype.toJSON = function () {
879 OutputArea.prototype.toJSON = function () {
880 return this.outputs;
880 return this.outputs;
881 };
881 };
882
882
883 /**
883 /**
884 * Class properties
884 * Class properties
885 **/
885 **/
886
886
887 /**
887 /**
888 * Threshold to trigger autoscroll when the OutputArea is resized,
888 * Threshold to trigger autoscroll when the OutputArea is resized,
889 * typically when new outputs are added.
889 * typically when new outputs are added.
890 *
890 *
891 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
891 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
892 * unless it is < 0, in which case autoscroll will never be triggered
892 * unless it is < 0, in which case autoscroll will never be triggered
893 *
893 *
894 * @property auto_scroll_threshold
894 * @property auto_scroll_threshold
895 * @type Number
895 * @type Number
896 * @default 100
896 * @default 100
897 *
897 *
898 **/
898 **/
899 OutputArea.auto_scroll_threshold = 100;
899 OutputArea.auto_scroll_threshold = 100;
900
900
901 /**
901 /**
902 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
902 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
903 * shorter than this are never scrolled.
903 * shorter than this are never scrolled.
904 *
904 *
905 * @property minimum_scroll_threshold
905 * @property minimum_scroll_threshold
906 * @type Number
906 * @type Number
907 * @default 20
907 * @default 20
908 *
908 *
909 **/
909 **/
910 OutputArea.minimum_scroll_threshold = 20;
910 OutputArea.minimum_scroll_threshold = 20;
911
911
912
912
913 OutputArea.display_order = [
913 OutputArea.display_order = [
914 'application/javascript',
914 'application/javascript',
915 'text/html',
915 'text/html',
916 'text/markdown',
916 'text/markdown',
917 'text/latex',
917 'text/latex',
918 'image/svg+xml',
918 'image/svg+xml',
919 'image/png',
919 'image/png',
920 'image/jpeg',
920 'image/jpeg',
921 'application/pdf',
921 'application/pdf',
922 'text/plain'
922 'text/plain'
923 ];
923 ];
924
924
925 OutputArea.append_map = {
925 OutputArea.append_map = {
926 "text/plain" : append_text,
926 "text/plain" : append_text,
927 "text/html" : append_html,
927 "text/html" : append_html,
928 "text/markdown": append_markdown,
928 "text/markdown": append_markdown,
929 "image/svg+xml" : append_svg,
929 "image/svg+xml" : append_svg,
930 "image/png" : append_png,
930 "image/png" : append_png,
931 "image/jpeg" : append_jpeg,
931 "image/jpeg" : append_jpeg,
932 "text/latex" : append_latex,
932 "text/latex" : append_latex,
933 "application/javascript" : append_javascript,
933 "application/javascript" : append_javascript,
934 "application/pdf" : append_pdf
934 "application/pdf" : append_pdf
935 };
935 };
936
936
937 // For backwards compatability.
937 // For backwards compatability.
938 IPython.OutputArea = OutputArea;
938 IPython.OutputArea = OutputArea;
939
939
940 return {'OutputArea': OutputArea};
940 return {'OutputArea': OutputArea};
941 });
941 });
@@ -1,23 +1,23 b''
1 //
1 //
2 // Test robustness about JS injection in different place
2 // Test robustness about JS injection in different place
3 //
3 //
4 // This assume malicious document arrive to the frontend.
4 // This assume malicious document arrive to the frontend.
5 //
5 //
6
6
7 casper.notebook_test(function () {
7 casper.notebook_test(function () {
8 var messages = [];
8 var messages = [];
9 this.on('remote.alert', function (msg) {
9 this.on('remote.alert', function (msg) {
10 messages.push(msg);
10 messages.push(msg);
11 });
11 });
12
12
13 this.evaluate(function () {
13 this.evaluate(function () {
14 var cell = IPython.notebook.get_cell(0);
14 var cell = IPython.notebook.get_cell(0);
15 var json = cell.toJSON();
15 var json = cell.toJSON();
16 json.prompt_number = "<script> alert('hello from input prompts !')</script>";
16 json.execution_count = "<script> alert('hello from input prompts !')</script>";
17 cell.fromJSON(json);
17 cell.fromJSON(json);
18 });
18 });
19
19
20 this.then(function () {
20 this.then(function () {
21 this.test.assert(messages.length == 0, "Captured log message from script tag injection !");
21 this.test.assert(messages.length == 0, "Captured log message from script tag injection !");
22 });
22 });
23 });
23 });
@@ -1,168 +1,168 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "heading",
4 "cell_type": "heading",
5 "level": 1,
5 "level": 1,
6 "metadata": {},
6 "metadata": {},
7 "source": [
7 "source": [
8 "NumPy and Matplotlib examples"
8 "NumPy and Matplotlib examples"
9 ]
9 ]
10 },
10 },
11 {
11 {
12 "cell_type": "markdown",
12 "cell_type": "markdown",
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "First import NumPy and Matplotlib:"
15 "First import NumPy and Matplotlib:"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "code",
19 "cell_type": "code",
20 "execution_count": 1,
20 "metadata": {
21 "metadata": {
21 "collapsed": false
22 "collapsed": false
22 },
23 },
23 "outputs": [
24 "outputs": [
24 {
25 {
25 "metadata": {},
26 "metadata": {},
26 "name": "stdout",
27 "name": "stdout",
27 "output_type": "stream",
28 "output_type": "stream",
28 "text": "\nWelcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline].\nFor more information, type 'help(pylab)'.\n"
29 "text": "\nWelcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline].\nFor more information, type 'help(pylab)'.\n"
29 }
30 }
30 ],
31 ],
31 "prompt_number": 1,
32 "source": [
32 "source": [
33 "%pylab inline"
33 "%pylab inline"
34 ]
34 ]
35 },
35 },
36 {
36 {
37 "cell_type": "code",
37 "cell_type": "code",
38 "execution_count": 2,
38 "metadata": {
39 "metadata": {
39 "collapsed": false
40 "collapsed": false
40 },
41 },
41 "outputs": [],
42 "outputs": [],
42 "prompt_number": 2,
43 "source": [
43 "source": [
44 "import numpy as np"
44 "import numpy as np"
45 ]
45 ]
46 },
46 },
47 {
47 {
48 "cell_type": "markdown",
48 "cell_type": "markdown",
49 "metadata": {},
49 "metadata": {},
50 "source": [
50 "source": [
51 "Now we show some very basic examples of how they can be used."
51 "Now we show some very basic examples of how they can be used."
52 ]
52 ]
53 },
53 },
54 {
54 {
55 "cell_type": "code",
55 "cell_type": "code",
56 "execution_count": 6,
56 "metadata": {
57 "metadata": {
57 "collapsed": false
58 "collapsed": false
58 },
59 },
59 "outputs": [],
60 "outputs": [],
60 "prompt_number": 6,
61 "source": [
61 "source": [
62 "a = np.random.uniform(size=(100,100))"
62 "a = np.random.uniform(size=(100,100))"
63 ]
63 ]
64 },
64 },
65 {
65 {
66 "cell_type": "code",
66 "cell_type": "code",
67 "execution_count": 7,
67 "metadata": {
68 "metadata": {
68 "collapsed": false
69 "collapsed": false
69 },
70 },
70 "outputs": [
71 "outputs": [
71 {
72 {
73 "execution_count": 7,
72 "metadata": {},
74 "metadata": {},
73 "output_type": "execute_result",
75 "output_type": "execute_result",
74 "prompt_number": 7,
75 "text/plain": [
76 "text/plain": [
76 "(100, 100)"
77 "(100, 100)"
77 ]
78 ]
78 }
79 }
79 ],
80 ],
80 "prompt_number": 7,
81 "source": [
81 "source": [
82 "a.shape"
82 "a.shape"
83 ]
83 ]
84 },
84 },
85 {
85 {
86 "cell_type": "code",
86 "cell_type": "code",
87 "execution_count": 8,
87 "metadata": {
88 "metadata": {
88 "collapsed": false
89 "collapsed": false
89 },
90 },
90 "outputs": [],
91 "outputs": [],
91 "prompt_number": 8,
92 "source": [
92 "source": [
93 "evs = np.linalg.eigvals(a)"
93 "evs = np.linalg.eigvals(a)"
94 ]
94 ]
95 },
95 },
96 {
96 {
97 "cell_type": "code",
97 "cell_type": "code",
98 "execution_count": 10,
98 "metadata": {
99 "metadata": {
99 "collapsed": false
100 "collapsed": false
100 },
101 },
101 "outputs": [
102 "outputs": [
102 {
103 {
104 "execution_count": 10,
103 "metadata": {},
105 "metadata": {},
104 "output_type": "execute_result",
106 "output_type": "execute_result",
105 "prompt_number": 10,
106 "text/plain": [
107 "text/plain": [
107 "(100,)"
108 "(100,)"
108 ]
109 ]
109 }
110 }
110 ],
111 ],
111 "prompt_number": 10,
112 "source": [
112 "source": [
113 "evs.shape"
113 "evs.shape"
114 ]
114 ]
115 },
115 },
116 {
116 {
117 "cell_type": "markdown",
117 "cell_type": "markdown",
118 "metadata": {},
118 "metadata": {},
119 "source": [
119 "source": [
120 "Here is a cell that has both text and PNG output:"
120 "Here is a cell that has both text and PNG output:"
121 ]
121 ]
122 },
122 },
123 {
123 {
124 "cell_type": "code",
124 "cell_type": "code",
125 "execution_count": 14,
125 "metadata": {
126 "metadata": {
126 "collapsed": false
127 "collapsed": false
127 },
128 },
128 "outputs": [
129 "outputs": [
129 {
130 {
131 "execution_count": 14,
130 "metadata": {},
132 "metadata": {},
131 "output_type": "execute_result",
133 "output_type": "execute_result",
132 "prompt_number": 14,
133 "text/plain": [
134 "text/plain": [
134 "(array([95, 4, 0, 0, 0, 0, 0, 0, 0, 1]),\n",
135 "(array([95, 4, 0, 0, 0, 0, 0, 0, 0, 1]),\n",
135 " array([ -2.93566063, 2.35937011, 7.65440086, 12.9494316 ,\n",
136 " array([ -2.93566063, 2.35937011, 7.65440086, 12.9494316 ,\n",
136 " 18.24446235, 23.53949309, 28.83452384, 34.12955458,\n",
137 " 18.24446235, 23.53949309, 28.83452384, 34.12955458,\n",
137 " 39.42458533, 44.71961607, 50.01464682]),\n",
138 " 39.42458533, 44.71961607, 50.01464682]),\n",
138 " <a list of 10 Patch objects>)"
139 " <a list of 10 Patch objects>)"
139 ]
140 ]
140 },
141 },
141 {
142 {
142 "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAD9CAYAAAC2l2x5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEhdJREFUeJzt3X1olfX/x/HXtVbT8CZDmsK6KmrubEu3U2xnZOpxLBnG\nOqsIE7RoE3QRZkT/yEAjcIh/LIs6i/BEGSU1CkxT0+pkFp1zMmsxZ5uUTIXoxm95lmdlef3+8Nep\ndbtz7exs16fnAw7sXNs5n/c14nmurl3naDmO4wgAYJy8sR4AADA6CDwAGIrAA4ChCDwAGIrAA4Ch\nCDwAGOofA9/U1KTCwkLNnj07vS2ZTCoUCsm2bTU2NmpgYCD9vccee0zFxcUqKyvTgQMHRm9qAMC/\n+sfA33PPPdq9e/eQbeFwWLZtq6+vT0VFRero6JAkffXVV3ryySf15ptvKhwOa/Xq1aM3NQDgX/1j\n4OfNm6dp06YN2RaPx9Xc3KyCggI1NTUpFotJkmKxmOrr62XbthYsWCDHcZRMJkdvcgDAP8r4HHwi\nkZDP55Mk+Xw+xeNxSecDX1pamv65kpKS9PcAALmXn+kDMvlkA8uyhrUNAPDvMv1kmYyP4KuqqtTT\n0yNJ6unpUVVVlSQpEAjo8OHD6Z87cuRI+nt/NaRXb+vWrRvzGZh/7Odgfu/dvDy747j7yLCMAx8I\nBBSJRJRKpRSJRFRTUyNJqq6u1p49e9Tf369oNKq8vDxNnjzZ1VAAgJH7x8AvXbpUN9xwg3p7e3X5\n5ZfrmWeeUUtLi/r7+1VSUqKTJ09q1apVkqTCwkK1tLSotrZW9957rzZv3pyTHQAA/DXLcXvs73ZB\ny3L9vxvjQTQaVTAYHOsxXGP+scX8Y8fLs0vu2kngAcAD3LSTjyoAAEMReAAwFIEHAEMReAAwFIEH\nAEP9ZwM/Zcqlsixr1G9Tplw61rsK4D/qP3uZ5PnPxMnFHONjfwF4G5dJAgDSCDwAGIrAA4ChCDwA\nGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrA\nA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChXAf+6aef1g03\n3KDrr79ea9askSQlk0mFQiHZtq3GxkYNDAxkbVAAQGZcBf7UqVPasGGD9u7dq0Qiod7eXu3Zs0fh\ncFi2bauvr09FRUXq6OjI9rwAgGFyFfiJEyfKcRx9//33SqVSOnPmjC655BLF43E1NzeroKBATU1N\nisVi2Z4XADBMrgMfDod15ZVXasaMGZo7d64CgYASiYR8Pp8kyefzKR6PZ3VYAMDw5bt50Ndff62W\nlhYdPnxY06ZN0x133KEdO3bIcZxhPX79+vXpr4PBoILBoJsxAMBY0WhU0Wh0RM9hOcOt8u/s3LlT\nW7du1bZt2yRJ4XBYx44d09GjR9Xa2iq/36+DBw+qra1NnZ2dQxe0rGG/EIwmy7Ik5WKO8bG/ALzN\nTTtdnaKZN2+ePvzwQ506dUo//vijdu3apUWLFikQCCgSiSiVSikSiaimpsbN0wMAssBV4KdMmaLW\n1lbdeuutuvHGG1VRUaGFCxeqpaVF/f39Kikp0cmTJ7Vq1apszwsAGCZXp2hGtCCnaAAgYzk7RQMA\nGP8IPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEI\nPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAY\nisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYynXgf/jhB919992a\nNWuWysrKFIvFlEwmFQqFZNu2GhsbNTAwkM1ZAQAZcB34devWybZtdXV1qaurSz6fT+FwWLZtq6+v\nT0VFRero6MjmrACADLgO/L59+7R27VpNmDBB+fn5mjp1quLxuJqbm1VQUKCmpibFYrFszgoAyICr\nwJ84cUKDg4NqaWlRIBDQxo0blUqllEgk5PP5JEk+n0/xeDyrwwIAhi/fzYMGBwfV29urTZs2qa6u\nTitXrtRLL70kx3GG9fj169envw4GgwoGg27GAABjRaNRRaPRET2H5Qy3yn9QWlqqnp4eSdKuXbv0\n3HPP6aefflJra6v8fr8OHjyotrY2dXZ2Dl3Qsob9QjCaLMuSlIs5xsf+AvA2N+10fQ6+uLhYsVhM\n586d086dO1VXV6dAIKBIJKJUKqVIJKKamhq3Tw8AGCHXR/C9vb266667NDg4qLq6Oj388MM6d+6c\nli1bpkOHDum6667T888/r0mTJg1dkCN4AMiYm3a6DrxbBB4AMpfTUzQAgPGNwAOAoQg8ABiKwAOA\n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\n",
143 "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAD9CAYAAAC2l2x5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEhdJREFUeJzt3X1olfX/x/HXtVbT8CZDmsK6KmrubEu3U2xnZOpxLBnG\nOqsIE7RoE3QRZkT/yEAjcIh/LIs6i/BEGSU1CkxT0+pkFp1zMmsxZ5uUTIXoxm95lmdlef3+8Nep\ndbtz7exs16fnAw7sXNs5n/c14nmurl3naDmO4wgAYJy8sR4AADA6CDwAGIrAA4ChCDwAGIrAA4Ch\nCDwAGOofA9/U1KTCwkLNnj07vS2ZTCoUCsm2bTU2NmpgYCD9vccee0zFxcUqKyvTgQMHRm9qAMC/\n+sfA33PPPdq9e/eQbeFwWLZtq6+vT0VFRero6JAkffXVV3ryySf15ptvKhwOa/Xq1aM3NQDgX/1j\n4OfNm6dp06YN2RaPx9Xc3KyCggI1NTUpFotJkmKxmOrr62XbthYsWCDHcZRMJkdvcgDAP8r4HHwi\nkZDP55Mk+Xw+xeNxSecDX1pamv65kpKS9PcAALmXn+kDMvlkA8uyhrUNAPDvMv1kmYyP4KuqqtTT\n0yNJ6unpUVVVlSQpEAjo8OHD6Z87cuRI+nt/NaRXb+vWrRvzGZh/7Odgfu/dvDy747j7yLCMAx8I\nBBSJRJRKpRSJRFRTUyNJqq6u1p49e9Tf369oNKq8vDxNnjzZ1VAAgJH7x8AvXbpUN9xwg3p7e3X5\n5ZfrmWeeUUtLi/r7+1VSUqKTJ09q1apVkqTCwkK1tLSotrZW9957rzZv3pyTHQAA/DXLcXvs73ZB\ny3L9vxvjQTQaVTAYHOsxXGP+scX8Y8fLs0vu2kngAcAD3LSTjyoAAEMReAAwFIEHAEMReAAwFIEH\nAEP9ZwM/Zcqlsixr1G9Tplw61rsK4D/qP3uZ5PnPxMnFHONjfwF4G5dJAgDSCDwAGIrAA4ChCDwA\nGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrA\nA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChCDwAGIrAA4ChXAf+6aef1g03\n3KDrr79ea9askSQlk0mFQiHZtq3GxkYNDAxkbVAAQGZcBf7UqVPasGGD9u7dq0Qiod7eXu3Zs0fh\ncFi2bauvr09FRUXq6OjI9rwAgGFyFfiJEyfKcRx9//33SqVSOnPmjC655BLF43E1NzeroKBATU1N\nisVi2Z4XADBMrgMfDod15ZVXasaMGZo7d64CgYASiYR8Pp8kyefzKR6PZ3VYAMDw5bt50Ndff62W\nlhYdPnxY06ZN0x133KEdO3bIcZxhPX79+vXpr4PBoILBoJsxAMBY0WhU0Wh0RM9hOcOt8u/s3LlT\nW7du1bZt2yRJ4XBYx44d09GjR9Xa2iq/36+DBw+qra1NnZ2dQxe0rGG/EIwmy7Ik5WKO8bG/ALzN\nTTtdnaKZN2+ePvzwQ506dUo//vijdu3apUWLFikQCCgSiSiVSikSiaimpsbN0wMAssBV4KdMmaLW\n1lbdeuutuvHGG1VRUaGFCxeqpaVF/f39Kikp0cmTJ7Vq1apszwsAGCZXp2hGtCCnaAAgYzk7RQMA\nGP8IPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEI\nPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAY\nisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYisADgKEIPAAYynXgf/jhB919992a\nNWuWysrKFIvFlEwmFQqFZNu2GhsbNTAwkM1ZAQAZcB34devWybZtdXV1qaurSz6fT+FwWLZtq6+v\nT0VFRero6MjmrACADLgO/L59+7R27VpNmDBB+fn5mjp1quLxuJqbm1VQUKCmpibFYrFszgoAyICr\nwJ84cUKDg4NqaWlRIBDQxo0blUqllEgk5PP5JEk+n0/xeDyrwwIAhi/fzYMGBwfV29urTZs2qa6u\nTitXrtRLL70kx3GG9fj169envw4GgwoGg27GAABjRaNRRaPRET2H5Qy3yn9QWlqqnp4eSdKuXbv0\n3HPP6aefflJra6v8fr8OHjyotrY2dXZ2Dl3Qsob9QjCaLMuSlIs5xsf+AvA2N+10fQ6+uLhYsVhM\n586d086dO1VXV6dAIKBIJKJUKqVIJKKamhq3Tw8AGCHXR/C9vb266667NDg4qLq6Oj388MM6d+6c\nli1bpkOHDum6667T888/r0mTJg1dkCN4AMiYm3a6DrxbBB4AMpfTUzQAgPGNwAOAoQg8ABiKwAOA\n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\n",
143 "metadata": {},
144 "metadata": {},
144 "output_type": "display_data",
145 "output_type": "display_data",
145 "text/plain": [
146 "text/plain": [
146 "<matplotlib.figure.Figure at 0x108c8f1d0>"
147 "<matplotlib.figure.Figure at 0x108c8f1d0>"
147 ]
148 ]
148 }
149 }
149 ],
150 ],
150 "prompt_number": 14,
151 "source": [
151 "source": [
152 "hist(evs.real)"
152 "hist(evs.real)"
153 ]
153 ]
154 },
154 },
155 {
155 {
156 "cell_type": "code",
156 "cell_type": "code",
157 "execution_count": null,
157 "metadata": {
158 "metadata": {
158 "collapsed": false
159 "collapsed": false
159 },
160 },
160 "outputs": [],
161 "outputs": [],
161 "prompt_number": null,
162 "source": []
162 "source": []
163 }
163 }
164 ],
164 ],
165 "metadata": {},
165 "metadata": {},
166 "nbformat": 4,
166 "nbformat": 4,
167 "nbformat_minor": 0
167 "nbformat_minor": 0
168 } No newline at end of file
168 }
@@ -1,28 +1,20 b''
1 """Module containing a preprocessor that removes the outputs from code cells"""
1 """Module containing a preprocessor that removes the outputs from code cells"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 #-----------------------------------------------------------------------------
7 # Imports
8 #-----------------------------------------------------------------------------
9
10 from .base import Preprocessor
6 from .base import Preprocessor
11
7
12
13 #-----------------------------------------------------------------------------
14 # Classes
15 #-----------------------------------------------------------------------------
16 class ClearOutputPreprocessor(Preprocessor):
8 class ClearOutputPreprocessor(Preprocessor):
17 """
9 """
18 Removes the output from all code cells in a notebook.
10 Removes the output from all code cells in a notebook.
19 """
11 """
20
12
21 def preprocess_cell(self, cell, resources, cell_index):
13 def preprocess_cell(self, cell, resources, cell_index):
22 """
14 """
23 Apply a transformation on each cell. See base.py for details.
15 Apply a transformation on each cell. See base.py for details.
24 """
16 """
25 if cell.cell_type == 'code':
17 if cell.cell_type == 'code':
26 cell.outputs = []
18 cell.outputs = []
27 cell.prompt_number = None
19 cell.execution_count = None
28 return cell, resources
20 return cell, resources
@@ -1,114 +1,111 b''
1 """Module containing a preprocessor that removes the outputs from code cells"""
1 """Module containing a preprocessor that removes the outputs from code cells"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import os
6 import os
7 import sys
7 import sys
8
8
9 try:
9 try:
10 from queue import Empty # Py 3
10 from queue import Empty # Py 3
11 except ImportError:
11 except ImportError:
12 from Queue import Empty # Py 2
12 from Queue import Empty # Py 2
13
13
14 from IPython.utils.traitlets import List, Unicode
14 from IPython.utils.traitlets import List, Unicode
15
15
16 from IPython.nbformat.current import reads, writes, output_from_msg
16 from IPython.nbformat.current import reads, writes, output_from_msg
17 from .base import Preprocessor
17 from .base import Preprocessor
18 from IPython.utils.traitlets import Integer
18 from IPython.utils.traitlets import Integer
19
19
20 class ExecutePreprocessor(Preprocessor):
20 class ExecutePreprocessor(Preprocessor):
21 """
21 """
22 Executes all the cells in a notebook
22 Executes all the cells in a notebook
23 """
23 """
24
24
25 timeout = Integer(30, config=True,
25 timeout = Integer(30, config=True,
26 help="The time to wait (in seconds) for output from executions."
26 help="The time to wait (in seconds) for output from executions."
27 )
27 )
28
28
29 extra_arguments = List(Unicode)
29 extra_arguments = List(Unicode)
30
30
31 def preprocess(self, nb, resources):
31 def preprocess(self, nb, resources):
32 from IPython.kernel import run_kernel
32 from IPython.kernel import run_kernel
33 kernel_name = nb.metadata.get('kernelspec', {}).get('name', 'python')
33 kernel_name = nb.metadata.get('kernelspec', {}).get('name', 'python')
34 self.log.info("Executing notebook with kernel: %s" % kernel_name)
34 self.log.info("Executing notebook with kernel: %s" % kernel_name)
35 with run_kernel(kernel_name=kernel_name,
35 with run_kernel(kernel_name=kernel_name,
36 extra_arguments=self.extra_arguments,
36 extra_arguments=self.extra_arguments,
37 stderr=open(os.devnull, 'w')) as kc:
37 stderr=open(os.devnull, 'w')) as kc:
38 self.kc = kc
38 self.kc = kc
39 nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources)
39 nb, resources = super(ExecutePreprocessor, self).preprocess(nb, resources)
40 return nb, resources
40 return nb, resources
41
41
42 def preprocess_cell(self, cell, resources, cell_index):
42 def preprocess_cell(self, cell, resources, cell_index):
43 """
43 """
44 Apply a transformation on each code cell. See base.py for details.
44 Apply a transformation on each code cell. See base.py for details.
45 """
45 """
46 if cell.cell_type != 'code':
46 if cell.cell_type != 'code':
47 return cell, resources
47 return cell, resources
48 try:
48 try:
49 outputs = self.run_cell(self.kc.shell_channel, self.kc.iopub_channel, cell)
49 outputs = self.run_cell(self.kc.shell_channel, self.kc.iopub_channel, cell)
50 except Exception as e:
50 except Exception as e:
51 self.log.error("failed to run cell: " + repr(e))
51 self.log.error("failed to run cell: " + repr(e))
52 self.log.error(str(cell.source))
52 self.log.error(str(cell.source))
53 raise
53 raise
54 cell.outputs = outputs
54 cell.outputs = outputs
55 return cell, resources
55 return cell, resources
56
56
57 def run_cell(self, shell, iopub, cell):
57 def run_cell(self, shell, iopub, cell):
58 msg_id = shell.execute(cell.source)
58 msg_id = shell.execute(cell.source)
59 self.log.debug("Executing cell:\n%s", cell.source)
59 self.log.debug("Executing cell:\n%s", cell.source)
60 # wait for finish, with timeout
60 # wait for finish, with timeout
61 while True:
61 while True:
62 try:
62 try:
63 msg = shell.get_msg(timeout=self.timeout)
63 msg = shell.get_msg(timeout=self.timeout)
64 except Empty:
64 except Empty:
65 self.log.error("Timeout waiting for execute reply")
65 self.log.error("Timeout waiting for execute reply")
66 raise
66 raise
67 if msg['parent_header'].get('msg_id') == msg_id:
67 if msg['parent_header'].get('msg_id') == msg_id:
68 break
68 break
69 else:
69 else:
70 # not our reply
70 # not our reply
71 continue
71 continue
72
72
73 outs = []
73 outs = []
74
74
75 while True:
75 while True:
76 try:
76 try:
77 msg = iopub.get_msg(timeout=self.timeout)
77 msg = iopub.get_msg(timeout=self.timeout)
78 except Empty:
78 except Empty:
79 self.log.warn("Timeout waiting for IOPub output")
79 self.log.warn("Timeout waiting for IOPub output")
80 break
80 break
81 if msg['parent_header'].get('msg_id') != msg_id:
81 if msg['parent_header'].get('msg_id') != msg_id:
82 # not an output from our execution
82 # not an output from our execution
83 continue
83 continue
84
84
85 msg_type = msg['msg_type']
85 msg_type = msg['msg_type']
86 self.log.debug("output: %s", msg_type)
86 self.log.debug("output: %s", msg_type)
87 content = msg['content']
87 content = msg['content']
88
88
89 # set the prompt number for the input and the output
89 # set the prompt number for the input and the output
90 if 'execution_count' in content:
90 if 'execution_count' in content:
91 cell['prompt_number'] = content['execution_count']
91 cell['execution_count'] = content['execution_count']
92 out.prompt_number = content['execution_count']
93
92
94 if msg_type == 'status':
93 if msg_type == 'status':
95 if content['execution_state'] == 'idle':
94 if content['execution_state'] == 'idle':
96 break
95 break
97 else:
96 else:
98 continue
97 continue
99 elif msg_type == 'execute_input':
98 elif msg_type == 'execute_input':
100 continue
99 continue
101 elif msg_type == 'clear_output':
100 elif msg_type == 'clear_output':
102 outs = []
101 outs = []
103 continue
102 continue
104 elif msg_type == 'execute_result':
105 cell['prompt_number'] = content['execution_count']
106
103
107 try:
104 try:
108 out = output_from_msg(msg)
105 out = output_from_msg(msg)
109 except ValueError:
106 except ValueError:
110 self.log.error("unhandled iopub msg: " + msg_type)
107 self.log.error("unhandled iopub msg: " + msg_type)
111 else:
108 else:
112 outs.append(out)
109 outs.append(out)
113
110
114 return outs
111 return outs
@@ -1,41 +1,41 b''
1 """utility functions for preprocessor tests"""
1 """utility functions for preprocessor tests"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from IPython.nbformat import current as nbformat
6 from IPython.nbformat import current as nbformat
7
7
8 from ...tests.base import TestsBase
8 from ...tests.base import TestsBase
9 from ...exporters.exporter import ResourcesDict
9 from ...exporters.exporter import ResourcesDict
10
10
11
11
12 class PreprocessorTestsBase(TestsBase):
12 class PreprocessorTestsBase(TestsBase):
13 """Contains test functions preprocessor tests"""
13 """Contains test functions preprocessor tests"""
14
14
15
15
16 def build_notebook(self):
16 def build_notebook(self):
17 """Build a notebook in memory for use with preprocessor tests"""
17 """Build a notebook in memory for use with preprocessor tests"""
18
18
19 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a"),
19 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a"),
20 nbformat.new_output(output_type="display_data", mime_bundle={'text/plain': 'b'}),
20 nbformat.new_output(output_type="display_data", mime_bundle={'text/plain': 'b'}),
21 nbformat.new_output(output_type="stream", name="stdout", text="c"),
21 nbformat.new_output(output_type="stream", name="stdout", text="c"),
22 nbformat.new_output(output_type="stream", name="stdout", text="d"),
22 nbformat.new_output(output_type="stream", name="stdout", text="d"),
23 nbformat.new_output(output_type="stream", name="stderr", text="e"),
23 nbformat.new_output(output_type="stream", name="stderr", text="e"),
24 nbformat.new_output(output_type="stream", name="stderr", text="f"),
24 nbformat.new_output(output_type="stream", name="stderr", text="f"),
25 nbformat.new_output(output_type="display_data", mime_bundle={'image/png': 'Zw=='})] # g
25 nbformat.new_output(output_type="display_data", mime_bundle={'image/png': 'Zw=='})] # g
26 out = nbformat.new_output(output_type="display_data")
26 out = nbformat.new_output(output_type="display_data")
27 out['application/pdf'] = 'aA=='
27 out['application/pdf'] = 'aA=='
28 outputs.append(out)
28 outputs.append(out)
29
29
30 cells=[nbformat.new_code_cell(source="$ e $", prompt_number=1, outputs=outputs),
30 cells=[nbformat.new_code_cell(source="$ e $", execution_count=1, outputs=outputs),
31 nbformat.new_markdown_cell(source="$ e $")]
31 nbformat.new_markdown_cell(source="$ e $")]
32
32
33 return nbformat.new_notebook(cells=cells)
33 return nbformat.new_notebook(cells=cells)
34
34
35
35
36 def build_resources(self):
36 def build_resources(self):
37 """Build an empty resources dictionary."""
37 """Build an empty resources dictionary."""
38
38
39 res = ResourcesDict()
39 res = ResourcesDict()
40 res['metadata'] = ResourcesDict()
40 res['metadata'] = ResourcesDict()
41 return res
41 return res
@@ -1,38 +1,38 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "code",
4 "cell_type": "code",
5 "execution_count": 1,
5 "metadata": {
6 "metadata": {
6 "collapsed": false
7 "collapsed": false
7 },
8 },
8 "outputs": [],
9 "outputs": [],
9 "prompt_number": 1,
10 "source": [
10 "source": [
11 "from IPython.display import clear_output"
11 "from IPython.display import clear_output"
12 ]
12 ]
13 },
13 },
14 {
14 {
15 "cell_type": "code",
15 "cell_type": "code",
16 "execution_count": 2,
16 "metadata": {
17 "metadata": {
17 "collapsed": false
18 "collapsed": false
18 },
19 },
19 "outputs": [
20 "outputs": [
20 {
21 {
21 "metadata": {},
22 "metadata": {},
22 "name": "stdout",
23 "name": "stdout",
23 "output_type": "stream",
24 "output_type": "stream",
24 "text": "9\n"
25 "text": "9\n"
25 }
26 }
26 ],
27 ],
27 "prompt_number": 2,
28 "source": [
28 "source": [
29 "for i in range(10):\n",
29 "for i in range(10):\n",
30 " clear_output()\n",
30 " clear_output()\n",
31 " print(i)"
31 " print(i)"
32 ]
32 ]
33 }
33 }
34 ],
34 ],
35 "metadata": {},
35 "metadata": {},
36 "nbformat": 4,
36 "nbformat": 4,
37 "nbformat_minor": 0
37 "nbformat_minor": 0
38 } No newline at end of file
38 }
@@ -1,38 +1,38 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "code",
4 "cell_type": "code",
5 "execution_count": 1,
5 "metadata": {
6 "metadata": {
6 "collapsed": false
7 "collapsed": false
7 },
8 },
8 "outputs": [],
9 "outputs": [],
9 "prompt_number": 1,
10 "source": [
10 "source": [
11 "i, j = 1, 1"
11 "i, j = 1, 1"
12 ]
12 ]
13 },
13 },
14 {
14 {
15 "cell_type": "code",
15 "cell_type": "code",
16 "execution_count": 2,
16 "metadata": {
17 "metadata": {
17 "collapsed": false
18 "collapsed": false
18 },
19 },
19 "outputs": [
20 "outputs": [
20 {
21 {
21 "metadata": {},
22 "metadata": {},
22 "name": "stdout",
23 "name": "stdout",
23 "output_type": "stream",
24 "output_type": "stream",
24 "text": "2\n3\n5\n8\n13\n21\n34\n55\n89\n144\n"
25 "text": "2\n3\n5\n8\n13\n21\n34\n55\n89\n144\n"
25 }
26 }
26 ],
27 ],
27 "prompt_number": 2,
28 "source": [
28 "source": [
29 "for m in range(10):\n",
29 "for m in range(10):\n",
30 " i, j = j, i + j\n",
30 " i, j = j, i + j\n",
31 " print(j)"
31 " print(j)"
32 ]
32 ]
33 }
33 }
34 ],
34 ],
35 "metadata": {},
35 "metadata": {},
36 "nbformat": 4,
36 "nbformat": 4,
37 "nbformat_minor": 0
37 "nbformat_minor": 0
38 } No newline at end of file
38 }
@@ -1,25 +1,25 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "code",
4 "cell_type": "code",
5 "execution_count": 1,
5 "metadata": {
6 "metadata": {
6 "collapsed": false
7 "collapsed": false
7 },
8 },
8 "outputs": [
9 "outputs": [
9 {
10 {
10 "metadata": {},
11 "metadata": {},
11 "name": "stdout",
12 "name": "stdout",
12 "output_type": "stream",
13 "output_type": "stream",
13 "text": "Hello World\n"
14 "text": "Hello World\n"
14 }
15 }
15 ],
16 ],
16 "prompt_number": 1,
17 "source": [
17 "source": [
18 "print(\"Hello World\")"
18 "print(\"Hello World\")"
19 ]
19 ]
20 }
20 }
21 ],
21 ],
22 "metadata": {},
22 "metadata": {},
23 "nbformat": 4,
23 "nbformat": 4,
24 "nbformat_minor": 0
24 "nbformat_minor": 0
25 } No newline at end of file
25 }
@@ -1,29 +1,29 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "code",
4 "cell_type": "code",
5 "execution_count": 1,
5 "metadata": {
6 "metadata": {
6 "collapsed": false
7 "collapsed": false
7 },
8 },
8 "outputs": [],
9 "outputs": [],
9 "prompt_number": 1,
10 "source": [
10 "source": [
11 "from IPython.display import Image"
11 "from IPython.display import Image"
12 ]
12 ]
13 },
13 },
14 {
14 {
15 "cell_type": "code",
15 "cell_type": "code",
16 "execution_count": 2,
16 "metadata": {
17 "metadata": {
17 "collapsed": false
18 "collapsed": false
18 },
19 },
19 "outputs": [],
20 "outputs": [],
20 "prompt_number": 2,
21 "source": [
21 "source": [
22 "Image('../input/python.png');"
22 "Image('../input/python.png');"
23 ]
23 ]
24 }
24 }
25 ],
25 ],
26 "metadata": {},
26 "metadata": {},
27 "nbformat": 4,
27 "nbformat": 4,
28 "nbformat_minor": 0
28 "nbformat_minor": 0
29 } No newline at end of file
29 }
@@ -1,46 +1,46 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "code",
4 "cell_type": "code",
5 "execution_count": 1,
5 "metadata": {
6 "metadata": {
6 "collapsed": false
7 "collapsed": false
7 },
8 },
8 "outputs": [],
9 "outputs": [],
9 "prompt_number": 1,
10 "source": [
10 "source": [
11 "from IPython.display import SVG"
11 "from IPython.display import SVG"
12 ]
12 ]
13 },
13 },
14 {
14 {
15 "cell_type": "code",
15 "cell_type": "code",
16 "execution_count": 2,
16 "metadata": {
17 "metadata": {
17 "collapsed": false
18 "collapsed": false
18 },
19 },
19 "outputs": [
20 "outputs": [
20 {
21 {
22 "execution_count": 2,
21 "image/svg+xml": [
23 "image/svg+xml": [
22 "<svg height=\"100\" width=\"100\">\n",
24 "<svg height=\"100\" width=\"100\">\n",
23 " <circle cx=\"50\" cy=\"50\" fill=\"red\" r=\"40\" stroke=\"black\" stroke-width=\"2\"/>\n",
25 " <circle cx=\"50\" cy=\"50\" fill=\"red\" r=\"40\" stroke=\"black\" stroke-width=\"2\"/>\n",
24 "</svg>"
26 "</svg>"
25 ],
27 ],
26 "metadata": {},
28 "metadata": {},
27 "output_type": "execute_result",
29 "output_type": "execute_result",
28 "prompt_number": 2,
29 "text/plain": [
30 "text/plain": [
30 "<IPython.core.display.SVG object>"
31 "<IPython.core.display.SVG object>"
31 ]
32 ]
32 }
33 }
33 ],
34 ],
34 "prompt_number": 2,
35 "source": [
35 "source": [
36 "SVG(data='''\n",
36 "SVG(data='''\n",
37 "<svg height=\"100\" width=\"100\">\n",
37 "<svg height=\"100\" width=\"100\">\n",
38 " <circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"2\" fill=\"red\" />\n",
38 " <circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"2\" fill=\"red\" />\n",
39 "</svg>''')"
39 "</svg>''')"
40 ]
40 ]
41 }
41 }
42 ],
42 ],
43 "metadata": {},
43 "metadata": {},
44 "nbformat": 4,
44 "nbformat": 4,
45 "nbformat_minor": 0
45 "nbformat_minor": 0
46 } No newline at end of file
46 }
@@ -1,51 +1,51 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "code",
4 "cell_type": "code",
5 "execution_count": 1,
5 "metadata": {
6 "metadata": {
6 "collapsed": false
7 "collapsed": false
7 },
8 },
8 "outputs": [
9 "outputs": [
9 {
10 {
10 "ename": "Exception",
11 "ename": "Exception",
11 "evalue": "message",
12 "evalue": "message",
12 "metadata": {},
13 "metadata": {},
13 "output_type": "error",
14 "output_type": "error",
14 "traceback": [
15 "traceback": [
15 "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
16 "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
16 "\u001b[1;31mException\u001b[0m Traceback (most recent call last)",
17 "\u001b[1;31mException\u001b[0m Traceback (most recent call last)",
17 "\u001b[1;32m<ipython-input-1-335814d14fc1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"message\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
18 "\u001b[1;32m<ipython-input-1-335814d14fc1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"message\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
18 "\u001b[1;31mException\u001b[0m: message"
19 "\u001b[1;31mException\u001b[0m: message"
19 ]
20 ]
20 }
21 }
21 ],
22 ],
22 "prompt_number": 1,
23 "source": [
23 "source": [
24 "raise Exception(\"message\")"
24 "raise Exception(\"message\")"
25 ]
25 ]
26 },
26 },
27 {
27 {
28 "cell_type": "code",
28 "cell_type": "code",
29 "execution_count": 2,
29 "metadata": {
30 "metadata": {
30 "collapsed": false
31 "collapsed": false
31 },
32 },
32 "outputs": [
33 "outputs": [
33 {
34 {
34 "metadata": {},
35 "metadata": {},
35 "name": "stdout",
36 "name": "stdout",
36 "output_type": "stream",
37 "output_type": "stream",
37 "text": "ok\n"
38 "text": "ok\n"
38 }
39 }
39 ],
40 ],
40 "prompt_number": 2,
41 "source": [
41 "source": [
42 "print('ok')"
42 "print('ok')"
43 ]
43 ]
44 }
44 }
45 ],
45 ],
46 "metadata": {
46 "metadata": {
47 "signature": "sha256:9d47889f0678e9685429071216d0f3354db59bb66489f3225bcadfb6a1a9bbba"
47 "signature": "sha256:9d47889f0678e9685429071216d0f3354db59bb66489f3225bcadfb6a1a9bbba"
48 },
48 },
49 "nbformat": 4,
49 "nbformat": 4,
50 "nbformat_minor": 0
50 "nbformat_minor": 0
51 } No newline at end of file
51 }
@@ -1,25 +1,25 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "code",
4 "cell_type": "code",
5 "execution_count": 1,
5 "metadata": {
6 "metadata": {
6 "collapsed": false
7 "collapsed": false
7 },
8 },
8 "outputs": [
9 "outputs": [
9 {
10 {
10 "metadata": {},
11 "metadata": {},
11 "name": "stdout",
12 "name": "stdout",
12 "output_type": "stream",
13 "output_type": "stream",
13 "text": "\u2603\n"
14 "text": "\u2603\n"
14 }
15 }
15 ],
16 ],
16 "prompt_number": 1,
17 "source": [
17 "source": [
18 "print('\u2603')"
18 "print('\u2603')"
19 ]
19 ]
20 }
20 }
21 ],
21 ],
22 "metadata": {},
22 "metadata": {},
23 "nbformat": 4,
23 "nbformat": 4,
24 "nbformat_minor": 0
24 "nbformat_minor": 0
25 } No newline at end of file
25 }
@@ -1,35 +1,35 b''
1 """
1 """
2 Module with tests for the clearoutput preprocessor.
2 Module with tests for the clearoutput preprocessor.
3 """
3 """
4
4
5 # Copyright (c) IPython Development Team.
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7
7
8 from IPython.nbformat import current as nbformat
8 from IPython.nbformat import current as nbformat
9
9
10 from .base import PreprocessorTestsBase
10 from .base import PreprocessorTestsBase
11 from ..clearoutput import ClearOutputPreprocessor
11 from ..clearoutput import ClearOutputPreprocessor
12
12
13
13
14 class TestClearOutput(PreprocessorTestsBase):
14 class TestClearOutput(PreprocessorTestsBase):
15 """Contains test functions for clearoutput.py"""
15 """Contains test functions for clearoutput.py"""
16
16
17
17
18 def build_preprocessor(self):
18 def build_preprocessor(self):
19 """Make an instance of a preprocessor"""
19 """Make an instance of a preprocessor"""
20 preprocessor = ClearOutputPreprocessor()
20 preprocessor = ClearOutputPreprocessor()
21 preprocessor.enabled = True
21 preprocessor.enabled = True
22 return preprocessor
22 return preprocessor
23
23
24 def test_constructor(self):
24 def test_constructor(self):
25 """Can a ClearOutputPreprocessor be constructed?"""
25 """Can a ClearOutputPreprocessor be constructed?"""
26 self.build_preprocessor()
26 self.build_preprocessor()
27
27
28 def test_output(self):
28 def test_output(self):
29 """Test the output of the ClearOutputPreprocessor"""
29 """Test the output of the ClearOutputPreprocessor"""
30 nb = self.build_notebook()
30 nb = self.build_notebook()
31 res = self.build_resources()
31 res = self.build_resources()
32 preprocessor = self.build_preprocessor()
32 preprocessor = self.build_preprocessor()
33 nb, res = preprocessor(nb, res)
33 nb, res = preprocessor(nb, res)
34 assert nb.cells[0].outputs == []
34 assert nb.cells[0].outputs == []
35 assert nb.cells[0].prompt_number is None
35 assert nb.cells[0].execution_count is None
@@ -1,58 +1,58 b''
1 """Tests for the coalescestreams preprocessor"""
1 """Tests for the coalescestreams preprocessor"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from IPython.nbformat import current as nbformat
6 from IPython.nbformat import current as nbformat
7
7
8 from .base import PreprocessorTestsBase
8 from .base import PreprocessorTestsBase
9 from ..coalescestreams import coalesce_streams
9 from ..coalescestreams import coalesce_streams
10
10
11
11
12 class TestCoalesceStreams(PreprocessorTestsBase):
12 class TestCoalesceStreams(PreprocessorTestsBase):
13 """Contains test functions for coalescestreams.py"""
13 """Contains test functions for coalescestreams.py"""
14
14
15 def test_coalesce_streams(self):
15 def test_coalesce_streams(self):
16 """coalesce_streams preprocessor output test"""
16 """coalesce_streams preprocessor output test"""
17 nb = self.build_notebook()
17 nb = self.build_notebook()
18 res = self.build_resources()
18 res = self.build_resources()
19 nb, res = coalesce_streams(nb, res)
19 nb, res = coalesce_streams(nb, res)
20 outputs = nb.cells[0].outputs
20 outputs = nb.cells[0].outputs
21 self.assertEqual(outputs[0].text, "a")
21 self.assertEqual(outputs[0].text, "a")
22 self.assertEqual(outputs[1].output_type, "display_data")
22 self.assertEqual(outputs[1].output_type, "display_data")
23 self.assertEqual(outputs[2].text, "cd")
23 self.assertEqual(outputs[2].text, "cd")
24 self.assertEqual(outputs[3].text, "ef")
24 self.assertEqual(outputs[3].text, "ef")
25
25
26 def test_coalesce_sequenced_streams(self):
26 def test_coalesce_sequenced_streams(self):
27 """Can the coalesce streams preprocessor merge a sequence of streams?"""
27 """Can the coalesce streams preprocessor merge a sequence of streams?"""
28 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="0"),
28 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="0"),
29 nbformat.new_output(output_type="stream", name="stdout", text="1"),
29 nbformat.new_output(output_type="stream", name="stdout", text="1"),
30 nbformat.new_output(output_type="stream", name="stdout", text="2"),
30 nbformat.new_output(output_type="stream", name="stdout", text="2"),
31 nbformat.new_output(output_type="stream", name="stdout", text="3"),
31 nbformat.new_output(output_type="stream", name="stdout", text="3"),
32 nbformat.new_output(output_type="stream", name="stdout", text="4"),
32 nbformat.new_output(output_type="stream", name="stdout", text="4"),
33 nbformat.new_output(output_type="stream", name="stdout", text="5"),
33 nbformat.new_output(output_type="stream", name="stdout", text="5"),
34 nbformat.new_output(output_type="stream", name="stdout", text="6"),
34 nbformat.new_output(output_type="stream", name="stdout", text="6"),
35 nbformat.new_output(output_type="stream", name="stdout", text="7")]
35 nbformat.new_output(output_type="stream", name="stdout", text="7")]
36 cells=[nbformat.new_code_cell(source="# None", prompt_number=1,outputs=outputs)]
36 cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)]
37
37
38 nb = nbformat.new_notebook(cells=cells)
38 nb = nbformat.new_notebook(cells=cells)
39 res = self.build_resources()
39 res = self.build_resources()
40 nb, res = coalesce_streams(nb, res)
40 nb, res = coalesce_streams(nb, res)
41 outputs = nb.cells[0].outputs
41 outputs = nb.cells[0].outputs
42 self.assertEqual(outputs[0].text, u'01234567')
42 self.assertEqual(outputs[0].text, u'01234567')
43
43
44 def test_coalesce_replace_streams(self):
44 def test_coalesce_replace_streams(self):
45 """Are \\r characters handled?"""
45 """Are \\r characters handled?"""
46 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="z"),
46 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="z"),
47 nbformat.new_output(output_type="stream", name="stdout", text="\ra"),
47 nbformat.new_output(output_type="stream", name="stdout", text="\ra"),
48 nbformat.new_output(output_type="stream", name="stdout", text="\nz\rb"),
48 nbformat.new_output(output_type="stream", name="stdout", text="\nz\rb"),
49 nbformat.new_output(output_type="stream", name="stdout", text="\nz"),
49 nbformat.new_output(output_type="stream", name="stdout", text="\nz"),
50 nbformat.new_output(output_type="stream", name="stdout", text="\rc\n"),
50 nbformat.new_output(output_type="stream", name="stdout", text="\rc\n"),
51 nbformat.new_output(output_type="stream", name="stdout", text="z\rz\rd")]
51 nbformat.new_output(output_type="stream", name="stdout", text="z\rz\rd")]
52 cells=[nbformat.new_code_cell(source="# None", prompt_number=1,outputs=outputs)]
52 cells=[nbformat.new_code_cell(source="# None", execution_count=1,outputs=outputs)]
53
53
54 nb = nbformat.new_notebook(cells=cells)
54 nb = nbformat.new_notebook(cells=cells)
55 res = self.build_resources()
55 res = self.build_resources()
56 nb, res = coalesce_streams(nb, res)
56 nb, res = coalesce_streams(nb, res)
57 outputs = nb.cells[0].outputs
57 outputs = nb.cells[0].outputs
58 self.assertEqual(outputs[0].text, u'a\nb\nc\nd')
58 self.assertEqual(outputs[0].text, u'a\nb\nc\nd')
@@ -1,88 +1,88 b''
1 """
1 """
2 Module with tests for the execute preprocessor.
2 Module with tests for the execute preprocessor.
3 """
3 """
4
4
5 # Copyright (c) IPython Development Team.
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7
7
8 import copy
8 import copy
9 import glob
9 import glob
10 import os
10 import os
11 import re
11 import re
12
12
13 from IPython.nbformat import current as nbformat
13 from IPython.nbformat import current as nbformat
14
14
15 from .base import PreprocessorTestsBase
15 from .base import PreprocessorTestsBase
16 from ..execute import ExecutePreprocessor
16 from ..execute import ExecutePreprocessor
17
17
18 from IPython.nbconvert.filters import strip_ansi
18 from IPython.nbconvert.filters import strip_ansi
19
19
20 addr_pat = re.compile(r'0x[0-9a-f]{7,9}')
20 addr_pat = re.compile(r'0x[0-9a-f]{7,9}')
21
21
22 class TestExecute(PreprocessorTestsBase):
22 class TestExecute(PreprocessorTestsBase):
23 """Contains test functions for execute.py"""
23 """Contains test functions for execute.py"""
24
24
25 @staticmethod
25 @staticmethod
26 def normalize_output(output):
26 def normalize_output(output):
27 """
27 """
28 Normalizes outputs for comparison.
28 Normalizes outputs for comparison.
29 """
29 """
30 output = dict(output)
30 output = dict(output)
31 if 'metadata' in output:
31 if 'metadata' in output:
32 del output['metadata']
32 del output['metadata']
33 if 'text/plain' in output:
33 if 'text/plain' in output:
34 output['text/plain'] = re.sub(addr_pat, '<HEXADDR>', output['text/plain'])
34 output['text/plain'] = re.sub(addr_pat, '<HEXADDR>', output['text/plain'])
35 if 'traceback' in output:
35 if 'traceback' in output:
36 tb = []
36 tb = []
37 for line in output['traceback']:
37 for line in output['traceback']:
38 tb.append(strip_ansi(line))
38 tb.append(strip_ansi(line))
39 output['traceback'] = tb
39 output['traceback'] = tb
40
40
41 return output
41 return output
42
42
43
43
44 def assert_notebooks_equal(self, expected, actual):
44 def assert_notebooks_equal(self, expected, actual):
45 expected_cells = expected['cells']
45 expected_cells = expected['cells']
46 actual_cells = actual['cells']
46 actual_cells = actual['cells']
47 assert len(expected_cells) == len(actual_cells)
47 assert len(expected_cells) == len(actual_cells)
48
48
49 for expected_cell, actual_cell in zip(expected_cells, actual_cells):
49 for expected_cell, actual_cell in zip(expected_cells, actual_cells):
50 expected_outputs = expected_cell.get('outputs', [])
50 expected_outputs = expected_cell.get('outputs', [])
51 actual_outputs = actual_cell.get('outputs', [])
51 actual_outputs = actual_cell.get('outputs', [])
52 normalized_expected_outputs = list(map(self.normalize_output, expected_outputs))
52 normalized_expected_outputs = list(map(self.normalize_output, expected_outputs))
53 normalized_actual_outputs = list(map(self.normalize_output, actual_outputs))
53 normalized_actual_outputs = list(map(self.normalize_output, actual_outputs))
54 assert normalized_expected_outputs == normalized_actual_outputs
54 assert normalized_expected_outputs == normalized_actual_outputs
55
55
56 expected_prompt_number = expected_cell.get('prompt_number', None)
56 expected_execution_count = expected_cell.get('execution_count', None)
57 actual_prompt_number = actual_cell.get('prompt_number', None)
57 actual_execution_count = actual_cell.get('execution_count', None)
58 assert expected_prompt_number == actual_prompt_number
58 assert expected_execution_count == actual_execution_count
59
59
60
60
61 def build_preprocessor(self):
61 def build_preprocessor(self):
62 """Make an instance of a preprocessor"""
62 """Make an instance of a preprocessor"""
63 preprocessor = ExecutePreprocessor()
63 preprocessor = ExecutePreprocessor()
64 preprocessor.enabled = True
64 preprocessor.enabled = True
65 return preprocessor
65 return preprocessor
66
66
67
67
68 def test_constructor(self):
68 def test_constructor(self):
69 """Can a ExecutePreprocessor be constructed?"""
69 """Can a ExecutePreprocessor be constructed?"""
70 self.build_preprocessor()
70 self.build_preprocessor()
71
71
72
72
73 def test_run_notebooks(self):
73 def test_run_notebooks(self):
74 """Runs a series of test notebooks and compares them to their actual output"""
74 """Runs a series of test notebooks and compares them to their actual output"""
75 current_dir = os.path.dirname(__file__)
75 current_dir = os.path.dirname(__file__)
76 input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb'))
76 input_files = glob.glob(os.path.join(current_dir, 'files', '*.ipynb'))
77 for filename in input_files:
77 for filename in input_files:
78 with open(os.path.join(current_dir, 'files', filename)) as f:
78 with open(os.path.join(current_dir, 'files', filename)) as f:
79 input_nb = nbformat.read(f, 'ipynb')
79 input_nb = nbformat.read(f, 'ipynb')
80 res = self.build_resources()
80 res = self.build_resources()
81 preprocessor = self.build_preprocessor()
81 preprocessor = self.build_preprocessor()
82 cleaned_input_nb = copy.deepcopy(input_nb)
82 cleaned_input_nb = copy.deepcopy(input_nb)
83 for cell in cleaned_input_nb.cells:
83 for cell in cleaned_input_nb.cells:
84 if 'prompt_number' in cell:
84 if 'execution_count' in cell:
85 del cell['prompt_number']
85 del cell['execution_count']
86 cell['outputs'] = []
86 cell['outputs'] = []
87 output_nb, _ = preprocessor(cleaned_input_nb, res)
87 output_nb, _ = preprocessor(cleaned_input_nb, res)
88 self.assert_notebooks_equal(output_nb, input_nb)
88 self.assert_notebooks_equal(output_nb, input_nb)
@@ -1,78 +1,78 b''
1 """Tests for the revealhelp preprocessor"""
1 """Tests for the revealhelp preprocessor"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from IPython.nbformat import current as nbformat
6 from IPython.nbformat import current as nbformat
7
7
8 from .base import PreprocessorTestsBase
8 from .base import PreprocessorTestsBase
9 from ..revealhelp import RevealHelpPreprocessor
9 from ..revealhelp import RevealHelpPreprocessor
10
10
11
11
12 class Testrevealhelp(PreprocessorTestsBase):
12 class Testrevealhelp(PreprocessorTestsBase):
13 """Contains test functions for revealhelp.py"""
13 """Contains test functions for revealhelp.py"""
14
14
15 def build_notebook(self):
15 def build_notebook(self):
16 """Build a reveal slides notebook in memory for use with tests.
16 """Build a reveal slides notebook in memory for use with tests.
17 Overrides base in PreprocessorTestsBase"""
17 Overrides base in PreprocessorTestsBase"""
18
18
19 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a")]
19 outputs = [nbformat.new_output(output_type="stream", name="stdout", text="a")]
20
20
21 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
21 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
22 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
22 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
23
23
24 cells=[nbformat.new_code_cell(source="", prompt_number=1, outputs=outputs),
24 cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs),
25 nbformat.new_markdown_cell(source="", metadata=slide_metadata),
25 nbformat.new_markdown_cell(source="", metadata=slide_metadata),
26 nbformat.new_code_cell(source="", prompt_number=2, outputs=outputs),
26 nbformat.new_code_cell(source="", execution_count=2, outputs=outputs),
27 nbformat.new_markdown_cell(source="", metadata=slide_metadata),
27 nbformat.new_markdown_cell(source="", metadata=slide_metadata),
28 nbformat.new_markdown_cell(source="", metadata=subslide_metadata)]
28 nbformat.new_markdown_cell(source="", metadata=subslide_metadata)]
29
29
30 return nbformat.new_notebook(cells=cells)
30 return nbformat.new_notebook(cells=cells)
31
31
32
32
33 def build_preprocessor(self):
33 def build_preprocessor(self):
34 """Make an instance of a preprocessor"""
34 """Make an instance of a preprocessor"""
35 preprocessor = RevealHelpPreprocessor()
35 preprocessor = RevealHelpPreprocessor()
36 preprocessor.enabled = True
36 preprocessor.enabled = True
37 return preprocessor
37 return preprocessor
38
38
39
39
40 def test_constructor(self):
40 def test_constructor(self):
41 """Can a RevealHelpPreprocessor be constructed?"""
41 """Can a RevealHelpPreprocessor be constructed?"""
42 self.build_preprocessor()
42 self.build_preprocessor()
43
43
44
44
45 def test_reveal_attribute(self):
45 def test_reveal_attribute(self):
46 """Make sure the reveal url_prefix resources is set"""
46 """Make sure the reveal url_prefix resources is set"""
47 nb = self.build_notebook()
47 nb = self.build_notebook()
48 res = self.build_resources()
48 res = self.build_resources()
49 preprocessor = self.build_preprocessor()
49 preprocessor = self.build_preprocessor()
50 nb, res = preprocessor(nb, res)
50 nb, res = preprocessor(nb, res)
51 assert 'reveal' in res
51 assert 'reveal' in res
52 assert 'url_prefix' in res['reveal']
52 assert 'url_prefix' in res['reveal']
53
53
54
54
55 def test_reveal_output(self):
55 def test_reveal_output(self):
56 """Make sure that the reveal preprocessor """
56 """Make sure that the reveal preprocessor """
57 nb = self.build_notebook()
57 nb = self.build_notebook()
58 res = self.build_resources()
58 res = self.build_resources()
59 preprocessor = self.build_preprocessor()
59 preprocessor = self.build_preprocessor()
60 nb, res = preprocessor(nb, res)
60 nb, res = preprocessor(nb, res)
61 cells = nb.cells
61 cells = nb.cells
62
62
63 # Make sure correct metadata tags are available on every cell.
63 # Make sure correct metadata tags are available on every cell.
64 for cell in cells:
64 for cell in cells:
65 assert 'slide_type' in cell.metadata
65 assert 'slide_type' in cell.metadata
66
66
67 # Make sure slide end is only applied to the cells preceeding slide
67 # Make sure slide end is only applied to the cells preceeding slide
68 # cells.
68 # cells.
69 assert 'slide_helper' in cells[1].metadata
69 assert 'slide_helper' in cells[1].metadata
70 self.assertEqual(cells[1].metadata['slide_helper'], '-')
70 self.assertEqual(cells[1].metadata['slide_helper'], '-')
71
71
72 # Verify 'slide-end'
72 # Verify 'slide-end'
73 assert 'slide_helper' in cells[0].metadata
73 assert 'slide_helper' in cells[0].metadata
74 self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end')
74 self.assertEqual(cells[0].metadata['slide_helper'], 'slide_end')
75 assert 'slide_helper' in cells[2].metadata
75 assert 'slide_helper' in cells[2].metadata
76 self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end')
76 self.assertEqual(cells[2].metadata['slide_helper'], 'slide_end')
77 assert 'slide_helper' in cells[3].metadata
77 assert 'slide_helper' in cells[3].metadata
78 self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end')
78 self.assertEqual(cells[3].metadata['slide_helper'], 'subslide_end')
@@ -1,74 +1,74 b''
1 """Tests for the svg2pdf preprocessor"""
1 """Tests for the svg2pdf preprocessor"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from IPython.testing import decorators as dec
6 from IPython.testing import decorators as dec
7 from IPython.nbformat import current as nbformat
7 from IPython.nbformat import current as nbformat
8
8
9 from .base import PreprocessorTestsBase
9 from .base import PreprocessorTestsBase
10 from ..svg2pdf import SVG2PDFPreprocessor
10 from ..svg2pdf import SVG2PDFPreprocessor
11
11
12
12
13 class Testsvg2pdf(PreprocessorTestsBase):
13 class Testsvg2pdf(PreprocessorTestsBase):
14 """Contains test functions for svg2pdf.py"""
14 """Contains test functions for svg2pdf.py"""
15
15
16 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
16 simple_svg = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
17 <!-- Created with Inkscape (http://www.inkscape.org/) -->
17 <!-- Created with Inkscape (http://www.inkscape.org/) -->
18 <svg
18 <svg
19 xmlns:svg="http://www.w3.org/2000/svg"
19 xmlns:svg="http://www.w3.org/2000/svg"
20 xmlns="http://www.w3.org/2000/svg"
20 xmlns="http://www.w3.org/2000/svg"
21 version="1.0"
21 version="1.0"
22 x="0.00000000"
22 x="0.00000000"
23 y="0.00000000"
23 y="0.00000000"
24 width="500.00000"
24 width="500.00000"
25 height="500.00000"
25 height="500.00000"
26 id="svg2">
26 id="svg2">
27 <defs
27 <defs
28 id="defs4" />
28 id="defs4" />
29 <g
29 <g
30 id="layer1">
30 id="layer1">
31 <rect
31 <rect
32 width="300.00000"
32 width="300.00000"
33 height="300.00000"
33 height="300.00000"
34 x="100.00000"
34 x="100.00000"
35 y="100.00000"
35 y="100.00000"
36 style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
36 style="opacity:1.0000000;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:8.0000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.00000000;stroke-opacity:1.0000000"
37 id="rect5719" />
37 id="rect5719" />
38 </g>
38 </g>
39 </svg>"""
39 </svg>"""
40
40
41 def build_notebook(self):
41 def build_notebook(self):
42 """Build a reveal slides notebook in memory for use with tests.
42 """Build a reveal slides notebook in memory for use with tests.
43 Overrides base in PreprocessorTestsBase"""
43 Overrides base in PreprocessorTestsBase"""
44
44
45 outputs = [nbformat.new_output(output_type="svg", output_svg=self.simple_svg)]
45 outputs = [nbformat.new_output(output_type="svg", output_svg=self.simple_svg)]
46
46
47 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
47 slide_metadata = {'slideshow' : {'slide_type': 'slide'}}
48 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
48 subslide_metadata = {'slideshow' : {'slide_type': 'subslide'}}
49
49
50 cells=[nbformat.new_code_cell(source="", prompt_number=1, outputs=outputs)]
50 cells=[nbformat.new_code_cell(source="", execution_count=1, outputs=outputs)]
51
51
52 return nbformat.new_notebook(cells=cells)
52 return nbformat.new_notebook(cells=cells)
53
53
54
54
55 def build_preprocessor(self):
55 def build_preprocessor(self):
56 """Make an instance of a preprocessor"""
56 """Make an instance of a preprocessor"""
57 preprocessor = SVG2PDFPreprocessor()
57 preprocessor = SVG2PDFPreprocessor()
58 preprocessor.enabled = True
58 preprocessor.enabled = True
59 return preprocessor
59 return preprocessor
60
60
61
61
62 def test_constructor(self):
62 def test_constructor(self):
63 """Can a SVG2PDFPreprocessor be constructed?"""
63 """Can a SVG2PDFPreprocessor be constructed?"""
64 self.build_preprocessor()
64 self.build_preprocessor()
65
65
66
66
67 @dec.onlyif_cmds_exist('inkscape')
67 @dec.onlyif_cmds_exist('inkscape')
68 def test_output(self):
68 def test_output(self):
69 """Test the output of the SVG2PDFPreprocessor"""
69 """Test the output of the SVG2PDFPreprocessor"""
70 nb = self.build_notebook()
70 nb = self.build_notebook()
71 res = self.build_resources()
71 res = self.build_resources()
72 preprocessor = self.build_preprocessor()
72 preprocessor = self.build_preprocessor()
73 nb, res = preprocessor(nb, res)
73 nb, res = preprocessor(nb, res)
74 assert 'svg' in nb.cells[0].outputs[0]
74 assert 'svg' in nb.cells[0].outputs[0]
@@ -1,203 +1,203 b''
1 {%- extends 'display_priority.tpl' -%}
1 {%- extends 'display_priority.tpl' -%}
2
2
3
3
4 {% block codecell %}
4 {% block codecell %}
5 <div class="cell border-box-sizing code_cell rendered">
5 <div class="cell border-box-sizing code_cell rendered">
6 {{ super() }}
6 {{ super() }}
7 </div>
7 </div>
8 {%- endblock codecell %}
8 {%- endblock codecell %}
9
9
10 {% block input_group -%}
10 {% block input_group -%}
11 <div class="input">
11 <div class="input">
12 {{ super() }}
12 {{ super() }}
13 </div>
13 </div>
14 {% endblock input_group %}
14 {% endblock input_group %}
15
15
16 {% block output_group %}
16 {% block output_group %}
17 <div class="output_wrapper">
17 <div class="output_wrapper">
18 <div class="output">
18 <div class="output">
19 {{ super() }}
19 {{ super() }}
20 </div>
20 </div>
21 </div>
21 </div>
22 {% endblock output_group %}
22 {% endblock output_group %}
23
23
24 {% block in_prompt -%}
24 {% block in_prompt -%}
25 <div class="prompt input_prompt">
25 <div class="prompt input_prompt">
26 {%- if cell.prompt_number is defined -%}
26 {%- if cell.execution_count is defined -%}
27 In&nbsp;[{{ cell.prompt_number|replace(None, "&nbsp;") }}]:
27 In&nbsp;[{{ cell.execution_count|replace(None, "&nbsp;") }}]:
28 {%- else -%}
28 {%- else -%}
29 In&nbsp;[&nbsp;]:
29 In&nbsp;[&nbsp;]:
30 {%- endif -%}
30 {%- endif -%}
31 </div>
31 </div>
32 {%- endblock in_prompt %}
32 {%- endblock in_prompt %}
33
33
34 {% block empty_in_prompt -%}
34 {% block empty_in_prompt -%}
35 <div class="prompt input_prompt">
35 <div class="prompt input_prompt">
36 </div>
36 </div>
37 {%- endblock empty_in_prompt %}
37 {%- endblock empty_in_prompt %}
38
38
39 {#
39 {#
40 output_prompt doesn't do anything in HTML,
40 output_prompt doesn't do anything in HTML,
41 because there is a prompt div in each output area (see output block)
41 because there is a prompt div in each output area (see output block)
42 #}
42 #}
43 {% block output_prompt %}
43 {% block output_prompt %}
44 {% endblock output_prompt %}
44 {% endblock output_prompt %}
45
45
46 {% block input %}
46 {% block input %}
47 <div class="inner_cell">
47 <div class="inner_cell">
48 <div class="input_area">
48 <div class="input_area">
49 {{ cell.source | highlight_code(metadata=cell.metadata) }}
49 {{ cell.source | highlight_code(metadata=cell.metadata) }}
50 </div>
50 </div>
51 </div>
51 </div>
52 {%- endblock input %}
52 {%- endblock input %}
53
53
54 {% block output %}
54 {% block output %}
55 <div class="output_area">
55 <div class="output_area">
56 {%- if output.output_type == 'execute_result' -%}
56 {%- if output.output_type == 'execute_result' -%}
57 <div class="prompt output_prompt">
57 <div class="prompt output_prompt">
58 {%- if cell.prompt_number is defined -%}
58 {%- if cell.execution_count is defined -%}
59 Out[{{ cell.prompt_number|replace(None, "&nbsp;") }}]:
59 Out[{{ cell.execution_count|replace(None, "&nbsp;") }}]:
60 {%- else -%}
60 {%- else -%}
61 Out[&nbsp;]:
61 Out[&nbsp;]:
62 {%- endif -%}
62 {%- endif -%}
63 {%- else -%}
63 {%- else -%}
64 <div class="prompt">
64 <div class="prompt">
65 {%- endif -%}
65 {%- endif -%}
66 </div>
66 </div>
67 {{ super() }}
67 {{ super() }}
68 </div>
68 </div>
69 {% endblock output %}
69 {% endblock output %}
70
70
71 {% block markdowncell scoped %}
71 {% block markdowncell scoped %}
72 <div class="cell border-box-sizing text_cell rendered">
72 <div class="cell border-box-sizing text_cell rendered">
73 {{ self.empty_in_prompt() }}
73 {{ self.empty_in_prompt() }}
74 <div class="inner_cell">
74 <div class="inner_cell">
75 <div class="text_cell_render border-box-sizing rendered_html">
75 <div class="text_cell_render border-box-sizing rendered_html">
76 {{ cell.source | markdown2html | strip_files_prefix }}
76 {{ cell.source | markdown2html | strip_files_prefix }}
77 </div>
77 </div>
78 </div>
78 </div>
79 </div>
79 </div>
80 {%- endblock markdowncell %}
80 {%- endblock markdowncell %}
81
81
82 {% block headingcell scoped %}
82 {% block headingcell scoped %}
83 <div class="cell border-box-sizing text_cell rendered">
83 <div class="cell border-box-sizing text_cell rendered">
84 {{ self.empty_in_prompt() }}
84 {{ self.empty_in_prompt() }}
85 <div class="inner_cell">
85 <div class="inner_cell">
86 <div class="text_cell_render border-box-sizing rendered_html">
86 <div class="text_cell_render border-box-sizing rendered_html">
87 {{ ("#" * cell.level + cell.source) | replace('\n', ' ') | markdown2html | strip_files_prefix | add_anchor }}
87 {{ ("#" * cell.level + cell.source) | replace('\n', ' ') | markdown2html | strip_files_prefix | add_anchor }}
88 </div>
88 </div>
89 </div>
89 </div>
90 </div>
90 </div>
91 {% endblock headingcell %}
91 {% endblock headingcell %}
92
92
93 {% block unknowncell scoped %}
93 {% block unknowncell scoped %}
94 unknown type {{ cell.type }}
94 unknown type {{ cell.type }}
95 {% endblock unknowncell %}
95 {% endblock unknowncell %}
96
96
97 {% block execute_result -%}
97 {% block execute_result -%}
98 {%- set extra_class="output_execute_result" -%}
98 {%- set extra_class="output_execute_result" -%}
99 {% block data_priority scoped %}
99 {% block data_priority scoped %}
100 {{ super() }}
100 {{ super() }}
101 {% endblock %}
101 {% endblock %}
102 {%- set extra_class="" -%}
102 {%- set extra_class="" -%}
103 {%- endblock execute_result %}
103 {%- endblock execute_result %}
104
104
105 {% block stream_stdout -%}
105 {% block stream_stdout -%}
106 <div class="output_subarea output_stream output_stdout output_text">
106 <div class="output_subarea output_stream output_stdout output_text">
107 <pre>
107 <pre>
108 {{- output.text | ansi2html -}}
108 {{- output.text | ansi2html -}}
109 </pre>
109 </pre>
110 </div>
110 </div>
111 {%- endblock stream_stdout %}
111 {%- endblock stream_stdout %}
112
112
113 {% block stream_stderr -%}
113 {% block stream_stderr -%}
114 <div class="output_subarea output_stream output_stderr output_text">
114 <div class="output_subarea output_stream output_stderr output_text">
115 <pre>
115 <pre>
116 {{- output.text | ansi2html -}}
116 {{- output.text | ansi2html -}}
117 </pre>
117 </pre>
118 </div>
118 </div>
119 {%- endblock stream_stderr %}
119 {%- endblock stream_stderr %}
120
120
121 {% block data_svg scoped -%}
121 {% block data_svg scoped -%}
122 <div class="output_svg output_subarea {{extra_class}}">
122 <div class="output_svg output_subarea {{extra_class}}">
123 {%- if output.svg_filename %}
123 {%- if output.svg_filename %}
124 <img src="{{output.svg_filename | posix_path}}"
124 <img src="{{output.svg_filename | posix_path}}"
125 {%- else %}
125 {%- else %}
126 {{ output.svg }}
126 {{ output.svg }}
127 {%- endif %}
127 {%- endif %}
128 </div>
128 </div>
129 {%- endblock data_svg %}
129 {%- endblock data_svg %}
130
130
131 {% block data_html scoped -%}
131 {% block data_html scoped -%}
132 <div class="output_html rendered_html output_subarea {{extra_class}}">
132 <div class="output_html rendered_html output_subarea {{extra_class}}">
133 {{ output.html }}
133 {{ output.html }}
134 </div>
134 </div>
135 {%- endblock data_html %}
135 {%- endblock data_html %}
136
136
137 {% block data_png scoped %}
137 {% block data_png scoped %}
138 <div class="output_png output_subarea {{extra_class}}">
138 <div class="output_png output_subarea {{extra_class}}">
139 {%- if output.png_filename %}
139 {%- if output.png_filename %}
140 <img src="{{output.png_filename | posix_path}}"
140 <img src="{{output.png_filename | posix_path}}"
141 {%- else %}
141 {%- else %}
142 <img src="data:image/png;base64,{{ output.png }}"
142 <img src="data:image/png;base64,{{ output.png }}"
143 {%- endif %}
143 {%- endif %}
144 {%- if 'metadata' in output and 'width' in output.metadata.get('png', {}) %}
144 {%- if 'metadata' in output and 'width' in output.metadata.get('png', {}) %}
145 width={{output.metadata['png']['width']}}
145 width={{output.metadata['png']['width']}}
146 {%- endif %}
146 {%- endif %}
147 {%- if 'metadata' in output and 'height' in output.metadata.get('png', {}) %}
147 {%- if 'metadata' in output and 'height' in output.metadata.get('png', {}) %}
148 height={{output.metadata['png']['height']}}
148 height={{output.metadata['png']['height']}}
149 {%- endif %}
149 {%- endif %}
150 >
150 >
151 </div>
151 </div>
152 {%- endblock data_png %}
152 {%- endblock data_png %}
153
153
154 {% block data_jpg scoped %}
154 {% block data_jpg scoped %}
155 <div class="output_jpeg output_subarea {{extra_class}}">
155 <div class="output_jpeg output_subarea {{extra_class}}">
156 {%- if output.jpeg_filename %}
156 {%- if output.jpeg_filename %}
157 <img src="{{output.jpeg_filename | posix_path}}"
157 <img src="{{output.jpeg_filename | posix_path}}"
158 {%- else %}
158 {%- else %}
159 <img src="data:image/jpeg;base64,{{ output.jpeg }}"
159 <img src="data:image/jpeg;base64,{{ output.jpeg }}"
160 {%- endif %}
160 {%- endif %}
161 {%- if 'metadata' in output and 'width' in output.metadata.get('jpeg', {}) %}
161 {%- if 'metadata' in output and 'width' in output.metadata.get('jpeg', {}) %}
162 width={{output.metadata['jpeg']['width']}}
162 width={{output.metadata['jpeg']['width']}}
163 {%- endif %}
163 {%- endif %}
164 {%- if 'metadata' in output and 'height' in output.metadata.get('jpeg', {}) %}
164 {%- if 'metadata' in output and 'height' in output.metadata.get('jpeg', {}) %}
165 height={{output.metadata['jpeg']['height']}}
165 height={{output.metadata['jpeg']['height']}}
166 {%- endif %}
166 {%- endif %}
167 >
167 >
168 </div>
168 </div>
169 {%- endblock data_jpg %}
169 {%- endblock data_jpg %}
170
170
171 {% block data_latex scoped %}
171 {% block data_latex scoped %}
172 <div class="output_latex output_subarea {{extra_class}}">
172 <div class="output_latex output_subarea {{extra_class}}">
173 {{ output.latex }}
173 {{ output.latex }}
174 </div>
174 </div>
175 {%- endblock data_latex %}
175 {%- endblock data_latex %}
176
176
177 {% block error -%}
177 {% block error -%}
178 <div class="output_subarea output_text output_error">
178 <div class="output_subarea output_text output_error">
179 <pre>
179 <pre>
180 {{- super() -}}
180 {{- super() -}}
181 </pre>
181 </pre>
182 </div>
182 </div>
183 {%- endblock error %}
183 {%- endblock error %}
184
184
185 {%- block traceback_line %}
185 {%- block traceback_line %}
186 {{ line | ansi2html }}
186 {{ line | ansi2html }}
187 {%- endblock traceback_line %}
187 {%- endblock traceback_line %}
188
188
189 {%- block data_text scoped %}
189 {%- block data_text scoped %}
190 <div class="output_text output_subarea {{extra_class}}">
190 <div class="output_text output_subarea {{extra_class}}">
191 <pre>
191 <pre>
192 {{- output.text | ansi2html -}}
192 {{- output.text | ansi2html -}}
193 </pre>
193 </pre>
194 </div>
194 </div>
195 {%- endblock -%}
195 {%- endblock -%}
196
196
197 {%- block data_javascript scoped %}
197 {%- block data_javascript scoped %}
198 <div class="output_subarea output_javascript {{extra_class}}">
198 <div class="output_subarea output_javascript {{extra_class}}">
199 <script type="text/javascript">
199 <script type="text/javascript">
200 {{ output.javascript }}
200 {{ output.javascript }}
201 </script>
201 </script>
202 </div>
202 </div>
203 {%- endblock -%}
203 {%- endblock -%}
@@ -1,45 +1,45 b''
1 ((= Black&white ipython input/output style =))
1 ((= Black&white ipython input/output style =))
2
2
3 ((*- extends 'base.tplx' -*))
3 ((*- extends 'base.tplx' -*))
4
4
5 %===============================================================================
5 %===============================================================================
6 % Input
6 % Input
7 %===============================================================================
7 %===============================================================================
8
8
9 ((* block input scoped *))
9 ((* block input scoped *))
10 ((( add_prompt(cell.source, cell, 'In ') )))
10 ((( add_prompt(cell.source, cell, 'In ') )))
11 ((* endblock input *))
11 ((* endblock input *))
12
12
13
13
14 %===============================================================================
14 %===============================================================================
15 % Output
15 % Output
16 %===============================================================================
16 %===============================================================================
17
17
18 ((* block execute_result scoped *))
18 ((* block execute_result scoped *))
19 ((*- for type in output | filter_data_type -*))
19 ((*- for type in output | filter_data_type -*))
20 ((*- if type in ['text']*))
20 ((*- if type in ['text']*))
21 ((( add_prompt(output.text, cell, 'Out') )))
21 ((( add_prompt(output.text, cell, 'Out') )))
22 ((*- else -*))
22 ((*- else -*))
23 \verb+Out[((( cell.prompt_number )))]:+((( super() )))
23 \verb+Out[((( cell.execution_count )))]:+((( super() )))
24 ((*- endif -*))
24 ((*- endif -*))
25 ((*- endfor -*))
25 ((*- endfor -*))
26 ((* endblock execute_result *))
26 ((* endblock execute_result *))
27
27
28
28
29 %==============================================================================
29 %==============================================================================
30 % Support Macros
30 % Support Macros
31 %==============================================================================
31 %==============================================================================
32
32
33 % Name: draw_prompt
33 % Name: draw_prompt
34 % Purpose: Renders an output/input prompt
34 % Purpose: Renders an output/input prompt
35 ((* macro add_prompt(text, cell, prompt) -*))
35 ((* macro add_prompt(text, cell, prompt) -*))
36 ((*- if cell.prompt_number is defined -*))
36 ((*- if cell.execution_count is defined -*))
37 ((*- set prompt_number = "" ~ (cell.prompt_number | replace(None, " ")) -*))
37 ((*- set execution_count = "" ~ (cell.execution_count | replace(None, " ")) -*))
38 ((*- else -*))
38 ((*- else -*))
39 ((*- set prompt_number = " " -*))
39 ((*- set execution_count = " " -*))
40 ((*- endif -*))
40 ((*- endif -*))
41 ((*- set indentation = " " * (prompt_number | length + 7) -*))
41 ((*- set indentation = " " * (execution_count | length + 7) -*))
42 \begin{verbatim}
42 \begin{verbatim}
43 (((- text | add_prompts(first=prompt ~ '[' ~ prompt_number ~ ']: ', cont=indentation) -)))
43 (((- text | add_prompts(first=prompt ~ '[' ~ execution_count ~ ']: ', cont=indentation) -)))
44 \end{verbatim}
44 \end{verbatim}
45 ((*- endmacro *))
45 ((*- endmacro *))
@@ -1,58 +1,58 b''
1 ((= IPython input/output style =))
1 ((= IPython input/output style =))
2
2
3 ((*- extends 'base.tplx' -*))
3 ((*- extends 'base.tplx' -*))
4
4
5 % Custom definitions
5 % Custom definitions
6 ((* block definitions *))
6 ((* block definitions *))
7 ((( super() )))
7 ((( super() )))
8
8
9 % Pygments definitions
9 % Pygments definitions
10 ((( resources.latex.pygments_definitions )))
10 ((( resources.latex.pygments_definitions )))
11
11
12 % Exact colors from NB
12 % Exact colors from NB
13 \definecolor{incolor}{rgb}{0.0, 0.0, 0.5}
13 \definecolor{incolor}{rgb}{0.0, 0.0, 0.5}
14 \definecolor{outcolor}{rgb}{0.545, 0.0, 0.0}
14 \definecolor{outcolor}{rgb}{0.545, 0.0, 0.0}
15
15
16 ((* endblock definitions *))
16 ((* endblock definitions *))
17
17
18 %===============================================================================
18 %===============================================================================
19 % Input
19 % Input
20 %===============================================================================
20 %===============================================================================
21
21
22 ((* block input scoped *))
22 ((* block input scoped *))
23 ((( add_prompt(cell.source | highlight_code(strip_verbatim=True), cell, 'In ', 'incolor') )))
23 ((( add_prompt(cell.source | highlight_code(strip_verbatim=True), cell, 'In ', 'incolor') )))
24 ((* endblock input *))
24 ((* endblock input *))
25
25
26
26
27 %===============================================================================
27 %===============================================================================
28 % Output
28 % Output
29 %===============================================================================
29 %===============================================================================
30
30
31 ((* block execute_result scoped *))
31 ((* block execute_result scoped *))
32 ((*- for type in output | filter_data_type -*))
32 ((*- for type in output | filter_data_type -*))
33 ((*- if type in ['text']*))
33 ((*- if type in ['text']*))
34 ((( add_prompt(output.text | escape_latex, cell, 'Out', 'outcolor') )))
34 ((( add_prompt(output.text | escape_latex, cell, 'Out', 'outcolor') )))
35 ((* else -*))
35 ((* else -*))
36 \texttt{\color{outcolor}Out[{\color{outcolor}((( cell.prompt_number )))}]:}((( super() )))
36 \texttt{\color{outcolor}Out[{\color{outcolor}((( cell.execution_count )))}]:}((( super() )))
37 ((*- endif -*))
37 ((*- endif -*))
38 ((*- endfor -*))
38 ((*- endfor -*))
39 ((* endblock execute_result *))
39 ((* endblock execute_result *))
40
40
41
41
42 %==============================================================================
42 %==============================================================================
43 % Support Macros
43 % Support Macros
44 %==============================================================================
44 %==============================================================================
45
45
46 % Name: draw_prompt
46 % Name: draw_prompt
47 % Purpose: Renders an output/input prompt
47 % Purpose: Renders an output/input prompt
48 ((* macro add_prompt(text, cell, prompt, prompt_color) -*))
48 ((* macro add_prompt(text, cell, prompt, prompt_color) -*))
49 ((*- if cell.prompt_number is defined -*))
49 ((*- if cell.execution_count is defined -*))
50 ((*- set prompt_number = "" ~ (cell.prompt_number | replace(None, " ")) -*))
50 ((*- set execution_count = "" ~ (cell.execution_count | replace(None, " ")) -*))
51 ((*- else -*))
51 ((*- else -*))
52 ((*- set prompt_number = " " -*))
52 ((*- set execution_count = " " -*))
53 ((*- endif -*))
53 ((*- endif -*))
54 ((*- set indention = " " * (prompt_number | length + 7) -*))
54 ((*- set indention = " " * (execution_count | length + 7) -*))
55 \begin{Verbatim}[commandchars=\\\{\}]
55 \begin{Verbatim}[commandchars=\\\{\}]
56 ((( text | add_prompts(first='{\color{' ~ prompt_color ~ '}' ~ prompt ~ '[{\\color{' ~ prompt_color ~ '}' ~ prompt_number ~ '}]:} ', cont=indention) )))
56 ((( text | add_prompts(first='{\color{' ~ prompt_color ~ '}' ~ prompt ~ '[{\\color{' ~ prompt_color ~ '}' ~ execution_count ~ '}]:} ', cont=indention) )))
57 \end{Verbatim}
57 \end{Verbatim}
58 ((*- endmacro *))
58 ((*- endmacro *))
@@ -1,21 +1,21 b''
1 {%- extends 'null.tpl' -%}
1 {%- extends 'null.tpl' -%}
2
2
3 {% block header %}
3 {% block header %}
4 # coding: utf-8
4 # coding: utf-8
5 {% endblock header %}
5 {% endblock header %}
6
6
7 {% block in_prompt %}
7 {% block in_prompt %}
8 # In[{{ cell.prompt_number if cell.prompt_number else ' ' }}]:
8 # In[{{ cell.execution_count if cell.execution_count else ' ' }}]:
9 {% endblock in_prompt %}
9 {% endblock in_prompt %}
10
10
11 {% block input %}
11 {% block input %}
12 {{ cell.source | ipython2python }}
12 {{ cell.source | ipython2python }}
13 {% endblock input %}
13 {% endblock input %}
14
14
15 {% block markdowncell scoped %}
15 {% block markdowncell scoped %}
16 {{ cell.source | comment_lines }}
16 {{ cell.source | comment_lines }}
17 {% endblock markdowncell %}
17 {% endblock markdowncell %}
18
18
19 {% block headingcell scoped %}
19 {% block headingcell scoped %}
20 {{ '#' * cell.level }}{{ cell.source | replace('\n', ' ') | comment_lines }}
20 {{ '#' * cell.level }}{{ cell.source | replace('\n', ' ') | comment_lines }}
21 {% endblock headingcell %}
21 {% endblock headingcell %}
@@ -1,143 +1,143 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "heading",
4 "cell_type": "heading",
5 "level": 1,
5 "level": 1,
6 "metadata": {},
6 "metadata": {},
7 "source": [
7 "source": [
8 "A simple SymPy example"
8 "A simple SymPy example"
9 ]
9 ]
10 },
10 },
11 {
11 {
12 "cell_type": "markdown",
12 "cell_type": "markdown",
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "First we import SymPy and initialize printing:"
15 "First we import SymPy and initialize printing:"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "code",
19 "cell_type": "code",
20 "execution_count": 2,
20 "metadata": {
21 "metadata": {
21 "collapsed": false
22 "collapsed": false
22 },
23 },
23 "outputs": [],
24 "outputs": [],
24 "prompt_number": 2,
25 "source": [
25 "source": [
26 "from sympy import init_printing\n",
26 "from sympy import init_printing\n",
27 "from sympy import *\n",
27 "from sympy import *\n",
28 " init_printing()"
28 " init_printing()"
29 ]
29 ]
30 },
30 },
31 {
31 {
32 "cell_type": "markdown",
32 "cell_type": "markdown",
33 "metadata": {},
33 "metadata": {},
34 "source": [
34 "source": [
35 "Create a few symbols:"
35 "Create a few symbols:"
36 ]
36 ]
37 },
37 },
38 {
38 {
39 "cell_type": "code",
39 "cell_type": "code",
40 "execution_count": 4,
40 "metadata": {
41 "metadata": {
41 "collapsed": false
42 "collapsed": false
42 },
43 },
43 "outputs": [],
44 "outputs": [],
44 "prompt_number": 4,
45 "source": [
45 "source": [
46 "x,y,z = symbols('x y z')"
46 "x,y,z = symbols('x y z')"
47 ]
47 ]
48 },
48 },
49 {
49 {
50 "cell_type": "markdown",
50 "cell_type": "markdown",
51 "metadata": {},
51 "metadata": {},
52 "source": [
52 "source": [
53 "Here is a basic expression:"
53 "Here is a basic expression:"
54 ]
54 ]
55 },
55 },
56 {
56 {
57 "cell_type": "code",
57 "cell_type": "code",
58 "execution_count": 6,
58 "metadata": {
59 "metadata": {
59 "collapsed": false
60 "collapsed": false
60 },
61 },
61 "outputs": [
62 "outputs": [
62 {
63 {
64 "execution_count": 6,
63 "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKMAAAAZBAMAAACvE4OgAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAACz0lEQVRIDa1UTWjUQBT+ZpvdzW7TGlrxItjYSg/C6vbiDwjmoCgUpHioPYhdqig9\nFJYiPYmW4klB14NgFGnw4EHpj7UgUtTFXhSEBgVBxIOFggWVrrUqiMY3mZkkLNIK7oN575vvvfky\n8yYJIGzgkSlRrULKrivVSkvq6LbxtcaSjV3aSo0lgWyl5pK69V+SRlEsPxNTGYhhDrV3M2Ue2etc\nEDmuMmM+IjolrCuHXNoLoQDNSAXdzbjsfFVKTY1vCgFXFIxenG4cFSSzRewAPnN0FugXjPDr45MQ\nJwoKtitgXL9zT+CsJeIHYG+Z4H1gwhRU4G/FcAQbbYU3KdDo+0sCK8lRU0guA72uKqMYk9RehHxP\niDIu0NS2v90KGShJYi7T7tgvkrQ2vIT2XtRISWNra6lzGc8/PW3ji4PL7Vmge095YIX0iB71NCaZ\n5N3XyM0VCuNIyFNIyY3AMG/KDUvjn90DGmwq9wpIl5AyU5WsTYy0aJf6JFGB5An3Der5jExKHjNR\n4JKPge/EXqDBoOXpkxkmkJHFfAFRVhDIveWA0S57N2Me6yw+DSX1n1uCq3sIfCF2IcjNkjeWyKli\nginHubboOB4vSNAjyaiXE26ygrkyTfod55Lj3CTE+n2P73ImJpnk6wJJKjYJSwt3OQbNJu4icM5s\nKGGbzMuD70N6JSbJD44x7pLDyJrbkfiLpOEhYVMJSVEj83x5YFLyNrAzJsmvJ+uhLrieXvcJDshy\nHtQuD54c2IWWEnSXfUTDZJJfAjcpOW5imp9aHvw4ZZ4NDV4FGjw0tzadKgbFwinJUd//AT0P1tdW\nBtuRU39oKdk9ONQ163fM+nvu/s4D/FX30otdQIZGlSnJKpq6KUxKVqV1WxGHFIhishjhEO1Gi3r4\nkZCMg+hH1henV8EjmFoly1PTMs/Uadaox+FceY2STpmvt9co/Pe0Jvt1GvgDK/Osw/4jQ4wAAAAA\nSUVORK5CYII=\n",
65 "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKMAAAAZBAMAAACvE4OgAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAACz0lEQVRIDa1UTWjUQBT+ZpvdzW7TGlrxItjYSg/C6vbiDwjmoCgUpHioPYhdqig9\nFJYiPYmW4klB14NgFGnw4EHpj7UgUtTFXhSEBgVBxIOFggWVrrUqiMY3mZkkLNIK7oN575vvvfky\n8yYJIGzgkSlRrULKrivVSkvq6LbxtcaSjV3aSo0lgWyl5pK69V+SRlEsPxNTGYhhDrV3M2Ue2etc\nEDmuMmM+IjolrCuHXNoLoQDNSAXdzbjsfFVKTY1vCgFXFIxenG4cFSSzRewAPnN0FugXjPDr45MQ\nJwoKtitgXL9zT+CsJeIHYG+Z4H1gwhRU4G/FcAQbbYU3KdDo+0sCK8lRU0guA72uKqMYk9RehHxP\niDIu0NS2v90KGShJYi7T7tgvkrQ2vIT2XtRISWNra6lzGc8/PW3ji4PL7Vmge095YIX0iB71NCaZ\n5N3XyM0VCuNIyFNIyY3AMG/KDUvjn90DGmwq9wpIl5AyU5WsTYy0aJf6JFGB5An3Der5jExKHjNR\n4JKPge/EXqDBoOXpkxkmkJHFfAFRVhDIveWA0S57N2Me6yw+DSX1n1uCq3sIfCF2IcjNkjeWyKli\nginHubboOB4vSNAjyaiXE26ygrkyTfod55Lj3CTE+n2P73ImJpnk6wJJKjYJSwt3OQbNJu4icM5s\nKGGbzMuD70N6JSbJD44x7pLDyJrbkfiLpOEhYVMJSVEj83x5YFLyNrAzJsmvJ+uhLrieXvcJDshy\nHtQuD54c2IWWEnSXfUTDZJJfAjcpOW5imp9aHvw4ZZ4NDV4FGjw0tzadKgbFwinJUd//AT0P1tdW\nBtuRU39oKdk9ONQ163fM+nvu/s4D/FX30otdQIZGlSnJKpq6KUxKVqV1WxGHFIhishjhEO1Gi3r4\nkZCMg+hH1henV8EjmFoly1PTMs/Uadaox+FceY2STpmvt9co/Pe0Jvt1GvgDK/Osw/4jQ4wAAAAA\nSUVORK5CYII=\n",
64 "metadata": {},
66 "metadata": {},
65 "output_type": "execute_result",
67 "output_type": "execute_result",
66 "prompt_number": 6,
67 "text/latex": [
68 "text/latex": [
68 "$$x^{2} + 2.0 y + \\sin{\\left (z \\right )}$$"
69 "$$x^{2} + 2.0 y + \\sin{\\left (z \\right )}$$"
69 ],
70 ],
70 "text/plain": [
71 "text/plain": [
71 " 2 \n",
72 " 2 \n",
72 "x + 2.0\u22c5y + sin(z)"
73 "x + 2.0\u22c5y + sin(z)"
73 ]
74 ]
74 }
75 }
75 ],
76 ],
76 "prompt_number": 6,
77 "source": [
77 "source": [
78 "e = x**2 + 2.0*y + sin(z); e"
78 "e = x**2 + 2.0*y + sin(z); e"
79 ]
79 ]
80 },
80 },
81 {
81 {
82 "cell_type": "code",
82 "cell_type": "code",
83 "execution_count": 7,
83 "metadata": {
84 "metadata": {
84 "collapsed": false
85 "collapsed": false
85 },
86 },
86 "outputs": [
87 "outputs": [
87 {
88 {
89 "execution_count": 7,
88 "image/png": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAOBAMAAADd6iHDAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIpm7MhCriUTv3c12\nVGZoascqAAAAgElEQVQIHWNgVDJ2YICAMAb2H1BmKgPDTChzFgNDvgOEvT8AzgQKrA9gPZPYUwNk\ncXxnCGd4dWA1kMllwFDKUB9wEchUZmAIYNgMZDDwJIDIPyDiEgOjAAPLFwZWBhYFBh6BqzwfGI4y\nSJUXZXH8Zf7A+IBh////v1hzjh5/xwAAW80hUDE8HYkAAAAASUVORK5CYII=\n",
90 "image/png": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAOBAMAAADd6iHDAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIpm7MhCriUTv3c12\nVGZoascqAAAAgElEQVQIHWNgVDJ2YICAMAb2H1BmKgPDTChzFgNDvgOEvT8AzgQKrA9gPZPYUwNk\ncXxnCGd4dWA1kMllwFDKUB9wEchUZmAIYNgMZDDwJIDIPyDiEgOjAAPLFwZWBhYFBh6BqzwfGI4y\nSJUXZXH8Zf7A+IBh////v1hzjh5/xwAAW80hUDE8HYkAAAAASUVORK5CYII=\n",
89 "metadata": {},
91 "metadata": {},
90 "output_type": "execute_result",
92 "output_type": "execute_result",
91 "prompt_number": 7,
92 "text/latex": [
93 "text/latex": [
93 "$$2 x$$"
94 "$$2 x$$"
94 ],
95 ],
95 "text/plain": [
96 "text/plain": [
96 "2\u22c5x"
97 "2\u22c5x"
97 ]
98 ]
98 }
99 }
99 ],
100 ],
100 "prompt_number": 7,
101 "source": [
101 "source": [
102 "diff(e, x)"
102 "diff(e, x)"
103 ]
103 ]
104 },
104 },
105 {
105 {
106 "cell_type": "code",
106 "cell_type": "code",
107 "execution_count": 8,
107 "metadata": {
108 "metadata": {
108 "collapsed": false
109 "collapsed": false
109 },
110 },
110 "outputs": [
111 "outputs": [
111 {
112 {
113 "execution_count": 8,
112 "image/png": "iVBORw0KGgoAAAANSUhEUgAAALsAAAAZBAMAAACbakK8AAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAADAklEQVRIDbVVS2gTURQ90/wmk0k6tCJCsR1SKShIsxE3CgNWBKUxq9qFmqFqShfF\nUKQrkaDiF0pcCKYgBBcuBLV+wIWKARe6kQ4UhNKKWdiF4KIptmA/xPvmzZuMxdYUzIPcd+655568\nvLlJAL6G32oOasQWNHz5Rvg6nrKh/mygfSzlX2ygPaBUGmov6//NXs1yq4sex2EPrsHemTd2snNg\ntkb+Cx1zBL6SqwxZLvQAKYHzKZaPY4fh4TeHd0S5Nox9OClItm/jiU9DrEwwVEawpiVis9VkimqX\nAOr4o2cCs/0BT2I5+FYJRhJbePQxgzcD7QLEqtV5gdnu2Icr3L45gcCyt74Z7neL4SLQ0nm4S+dM\nYCz1gSPHnhKZDWyHhcCCNKwjqaF/TkwGl0L6nClie/wc1D1xdoNsSLhT0IJkhi7Lzr22xb8keE/N\nPm0Sc9yEuhRUyuiG9HzvFNeImCyq39SriOhtQI7IV/TiTqE8glqwohjE0NJwiANxOZTdZoxtfzSa\nx2tI8DtHcKQoQFmV6f1XT2swibxFL+6k5EgenhBCqKLTPX3ULnaYdDlaTMcCSd8zuXTvBq2bJUJr\nlE4WgSV5ZRdBzLFgO6nzhJp1ltvrlB2HCoWxQuG+jTvt2GxBWUZaU2mMApZNuSHA3vJpCliRhqqs\nZtvbTrb9ZIk+i70Ut1OcnpgeKskTCFUwjaYy8Jhr3eiefq0HIfa7yC6HOwVyULRuNDn21JngbcL+\nE8A+MNnSxb+w59+Cj2tELJBbjEZr8SGwn0j2aLkTPdp08R2OcKV6fXB3ikPH3n8tM5WTfrETtZcw\ng3QWH0dH7nKNiMkszqo/EDafaHhJ5Bm6ee4UtdAabxnMcmUUl0SnYx+uVqs5XAGN9QGgdeCrASv0\n3TmCsJcOdhnozexD38goK9HXynEKr1OKDs9guhQD039kGySyIQpJAdbvJ9YTlPvyUl3/aLUf34G/\nuGxIyXpE37DoLbAHwJaU53t9MRCfrU8o/k4iRn36Lar8Wd5wAfgN4R6xelyy/ssAAAAASUVORK5C\nYII=\n",
114 "image/png": "iVBORw0KGgoAAAANSUhEUgAAALsAAAAZBAMAAACbakK8AAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEHarIkSJZt3NVLsy\nme8Q6PJIAAADAklEQVRIDbVVS2gTURQ90/wmk0k6tCJCsR1SKShIsxE3CgNWBKUxq9qFmqFqShfF\nUKQrkaDiF0pcCKYgBBcuBLV+wIWKARe6kQ4UhNKKWdiF4KIptmA/xPvmzZuMxdYUzIPcd+655568\nvLlJAL6G32oOasQWNHz5Rvg6nrKh/mygfSzlX2ygPaBUGmov6//NXs1yq4sex2EPrsHemTd2snNg\ntkb+Cx1zBL6SqwxZLvQAKYHzKZaPY4fh4TeHd0S5Nox9OClItm/jiU9DrEwwVEawpiVis9VkimqX\nAOr4o2cCs/0BT2I5+FYJRhJbePQxgzcD7QLEqtV5gdnu2Icr3L45gcCyt74Z7neL4SLQ0nm4S+dM\nYCz1gSPHnhKZDWyHhcCCNKwjqaF/TkwGl0L6nClie/wc1D1xdoNsSLhT0IJkhi7Lzr22xb8keE/N\nPm0Sc9yEuhRUyuiG9HzvFNeImCyq39SriOhtQI7IV/TiTqE8glqwohjE0NJwiANxOZTdZoxtfzSa\nx2tI8DtHcKQoQFmV6f1XT2swibxFL+6k5EgenhBCqKLTPX3ULnaYdDlaTMcCSd8zuXTvBq2bJUJr\nlE4WgSV5ZRdBzLFgO6nzhJp1ltvrlB2HCoWxQuG+jTvt2GxBWUZaU2mMApZNuSHA3vJpCliRhqqs\nZtvbTrb9ZIk+i70Ut1OcnpgeKskTCFUwjaYy8Jhr3eiefq0HIfa7yC6HOwVyULRuNDn21JngbcL+\nE8A+MNnSxb+w59+Cj2tELJBbjEZr8SGwn0j2aLkTPdp08R2OcKV6fXB3ikPH3n8tM5WTfrETtZcw\ng3QWH0dH7nKNiMkszqo/EDafaHhJ5Bm6ee4UtdAabxnMcmUUl0SnYx+uVqs5XAGN9QGgdeCrASv0\n3TmCsJcOdhnozexD38goK9HXynEKr1OKDs9guhQD039kGySyIQpJAdbvJ9YTlPvyUl3/aLUf34G/\nuGxIyXpE37DoLbAHwJaU53t9MRCfrU8o/k4iRn36Lar8Wd5wAfgN4R6xelyy/ssAAAAASUVORK5C\nYII=\n",
113 "metadata": {},
115 "metadata": {},
114 "output_type": "execute_result",
116 "output_type": "execute_result",
115 "prompt_number": 8,
116 "text/latex": [
117 "text/latex": [
117 "$$x^{2} z + 2.0 y z - \\cos{\\left (z \\right )}$$"
118 "$$x^{2} z + 2.0 y z - \\cos{\\left (z \\right )}$$"
118 ],
119 ],
119 "text/plain": [
120 "text/plain": [
120 " 2 \n",
121 " 2 \n",
121 "x \u22c5z + 2.0\u22c5y\u22c5z - cos(z)"
122 "x \u22c5z + 2.0\u22c5y\u22c5z - cos(z)"
122 ]
123 ]
123 }
124 }
124 ],
125 ],
125 "prompt_number": 8,
126 "source": [
126 "source": [
127 "integrate(e, z)"
127 "integrate(e, z)"
128 ]
128 ]
129 },
129 },
130 {
130 {
131 "cell_type": "code",
131 "cell_type": "code",
132 "execution_count": null,
132 "metadata": {
133 "metadata": {
133 "collapsed": false
134 "collapsed": false
134 },
135 },
135 "outputs": [],
136 "outputs": [],
136 "prompt_number": null,
137 "source": []
137 "source": []
138 }
138 }
139 ],
139 ],
140 "metadata": {},
140 "metadata": {},
141 "nbformat": 4,
141 "nbformat": 4,
142 "nbformat_minor": 0
142 "nbformat_minor": 0
143 } No newline at end of file
143 }
@@ -1,215 +1,215 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "heading",
4 "cell_type": "heading",
5 "level": 1,
5 "level": 1,
6 "metadata": {},
6 "metadata": {},
7 "source": [
7 "source": [
8 "NumPy and Matplotlib examples"
8 "NumPy and Matplotlib examples"
9 ]
9 ]
10 },
10 },
11 {
11 {
12 "cell_type": "markdown",
12 "cell_type": "markdown",
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "First import NumPy and Matplotlib:"
15 "First import NumPy and Matplotlib:"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "code",
19 "cell_type": "code",
20 "execution_count": 1,
20 "metadata": {
21 "metadata": {
21 "collapsed": false
22 "collapsed": false
22 },
23 },
23 "outputs": [
24 "outputs": [
24 {
25 {
25 "metadata": {},
26 "metadata": {},
26 "name": "stdout",
27 "name": "stdout",
27 "output_type": "stream",
28 "output_type": "stream",
28 "text": "module://IPython.kernel.zmq.pylab.backend_inline\n"
29 "text": "module://IPython.kernel.zmq.pylab.backend_inline\n"
29 }
30 }
30 ],
31 ],
31 "prompt_number": 1,
32 "source": [
32 "source": [
33 "%matplotlib inline\n",
33 "%matplotlib inline\n",
34 "import matplotlib\n",
34 "import matplotlib\n",
35 "import matplotlib.pyplot as plt\n",
35 "import matplotlib.pyplot as plt\n",
36 "print(matplotlib.backends.backend)"
36 "print(matplotlib.backends.backend)"
37 ]
37 ]
38 },
38 },
39 {
39 {
40 "cell_type": "code",
40 "cell_type": "code",
41 "execution_count": 2,
41 "metadata": {
42 "metadata": {
42 "collapsed": false
43 "collapsed": false
43 },
44 },
44 "outputs": [],
45 "outputs": [],
45 "prompt_number": 2,
46 "source": [
46 "source": [
47 "from IPython.display import set_matplotlib_formats\n",
47 "from IPython.display import set_matplotlib_formats\n",
48 "set_matplotlib_formats('png', 'pdf')\n",
48 "set_matplotlib_formats('png', 'pdf')\n",
49 "matplotlib.rcParams['figure.figsize'] = (2,1)"
49 "matplotlib.rcParams['figure.figsize'] = (2,1)"
50 ]
50 ]
51 },
51 },
52 {
52 {
53 "cell_type": "code",
53 "cell_type": "code",
54 "execution_count": 3,
54 "metadata": {
55 "metadata": {
55 "collapsed": false
56 "collapsed": false
56 },
57 },
57 "outputs": [
58 "outputs": [
58 {
59 {
60 "execution_count": 3,
59 "metadata": {},
61 "metadata": {},
60 "output_type": "execute_result",
62 "output_type": "execute_result",
61 "prompt_number": 3,
62 "text/plain": [
63 "text/plain": [
63 "{matplotlib.figure.Figure: <function IPython.core.pylabtools.<lambda>>}"
64 "{matplotlib.figure.Figure: <function IPython.core.pylabtools.<lambda>>}"
64 ]
65 ]
65 }
66 }
66 ],
67 ],
67 "prompt_number": 3,
68 "source": [
68 "source": [
69 "ip.display_formatter.formatters['application/pdf'].type_printers"
69 "ip.display_formatter.formatters['application/pdf'].type_printers"
70 ]
70 ]
71 },
71 },
72 {
72 {
73 "cell_type": "code",
73 "cell_type": "code",
74 "execution_count": 4,
74 "metadata": {
75 "metadata": {
75 "collapsed": false
76 "collapsed": false
76 },
77 },
77 "outputs": [],
78 "outputs": [],
78 "prompt_number": 4,
79 "source": [
79 "source": [
80 "import numpy as np"
80 "import numpy as np"
81 ]
81 ]
82 },
82 },
83 {
83 {
84 "cell_type": "markdown",
84 "cell_type": "markdown",
85 "metadata": {},
85 "metadata": {},
86 "source": [
86 "source": [
87 "Now we show some very basic examples of how they can be used."
87 "Now we show some very basic examples of how they can be used."
88 ]
88 ]
89 },
89 },
90 {
90 {
91 "cell_type": "code",
91 "cell_type": "code",
92 "execution_count": 5,
92 "metadata": {
93 "metadata": {
93 "collapsed": false
94 "collapsed": false
94 },
95 },
95 "outputs": [],
96 "outputs": [],
96 "prompt_number": 5,
97 "source": [
97 "source": [
98 "a = np.random.uniform(size=(100,100))"
98 "a = np.random.uniform(size=(100,100))"
99 ]
99 ]
100 },
100 },
101 {
101 {
102 "cell_type": "code",
102 "cell_type": "code",
103 "execution_count": 6,
103 "metadata": {
104 "metadata": {
104 "collapsed": false
105 "collapsed": false
105 },
106 },
106 "outputs": [
107 "outputs": [
107 {
108 {
109 "execution_count": 6,
108 "metadata": {},
110 "metadata": {},
109 "output_type": "execute_result",
111 "output_type": "execute_result",
110 "prompt_number": 6,
111 "text/plain": [
112 "text/plain": [
112 "(100, 100)"
113 "(100, 100)"
113 ]
114 ]
114 }
115 }
115 ],
116 ],
116 "prompt_number": 6,
117 "source": [
117 "source": [
118 "a.shape"
118 "a.shape"
119 ]
119 ]
120 },
120 },
121 {
121 {
122 "cell_type": "code",
122 "cell_type": "code",
123 "execution_count": 7,
123 "metadata": {
124 "metadata": {
124 "collapsed": false
125 "collapsed": false
125 },
126 },
126 "outputs": [],
127 "outputs": [],
127 "prompt_number": 7,
128 "source": [
128 "source": [
129 "evs = np.linalg.eigvals(a)"
129 "evs = np.linalg.eigvals(a)"
130 ]
130 ]
131 },
131 },
132 {
132 {
133 "cell_type": "code",
133 "cell_type": "code",
134 "execution_count": 8,
134 "metadata": {
135 "metadata": {
135 "collapsed": false
136 "collapsed": false
136 },
137 },
137 "outputs": [
138 "outputs": [
138 {
139 {
140 "execution_count": 8,
139 "metadata": {},
141 "metadata": {},
140 "output_type": "execute_result",
142 "output_type": "execute_result",
141 "prompt_number": 8,
142 "text/plain": [
143 "text/plain": [
143 "(100,)"
144 "(100,)"
144 ]
145 ]
145 }
146 }
146 ],
147 ],
147 "prompt_number": 8,
148 "source": [
148 "source": [
149 "evs.shape"
149 "evs.shape"
150 ]
150 ]
151 },
151 },
152 {
152 {
153 "cell_type": "heading",
153 "cell_type": "heading",
154 "level": 2,
154 "level": 2,
155 "metadata": {},
155 "metadata": {},
156 "source": [
156 "source": [
157 "Here is a very long heading that pandoc will wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap"
157 "Here is a very long heading that pandoc will wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap and wrap"
158 ]
158 ]
159 },
159 },
160 {
160 {
161 "cell_type": "markdown",
161 "cell_type": "markdown",
162 "metadata": {},
162 "metadata": {},
163 "source": [
163 "source": [
164 "Here is a cell that has both text and PNG output:"
164 "Here is a cell that has both text and PNG output:"
165 ]
165 ]
166 },
166 },
167 {
167 {
168 "cell_type": "code",
168 "cell_type": "code",
169 "execution_count": 9,
169 "metadata": {
170 "metadata": {
170 "collapsed": false
171 "collapsed": false
171 },
172 },
172 "outputs": [
173 "outputs": [
173 {
174 {
175 "execution_count": 9,
174 "metadata": {},
176 "metadata": {},
175 "output_type": "execute_result",
177 "output_type": "execute_result",
176 "prompt_number": 9,
177 "text/plain": [
178 "text/plain": [
178 "(array([97, 2, 0, 0, 0, 0, 0, 0, 0, 1]),\n",
179 "(array([97, 2, 0, 0, 0, 0, 0, 0, 0, 1]),\n",
179 " array([ -2.59479443, 2.67371141, 7.94221725, 13.21072308,\n",
180 " array([ -2.59479443, 2.67371141, 7.94221725, 13.21072308,\n",
180 " 18.47922892, 23.74773476, 29.0162406 , 34.28474644,\n",
181 " 18.47922892, 23.74773476, 29.0162406 , 34.28474644,\n",
181 " 39.55325228, 44.82175812, 50.09026395]),\n",
182 " 39.55325228, 44.82175812, 50.09026395]),\n",
182 " <a list of 10 Patch objects>)"
183 " <a list of 10 Patch objects>)"
183 ]
184 ]
184 },
185 },
185 {
186 {
186 "application/pdf": "JVBERi0xLjQKJazcIKu6CjEgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDIgMCBSID4+\nCmVuZG9iago4IDAgb2JqCjw8IC9YT2JqZWN0IDcgMCBSIC9QYXR0ZXJuIDUgMCBSCi9Qcm9jU2V0\nIFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9FeHRHU3RhdGUgNCAwIFIK\nL1NoYWRpbmcgNiAwIFIgL0ZvbnQgMyAwIFIgPj4KZW5kb2JqCjEwIDAgb2JqCjw8IC9Hcm91cCA8\nPCAvQ1MgL0RldmljZVJHQiAvUyAvVHJhbnNwYXJlbmN5IC9UeXBlIC9Hcm91cCA+PiAvUGFyZW50\nIDIgMCBSCi9NZWRpYUJveCBbIDAgMCAxNTIuMzk4NDM3NSA4Ny4xOTIxODc1IF0gL1Jlc291cmNl\ncyA4IDAgUiAvVHlwZSAvUGFnZQovQ29udGVudHMgOSAwIFIgPj4KZW5kb2JqCjkgMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAxMSAwIFIgPj4Kc3RyZWFtCnicxZi/btwwDMYz\na+wTCJ3aRSEpiZLGHtAG6FbkgL5AmwTBXYCmQ16/dJycRcWq7SV3k81Pf76fzyZpo703l1/Q3v61\nZL9bsE8W7ZUBOTpajOR8ycGnKOcHdZ6Tw0KY5fAgojq9Mw+yKA2Lgiv+9WdvZeCVoewCR6ZoCVyk\njHIkewVw0IYPdTix8y/hao0qKvveiHOhcF5t6qJgqWDPRRXlkwmzm92vHp1g8rYzzf5on8xuby+/\noUWw+xsjO2L0w+gk06Ld/zKfPn64wAv4bPf39uu+XeGZwITgAuSQCQMVZbtRlHWt1fYbZRNCIAdA\n5F/mnjAWEFiiEb0vlGNSCI2iELRWIzTKJoQYXSglJU7PcyeEpf9BDFAJWDhQZgXRKApCazVEo2yC\nSOiQ0efhCnANQQsQhRz5BNHHhEFBNIqC0FoN0SibICR5QCjxde4E4RcgELLDVAqCTPQ6nzSSwmjE\nmqOVNoEgkCuFwuvkiSQskVBwSDTejKhJGkmTaFGRNNI2Esyu5PLyp9QkcYlkLpHr/K4J5jK8Gr/R\nuQ9Sc8bxlW1esL1YD6BjermIrTGdHI8VAXm47sDr8unkz6Pj/Mb1FG1c18Nnw6tcyzM/bIahMryU\neCZzUkOk+rSWp2hjuR4+G15pGUazvjgPle+lJ3RyGIPUvje+p2jjux4+G159qSPIZpXl9fc0RykT\nbyxP0cZyPXw2vNby8yy5p6hynVe77vRaXKeDFemDNxVUuc6JXKqfQWkIJs9/ZpMColBaaSmyffxt\nf9qHsZ12BFKZMbIUZxkbEBOHBCw20unEPk49atUtXxlhoITscwhNv5cdJ5TWC1TVO2ghBUkqYQRX\nS1WC9Mw788O+J9S896ON0gXIxBDZqwp4aBUxFQb3puE9CefA6rk/Dk+NzJQcSZLgFZdSzH+IK+Xd\nwXr2pW/1LnNhOaeowZRiusjnBevZP9o8ZK4i60pTrp8vpZgu8nnBevalSQfHsiYDSJekTCrFdJHP\nC9azL2BFsn2W/MaQGrBaMV3kM4N17A+vI0k8JOZEgM2nESWZLvR50boAwoaylaTvBEneMzSbkkwf\n+8xwPYLx7YtYXAafC2s4JRkpW5B5jtvW0gg3mk4+UZSmm9SHrBX9z/WKNxc9fsvXuu7w+ebt2ph/\nACMXFgplbmRzdHJlYW0KZW5kb2JqCjExIDAgb2JqCjg3MAplbmRvYmoKMTYgMCBvYmoKPDwgL0Zp\nbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aDEgMTkgMCBSIC9MZW5ndGggMjAgMCBSID4+CnN0cmVh\nbQp4nNS9eYAdVZ0vfurudavq3rr7vvftvdOdTtIJi6QTsnQATdhCgsYECRAWIVFAwAUGWQL6JjDj\nAEEQRJYAvsnNnbZZxjfkzVMExhl7HImgeZBRCIn6BnUcRudB8vt8zqm66QScef/+DqnvreXUWb6f\n73pO2QpNCBEH8Ynq8iVLlwleawdAhLl81cozz//y80lcm0LoZyw/8+zFIiXCQvvNBj5feebw6M3v\n9H4RL+zA9YbzP3ne5v959xPrhTj9QSEC2fOvvrIaXKRVhTj3RDyvXrj5ok9etDjUI8Q5T+Od0y+6\n7NoLR5ee8b+EWLdJaGdt2LTxk9fkfn3RLCFCWSFWbN10wXkbn8ze+XPUHcT7Y5twIzjoXYPrjbju\n2vTJK68pvnny6UJ4QujPvvSCT12+7NTTbxHarheEqC+57Irzz1v629+uRv8fE8Ib/uR512z23hfG\n2LWtHM/l533ygq985Ml/EdqPMD/jbzdf8ekr77zla3cJ7fVpjGHW5k9dsPmkX106T4i1eK4NKd6I\nxZenf/fv66Mn/psoeCWjPtds3cDf7994/87Daw/t8x7wfhOXuvAIVfCe98ChPyM9vPbwWryliaOK\ndhPvgG4UQXE2sFDPw5iZ0B8B0YTXE9XuEH7h89zuAQfEqepX+7gY1bKs5/d6+OPFUHauEtVT3LZP\nW/GRlWJcVP+vB2P4a45BW4rbX5X9/sh7j6jiPw+Hqv3OGU0aDf3lBxxXiw2e3WJEHm+K1Z7TcX3s\n8aawPINigzeMOj8UG7SQPJZrocNv4/gNzj3az0SEbaE/HhHvdbK+OhaLEW9LLJS/H3B4TlJ1ZF+D\nYlQeJ6E93McYz3rfcf7h99Aexx7wnHT4t51jUGTkEURbziF+LU7gr/cs595u5/desQrHWu3bouKt\nigF573wxoX0KeLwmTtd8wtR8h/8Vv4tw1MSvD78p7/9OrMBc0e7hn6tfjHNQfERep8XZOBahvRzu\nldFeL377OB/gPIdtoM+P4HoA7y3FcQ7ORz7gGIM8baEkEj/5zulixGn/bK0XfeZkvyPOr8DRLXYc\nXos+ycez0Nc7fA9jnIvjQ9oJ4gQcS1FvAs8mtQ+j/q95Lk7g2OX88A6Of0b9CTk29nsv5yYC4N/J\nePYbZ/wT+L0Jvyc74+Vvg2OceXjvlfwpy+tBsQkY9+AY1y4WY9rpoqL9iajgWa98Dt5D9kfA6zEc\nIe8i0e3OF3zIuWMhTzG+YRyDwOx+HOvdA+8tmHFs1E4TpxILjCGrPSFqPDCOk4gRecyxE2+pB4Pi\nLNSPyHGAlxjnIMZZx5z3oP8JWRfXcu7HHMRIyv8PRQS/PLfdwzN4+BD6zfBgu5RPxecO33GI1ezH\nweA3zvEmx43fFxxZIS83eL4movI4IIblwTHMEVWMYcLzMfDkTdGn/Rp8rYgLtP9z+Pe4l/N8TywH\nj9fTHoCHZ+BY7vyeQZkhj4+yCa49mGkXaAM+wDbQJsw8aB+UjYA+hA6/C9twBo7EMfahc3RshGsn\nXJswsx/XJhxtG44cH2QjcEgb8UfsAnV35iF1Venr+/Xx/GMOhbsJbF7B8VvgEqLezNQd58jDy53j\n6Id7xGfqCGUURxJH2ZXRzgF5nHl8kOzJQ8md3ZGzFnj7U8jlh6UOSUzJC5QR+kld9/uFN+CUoJ8l\n6A8GPSy+gN8fCgZDekgWf0g+VlX1gN8pHtwP4K4v6A94vfJFr9/n8Xn8Hq8X9/y4CPg9HlUbHQb9\nXq9XvYr7QZ8PV6iuuvSg75BHvqZKCC+GQvINtoIzHd37fPJ99hX04AJPvQH+C3k9ul+17vehbTxj\nXVnT4xQvJhyUcw3iKYYu5+Rx2RB02CCLywd5TSYcKQ4jnL5QAoHOfdWjnJUzGE6albzu5P0cHSbi\nDegIBcLEQfYY4CHHEQgFvbI6miMGDg6BkDNMVtTVKCQOuoTOBzhkL152DRQwM698BcwNeDzqBXQY\nDKi2MXX8C3KEAY8aN36CIY+O+kFXNnRUCoV8Xh8v0KDXG0b3nanhDnAIeCkHpCGfJxzwOWOTDA2Q\nQcfgQJaS/ayAriTPPYoNQZcNnHIw6PKBwiCZcKSounogEDgKGKc40/F04J2Bgyv1Ph9nHwQOhhEI\nCK/sISj7JeoBPaRwgFiGdV3ngRLQg+74QsFwh1HAEwhBiPRAUOHgpWhCOL2UXdTzecl6VRsdSpTV\nWDHPkMTBq3iKH8i+DviC7kzDeFnXMQFeoEGv1whSYp2peX06NYU4hAiF7vMaDg4BpcAB1vUeXcA+\n8i9ITcZ8A5y8R7Eh5LKBU5aK6FV4Kia4KLmMCIU7Aul35VjWcabjTBW3fEqHleLI9wkuZh9CXGxa\nxEH2EFK9YADBsK64iREaum6YhiyhMAcYUsMxJGK84cU5Xgz5wzhcHMAYL7jmM4Kogq5wrmZomgE5\nuQD1z4P7IRqZoItDgDgYXsUJSkaIF1AiH+URrYS9XgtjVTOhdPkMWhlw1qdDJYNhv9cM+h0F1/1S\nvQNKrGcU6LguK3AYEC925PEqHrhsCKPoussHKCY4ASY4KDlA6SFDckExNujKs6NIUhR9zkyU4Qr4\nHJFSmhSCxOqGEJYVDAqfahH9KoRDR3AIGuGwYTk4yEE4Q7X0o3EAa4wjOODuDBwCXr2DAzrUQ+5Q\nPBT+4NE4YOoGbuouDhZwMAyFAwA0vD6Jg+QzrBVxkIOAPhIHw++1HBwoUR+MAyYcDrP9MI2wrljq\nIRvCsig2HIMDLhUOZEIHB90KdpAJhf4LHOSYj8IBbtanW0JEoh0cdLcXMDysHAlGCBzMiClLyJS+\nQo4UOLiS4w2asFI4NSF/jgnkXZpyn0nnAubSvUqwo5EgJ+eTPXl04gCtD3kdyxEkDhbqS5/ENyK4\nME1lFzAXy+uNuBKr3LBJa4/24Mrwzwx4IyHHdjpKSy5I7s/EgXMFDkGSkMIBXYcdiZNsQKH7hLvX\nHf0gE1Rx5BbF6ozGASZ0xKBRFNVUdQZENFzBI66Go4N59+kRIaJ2KCR8snPioPAImR0cQtAFK2rJ\n4vBe4RB1OgXOIQvQhYFDSA9IHHyQfcQqIQQjlsTBBw66OERRFXOTI8E9X1ji4OvgEA57LV94Bg54\n2bJg43kBHPx+G91L5hIHr9/y0SiiFyPEqgFf1MEByuHIphTGIwXWLSyZrVNdMV/JUq8ffFc4yKFS\n9MLGERxwn0zosNrRnajigjvcGThQ8OkjjsaBouPgEFI4GFEh7FgHB4P9spi6lD9wBwpKDBwcwpZ0\n2lI39KghRyJxiEgVClpQcxcHHSjoxIFOPugzdAcH3bZDUshCHC/4AZbDV+kuDiEHB91wZxrFRSQC\n28ILhQP4pWYi9cECpjq0Ba4MUUUk4IvpAcWQoOVEe9LPzyh+TpYSTXUNozUcEgdDab6UNHVKHEKy\nO4cJYSdqUUCZRlRxQQ23g4/UeZ9PxtvOPakHDAoCjsu3JBbAwRYiFtN14XdxUI4Agm+pWB/MAAaR\nWESWcASj1cNyOEbMcIfjg26YcOahiN7BQXdw8Ec6OPiVHqFDafXCfOANGz7DwcFJLzAWfxT1OzjY\nR+MQ8ftjEgelHuzij+FAJzYTB/9MHCxKSJjqGjalKTC8fgcGS7JBzVPioAaDKzBBGisZQToVYnqn\nKAVxcJCRke4GWkfhEDiCgwlHbcSEiMeJg2It+pE4gOEKhzD6BwbRWFSWcJRO23BxcDXYp9uYsGmF\nolBzmaJIHGBxwKQoJQ04hB0cwujQoLLLC68BHBhBhn0qd/KHXRxMsok9xPByNAqF5gUa9PvjkEJH\nBNBDIAocwmgvaIUDqBr0xcPBDg66jLoJ4FE4kNl4YChiyJAQFs4yLcltxQYUJZBh2R0uwQSJg/TY\nLg6uHaPPCTvPpGNBR2EXB4MJQsBNQBRqHJ2pB/0WcEgkwmEHBxMdSXmIGNGIEk4oKDCw47Yshm26\n44sYCUtqEHEO27BYFnAImw43wRVKNphkc4Yhv4VzBRw6NPkgTFvsxalJHAx/0NUHmIKY33RjNMOI\n40Xbho1Hd3jR9vsTGKtKaqQTsyFmBvKSoGUETMMO+hOGxMxwgglG3ob/qBJQzA4bVFcjYkqWEgdL\nab4yOCiRiMsHGEhwwrb5xCmyqpUwHHNON+7ad9PpkSMMONWdgEolUcruyLDTbyWESCaBQ0CZPuAt\ncYi6OIQdHBIKB1PiYKqRzsQhFo6ErYgOOGbgEHZwsI7GAR1GTEaBEgfofSSMTMj0d/QBU4/5I6Zl\ngu0cTRygxGKYA2QYViLm9yeVmVaqThzAaIUD/sWC/qQRVFZep+0Od3AIzMQhGjWNsEl1RTgIAxCJ\nEAc5t6jDhg4O4f8Eh8gMHCz1SAq14UwHnSlHYzoBFV2+41kgShE4auKQShmGCEizg6E5AzDtqGrF\nChvAIJaMyWLGaDxNVTkhe2PHfiNuRDEoPWZY7vKLQRxMZFExvGACB9PBwUSHUeIguezD/Sgj+Rk4\nQAYS/qgbK5tmAhoSj4ckDrAScb8/BSlU2i9xiAEHE5MNRc2gZcZD/hQibDlR4MAuKajH4KCYbVg2\ncLCACBnq84PvygLL1yl6UTIiEJaw45JMMB0f4jAiklBckDhIJTYVZ/5LHEyaeeIQTQqRTndwwBhs\nqRe2GVM4GNBd4BBPxWWx4hYHoHBIKR1iRGEmAB3cR9yMhJxFLqIjcYiToTr46verztFh1GIUKHGA\nI4pSYy1nDRFvYerAATGaqax1CiBKHCCtSP4TgWAaY1USKZPYOLTPxSFCHNKmim0MI2r8ERwo2hZx\nMEgsaYN8QQUCH7FQ9KK2NCyyO+BAJsg5y5Gp2ilXHqEglrLrNFemMx0IiuKUJVNDnemjuiNxiIZD\ngWhKiEzGNF0cgLfUtJgVt2Vegv7NRCwWTzs4JCISJhYrFZWWDN0GgIPt4KCrtS4/7wYsJKtxMM/S\nA1EroHCw0KFNHCSXfQiEbIlDoIMDdDERsN1YGTjAiCQSiHnYHXAIBjMKB0xe4YBM18LUENqFYK5D\ngYylcDBVMGFRUI9agnNwgEeMAYcIELFxTRzk3GKKDZyyHWPernAALLgjnbcqylqnrIiru+rEch08\ntf5YHMIzQuAYcLARuEbTQmSzwCEoG4yiHzUAKxGT44WYm9CFZCYpSyQZIS+kjYpkbOWmMEUracUw\nKLiMqLMKG3BxCCbI0DD4GnCcEDq0I65I+KLAgTlqxFnLxVu2HUgG7IgNky1nlA5ErGQS2QZsCXBI\nBoNZjFVNXOKQcHGwESpYST2QtXTH28Ypp8xEj8WBoo0K0TjtbCwibZAvqCxPLK7YkECJxVw+0DjG\nyQSFg5RXFjsj7zgexXL1JGI500HArfxIZAYOinVxgotkzs4IkctZlghKcafWScWIR1wcbNNKJRLJ\nrItD9Ej32Rk4pGCxYraRJA5qsRF3zUAEF0kwLwIcIg4OEXQYkziQy75oFB7kaBww9XQg5uYskUgG\nxjyVQphPmx4MpoLBHOyFsgxcOdKT8NERTFaPR0LRSEoP5CIKB9gzFf4ZVKSZOAQVs61owiQYEWmD\nfGBDTGm+ZIPEIU5GmrZ0VOBEMimdtyrKa2aPaIjCIaIcfAeHkFNdRa9GB4cIpSRmhoLxnBD5/Ewc\nEmoAkWRcpqsWeJRJJFK5lCzRNIcQVZVzMenGcCMQSUfiGJSZitjhIzhYEgfcIw4xDEt1jg5jUXco\nPhs4UGMj7n6GFcDUOzhwNNlANJJOI06l1QgG08FgHmKgJFIu6qQcHMJxhGyRtB7Iz8DBkknRMTgE\ngAPEKmrZCYiDHY92cJAlodhA0Ysn5NpkzMGBTOjgoBgRzykuKEMlH1C5nB4tFwe85uDgpCLS7iAq\nRwJBHAqFSESEZIMx4C0NVDKaSjo4RCLZVCqdS8tiZ2zy4oNwSETiMTMdibk4RIhDFHlLmkmgEYhH\nA8oJRdFhXOLAuMAPIxTnmk30CA5x4hCPxh2nGc3hxUwGDs5WOIRCBXQ/A4c0rGA0RP8U1WPRTDhQ\niIaVw5OGFOEQDEZALbw6MIDj5GjEhgoDjJj0Bf4QIZBSrww/SjKpcGBnuCQTOGvlSBRoM3CIxaLu\nM9WjwsGZiLMSQhzUjSSsWQIpP3EoFomDNDuwfimpaSk7rXCAmEegC5l8RhY7A97HbDnWeF4ld2gu\nGM1Gk9FE3ATPwwG5CAzZD0aCNvKWDF6wjWACHFRuDR3GY/C6UbLVj8QgTo21g86aZSQYTwRzwbjK\nWTiafBA2GDjAT8bhNTOhUBH2QumKxCGDMNAO2XY4aeuoGg4W7bCtZDIlxZMhaPCoEqJoo0IsBXFA\nWB6JJ4hDMknLk0wpNlD0FA6RuIMDmECbrEamGJHIKy4oQ2W7o3Z6pKSEnHszcHA8fEThkMwLUSpF\no+/HIZNycIhGgUGukEPJ5mLZOBtUlQszcMgRh6SVicYNtZsIU9LBAfVM4hBQnaPDhA0c5IU/Hg8m\nHByUqEYCiUQgh/oJV+IKACWbRb4A2w0As6FQCWLg4gDf5+JgJO0wqoaDJQeHaCRp/VEcKNnROM0m\nwnLpC/yKDR0cKHqplMsHKmUGbKAtcHitaheO4KAeyVFD0WkaaJ10555aNzedVIR2BzgkI8ChIES5\nTByk+U+kUypATcdcHGAoC+i9mJMllotTJhUOpQRNGQUgaOftlJ1MWVk70cEB6ARj4FI2hpjDDCYh\nycqtocNEnDjEMBd/wsEhFgy7+pBIBvPBhModOZpiMB7L5ZD2wgbgxVwoVEb3ygpzoSCcRawUC8Vi\nRioWRlUjWI4ZsqtoNK3CcIv5eDAYOoJDMknJjsbTUYIBHJLEQVkeFMkGiUPa5cMMHJyRKUakSooL\n0rHKRzEVaHX0QXfqy0RPrQQoVqRhzFKRcChVFKJSsW2hSxyS6XRGDSCWld2HIOZ2MZvNl/KywBax\nQQVaKTkThzSsaSQHHJwdKdwlDrqeUzikOjigw2QcqikviAMiEAzMxSEaTBKHZCzl4lACDvm8wgFe\nM6/rFXSvrLDcNssRB13hkIjljWDFwcFGYIHyfhxCIZoYWpYM3FcinZC+wK87OGQUG7Io6bTDBwYM\n4ASY0MFBMcLFgYXsPxqH6H+KA8KrVDSsp0pCVKvEQQoBRCQrLV42nss4OMCe53KFckGWeCEh1UVW\nLieVc49BFAuxTCyVjuRjSXe7CiyKhuIhXc/HUc8KpSDJKrxAh+kEcWCM6E8m4MmBQzzk7ChEQ5h6\nIZRWOTxHUw4l4oUCsm84UOBQ0PUqZAbsZddcwc8jIInrcfinuAF7aYaqcVPFEtGMCsNhMEJHl1Qq\nm0WFRJb+LpOwYQrSfl1iAC4oNtAEZDIuH2wbl2ACfaNTlO6UFRekoVE8kfYi7kwHguLMxFmRkmuX\nSt5hzNLAIV0WolaLxYQu3TBERCUK2Xg+q/ZsUnYMulCsFGVJFJNsUFZOVlJyRBKHInBIp6MSB7UZ\nFYPBnolDuoMDOswkEYXKiwD8YAYe9ggOdghTL4YyKofnaMqhZLxYNA2LF7oOHGoQA2Wh5XJqB4cM\ncSiaoZqDA5McmuYPwCGdBg4wflm4r2QmIX1yQLGBOEg20ARksw4fUHAJJiQVswmUql1J/Cc42C4O\nuPU+HJiCZeywnqkIUa8fwSGbzckB5BL5nIMD7Dl6ryocksUkgzpVuYqYLillIxQvxbOwptFCPGXN\nxCGBi0ICeEVCGUiyCi/QocIhgbkEUhIHw0iEjBk4lFA/oyLIZLISSiYcHFJ4sajrdXSvvKHEoQAc\nEnoiYWUSRioBHOoJU3YVs3PSWjA1DoU6n2HxjKYeFVI5qGUqm5Q+WeJAY5TLdXDI5Vw+IHBzcXBH\npnCoKi6oSFf2K+124ggOTv0ZOChW5CQOhp6pCtFoxOMinJW2MJfLS4uXTxQUDrF0LF4pFEq1kizJ\nEpPrpKycqqWP4FCO54CDXTyCAyKbGHAIh4vH4oAOsymYSHkRQDyShWU/gkMslM2GyqGswoGjqYbg\njEoWMnsUXS+Fww3goCy03J0sIkBPoD0rmzBR1Qo1EpaKrWM5aa6ZGh+Fgw6O5/OJZDyVjxGMZDwL\nAAJhiQG4oNhAU6xwAB9QcAkmpBSzpd2Qpaa4IAPN9+FAy2k495yldCclJA6IJLIxI5ytCdHVRRxk\nOAQRKagBJIt5uZ4OcxOHLpTrZVlS5RSDOlk5Xc/INAfN6YlKIpfIZu1SIq1wQGoCx6kn9XC4lARe\nET0LSVZhHjokDkaCsXogndIlDknd2dOK6TAFFdTPqggylarpqWS5bJkROlFdL4fDXZAZ5Q0lDiWk\nRclwMmnlkib8lqV3JS0V08XyMrxkaqwfXehyUSFdgNlM51PSJwcUG+gFJBtoAvJ5hw8ouCQTOGs1\nMlW7rrigMg7Zr0o8nOlAYZ36M3BQrMgDhxxwyNWFaDYTCReHfL4gPU8hVSqoPUwIJXSh0qjIkqqk\nO91nGhkVNxGHaiKfyGXtciITUV/9wLXqcT0FHMop1IvqOUiyCi/QYS4NHGBkUqlAJq0jEjTNlG4q\nBsV1iGAV9eVaCkdT19OpSgU4wInixUo43ET3ykLLTbAyAvRUmPFaysykKpbeTFlqbEhyGNbQYBwN\nAyZcLDJSVzikpU+WONAYFRQbaAIKBZcPCShlCUzAg5RTFA4NxQUV6cr7KvFwpgMcnJk4WxrEQb3P\nFCwXN8O5hhDd3cDBkGFptlAoSotXTJUdHBA4QBeqXVVZ0tUMG5SVM11ZOSL6zmQ1WUgivSgnj8XB\nMN6HAzrMZbgvp3DI/Kc4cDQNHc6oGrEYv2fC4aphdEscKFFy80XigMlG8ikLVSN6dyry/4hDhmYz\nU8goHAyJAbig2EAT4OAgAyhcggkZxWwCpaL5LsWF/wIH3HJWyuVafgeHfNw08l1C9PQkk8KQYSn0\nsSQHUEqXixKHBBxWo1yuNWuypGsZqS4s2aZadJI41IBDPherJLMuDkloiZ4GDpU08LL1PCyKCvPQ\nYT7DfTmGisFsRs8nEqaZdnFI6Pm8XkP9fNqJIrv0TLpWkzhkFQ49kBlloSUOFQToaSOdjhTSVjZd\ni+g96YgaW6JI/qVpMI7BIZ8vlVAhWwIO2WJW+uSgYgO9QAeHYtHlAwI3cKJWw4O0U1TtpuKCDPiz\n8r5KPJzpwHA6M3G2loiDer8IY1ZImEahKURv7xEcYP+k5ymnKyW1p4/+uyqVWrfCIVPLskGFQ3dO\njgiwhlP1VDFVKMarqWxUfeQGHMKJcDpsGFWJQ7gAi6I6R4f57BEcsmHggIGFI2qLNwEWhevhfLrg\nzqgZzioceBEO1wyjF90rbyhxqIYVDlEHh3BvB4dSB4fwzKKHC4VyOZ1JZstwXxKHgoNDUXoByQaa\n4lLJ5QMCN3CiVssqZhMohUO34sL7cHCmA8Pp3HsfDiXgUExEjEK3EH19qZQwZFgKEXFwyFTLak8/\nn0zBJtV76rJk61kGdrJyrgexdVYqYjjVSJWIQy2Vi6qvEUMpOM5wBjjUMsALOECSVZiHDgvEAcY+\nkwnmsuECPKyVCUcVi5LhQj7cQP1Cxokiu8PZTL0ejdgMZgyjbhh9kBnlKeVmZA04ZAzEzcVMJJep\nR8N9maiKrZFsMrzkUtEH4IAKOeKQK+VkbBQkG+gUHBxoistlhw8ouCQTOGs1MhXN9yguyIA/J/tV\nCaAzHeDg1Hd2LOSeilK4JHGIGsUeIfr70ylhyrA0Xy5XpOepZGouDvCrtVqjtyFLtpFjg6pyr8IB\nsIbTXelyulhK1NN5W1cfrDg4mGadi7WxcLGDQ39/qpCDq5IXwXzu/TgUw13AoejOqCeMoKABHOBE\ngUPDNPshMyoqkTjUkShl0J5dykTymUY03H8MDjTcR+EQBscrlUw2laukCEYuXSgCB1NiAC4oNtAE\nuDjIwA2caDRyitnEQUXzvYoLKuOQ/Ur/eQQHy5mJs9U6E4d4vJSMmqVeIQYG0mlhyrAUIlKVnqea\nrVUkDqlCKg2b1NXXJUuuK0+ZlJXzfVyElYoYTjeBQ+koHNLQknCWOGTxTixcgkVR4TY6LOa5T82Q\nPQgjBH8ZiWRdHFJhmORmuJgtZdV6Tr43nM92ddkR5lF5w+gyzQGIgfKUHRyyJuLmcjaCqnZ4IGur\nhChVIf+yXCqS3O/AYJRKtDDpfBU45Cs5GRsFFRvojSUbiEOl4vBB4QAmyCRb5Rmqdp/igky85KOs\nSsSd6QAH594MHBQrKql4vAwcyn1CDA5mXBwgIjU1gGy9KvdbU0X41Xq92d+UJdc8gkOhvyhxAKxG\nppmpZJDmNTIF2/m0J40AxsgaptnIFrLZuFGCKVKdDw4qHORFsJA3FA7q0wpM2SiWjKYxA4c+I59t\nNu0ocEBto2mag4gnVVTCN6INJEoODlHED7Yx2MGhKnGg4TaOLhIHqEEN7qtQyWfKUASJQ0V6AckG\nmuJq1eUDAmhwotl8Hw79igsq85P9Sv+ZdaZjGC4Ozlars2RIwwenUk4Bh34hhoYyGWHJ9KBYrdak\n56nlGgqHdDGdgU3q7u+WJd9dYICtKvcXZdovcejOVBFdJLsyxZjzMVsGjtPIGZbVxUXzuFGGRVHh\nNjqsFPi9QA5zCRULiKjSkUjOcBBMGxDBbqMCY6HW1Qp9RiHX3Q0c4EQLptm0rCHIjPKUcnO+Czjk\nLMTNlVy0mOu2jaGcrXKcdJX8y3HJ7hgcyuV6HRUUDtW8jI1CZAOdQk2xgaZY4ZCWOOASTJBJtsoz\nVFbVr7ggAyC1QSD9Z86ZDhTWmckMHBQrqulEopKyrQpwmDUrCxxkelCCH5IDqOe7agqHUjoDm9Q9\n0MFBmi2W4oBaDAesRrYnW81Wyslm9mgc8sChmQdecaMCSVbh9qxZEocIjH0+38EhPwOHqtGD+pW8\nE833G4V8d3fMjjOYMc1uy5oFMVBRicShiYQ1b+XzsWo+Wsx3x4xZ+ZjKcdI1GebTcB+DQ6VSr6NC\nsY4wolgryNgopNhAbyzZQFNcqzl8QMGlwiHvFFV7QHFB4SDvq0T8CA7OTJwtb+Kg3ufSUDVtW9UB\nIYaHs1kHB0THDRkBNPLNusQhg8ABNqlnsEeWQk+RDSrQBstyRBKH3mwNM0l1Z0suDlloicShm5sX\niRk4oMNqsYNDqWggM8LAXBwyRrVq9BpVhQNHM2AU8z09wAHBDHDosaxhxJPKU8rP7rqP4GCX8j0x\nY9jBAXGWdJvvx8GsVBoNVCg2EEYQhyoUQeJQk95YsoGmuF53+YAAGpzo6SkqZhMohcOg4oJMvJRs\nyjgm70zHwQGvyQVZtfetWFHPODgMCjEykgMOMj2AqnbJAXQVmg35HQj7H2g2e4d6ZSn2FimTsnJp\nCDlOUeqomevL1XNV4JArxdWX68DBzJgFEzgUSgXkKlVYFBVuj4woHGDsCwXgYEocCurTFEzZrNbM\nPtSvFpxoftAsFnp7FQ4l0+y1rBGIgYqlFA5mMlmwCoV4rWCXCr0xc6QQUzlOpiHDfDwuyFG5n2oa\nZrXa1YUKpS6EEaV6KUeGhsgGOoWurg4OjYbLB4kDmcBZq5GprGpIcUHh4OSBPHGmY5oRp/4MHBQr\nGsChlrGt2pAQs2fnciIi0wOISJeMxLoK3QqHLAK4we7uvll9shT7SmxQVi7PqhzBoT/XyNWq6Z5c\nOe58ZJuD4wQOkUgPN5GSZq2DAzqslSKRqMKhXDIRtxAH58PRrAlT0I/6NXdGQ2ap0NcXjyUQVJYs\nqy8SmQ2ZUZ5SfqzSY8JDYrLxesEuF/ri5uxCXCWm2YZ0m3Sg5tGFoU+hmCt3IYwoN8oyRg2RDXQK\nXYoNNMUKh6wMZHEJJpQUs4mDyqpmKS7IxEttmKkFEWc6MJzOTJxPQGbgkE2l6plYpD5LiNHRvItD\ntdFoygigWezpUjhU4Vd7evqH+2Up9Zcpkwq04Sqaljpq5gfyjTxw6M1XEjNxKAKHXm4iAQdYFJX2\njI7m6mXgAKdbLIYqZUS2WdsuHsEBpmDArBdrKrMtl2eZ5WJ/P3BAMFO2rP5IZBTxpIql5McqvcCh\nGCkWE/ViDPFD3BwtxlWume2S6RaXTo+GwWLogwrlZq4AMMr5o3BoKjbQFHd1uXxAIgNO9PfLxQ6V\n7ykchhUXVAYu+5VxTPEIDs5M5MK4+gZBsaKLOGSBw7AQc+bk8yIi0zSoarccQHextylxyCGQhk0a\nGBmQpTQgcZCVKyNH4dCVrzcyfUdwyENLJA59Cod6Bwd0eAQHnTjkcjNwyLk41F0choHDwEA8lmRQ\nKXGYAzFQEYvEoc+EhyQODeIwEDfnODjkc00ZvtCBvg+H7u5iKV/pRjhX6arIGFWPSF2gN5ZsoClu\nNl0+IJEBJwYGZuCgstsRxQWZAL8Ph9zRONCZH8GBS3QN4NAYEWLu3AJwkGlaDX5IRmI9pd5u+cFZ\nDoH0LPQ+W+FQHqgw4ZSVq7ORa5aljpqFwUITUV6mv1BNyC0nB4cScOgvAa+U2YBlV+nn3Ln5RgU4\nwOmWSnq1YjaIQ+kIDo26OYj6jZJaZ66MmJXSwEAinkRQiRcHIpG5kBkV08rPMfqBQymCPLKrFKuW\nBhLm3FJC5fy5bnKnxCXsY3BgCIoKlR6Ec5VmpVBvEAfMqym9sWQDcejudvng4iAXnVTerbLb2YoL\nMhCtyn5lHFPq4GA7M5mBg2JFN3DoysUiXbOFmDevUBDRY3HoUzjka/nCcF/f4OigLOXBGTiMKhwA\nq1UcKjaLja5sf7GaVP9rJoSaVt4qWdGowsFqwLKrztFhoxKN2i4OFuIWDMyKq09E82CRNWTNwGG2\nVSkNDiocqpHIYDQ6DzioWEp+NNRvwUNGkUd2leKI4xLWPAcHxLsyfKEDtY4uXV29vaVyodqDcK7a\nXZG5gh49Gge6RIVDXuKASzDhfTiMKi6oQHYGDs504MCcmTif4shvUBQO+UymKxePdo0KMTZWBA4y\nXYaq9spIrLfc36NwQCA90t8/NGdIlspQlbZBVq7NqaNpqaNWcVaxu9jVlR0o1o7CoQwcBsrAK211\nwbKr9HNsrNBVBQ4lprB6rWp1EYfyERy6GtYs1O9SKwzV6qhVLQ8NJeMpBJXAYSgaHYPMzMBhADiU\no8gjm+V4rTyUtMbKSZXz53vInTKXsD8AB1So9SKcq3VXIUXEAfOic+5VbKBL7Olx+YBEBpwYGpKL\nfyrvVqsMcxQX1EqI7FctTB3BwZnJDBwUK3qAQzMfjzbnCDF/frEoojJNa/T09MlIrK8y0Ku+RW0U\nirBJs+bOkqU6q0aZlJXrc5FrVqVsWKXhUk+p2cwOluouDkUEklYFOAxWgFfaasKyq/QTHXbVgAOc\nbqWi12sW4sdYrOLiUACLrGGrC8ZCrTPX5li1yqxZyUQKQWUtEpkVjc6HzKhYSuIwCBwq0Uol2V2J\n1yuzktb8SlLl/IVe8q+Cx5VjcGg2+/pQodaHcK7WU5Uxqk420Dn3KTbQFPf2OnxAwSWYIBedVN6t\nstu5igsyAa7LfmUcU3GmAwfmzGQGDooVvYVMphs4dM8VYsGCUlHYLg79cgD9lUEXB8Q3g4PD84Zl\nqQ7PwGHeDBxGJA65oVI9JT/+tywHB9seOhaHBQuKzZptxzo4NBFxxmfg0OyyRlC/g8Nc4DA8nEyk\nGdxHo8O2vaCDg/yIbshCpGIzj6wkEMclrQXH4MBA5mgYIgxBK9Vivb9YLtZ7a6VuKIJuOzj0KzbQ\nFLs4yEQGnBgefh8O8/5fcZAbFOrbKBeHbLanELe758m/w+R1jqL6q4C+j+BKk9c+HyyXWCPGhV9k\nxRe0AW2+tkL7gvZnnoLne54XPf/b+xXv495ve3dXk9V8tVytV7urI9Xjq0uq36wlIL3dtVl1Tz1Q\nj9bj9VQdcVJ9oD5R31C/oPnSvj0/t35/+P96Dh/mX0oUD2qztOO009By1vM8Wn6l03KiiryPk0bL\nx31AyzG0nOu0vFG2LNCyJlt2yiH5dxQPNYV47xPvrXzvQ+8dL8S+h3lv34p9N+47Zd+Cfce9fuD1\n1uv/+Po/vPbua2+/9q9CvPY7HK+/9qPX/ua1R177xk+Pq94sRMgv/9riGi3p6fec6PmYEJ6/8XwH\n9DtuT57neXheEn+keKbUcdS9J3D8rUThSvG0+Kq4UOwUS8Vz4r+LvxQrxF+JdeJW0RIvijfEN8Q/\niX8QnxXXiBfE98TlYrv4mHhe3CE+JW4QU+IU7Uahi7AwhSUSIilSIi0KwLEkKuBxXfSLATEohsSw\nmC3GxHyxQBwnThSniw+LM8Ry8RNxvThJnCZWiw3iYnG1+Ly4WWwV/038qdgm/lzcI+4TT4pvid3i\nf4nvi5fFT8Ve8b/Fa+JnYqX4iFglJrQ/EVeJc8XfifXin8VZ4rtio/i4eEz8ibhTu0H8T/EVcb6Y\nFD8S02KRuEt8U+wSa8WjYoe4UTwiHhY/EE+JgHhJ+EQIshbUvigMERMRERW2yIsMpC8n4qImekSX\naIo+0S3uFr1inhgVc8RccbwYEV8QS8RCSOqpYrFYJk6G1H5SXCIuFZeJL4vbxO3iS+LT4l7xkLhf\nfE08IR4QF4jHxatij/ixeEW8Lv5e7NMMbYlmaks1S1umRbTlWlSb0GLaKZoNmY9rp2oJyGdK+4iW\n1lZqGW2VltVO15Lah7WcdoaW187UCtpZWlE7Wytpq7Wydo5W0dZoVW2tVtfO1WpiE/Tmeq2hfUzr\n0tZpTe3jWo+2QevW1mu92nmiLP5M69M+AQ3bqPVr52sXaIPahdqQdhH0YpNoQD+GtYu12dol2oh2\nqTaqXabN0T6pzdUuF7PEd6CVW7QxbTM06NPa8dqV2gnaVdqJ2tXah7TPaCdp12gLtWu1ce06bZH2\nWXGCtlj7nHay9nnxIfFzbZ52hbZA+5T4qDhHnCkuEn8rvi7+UdwitojN4lnx1+IZcZ74hDhb08Rf\naGEYhf3iLXFAHBS/FL8S/0e8LX4tfiN+K34h/lX8TnxGXCsC2ktSn/f9/1uWMQdIIWQwApnrhoQt\nhHSNQ7JOhWytgVx9UkrWbZAtSta9kKqHIFcPQLL2QKooU+dB3qkN3xVnQ9q/AA34uPghZH+j5od0\n94r3xKQW1ELQlbvEIU3TPOI/xGHoyw7x75Dex6EPV0FzhLhOC4h/gxbdKK6AhgWgH32Uhw5C3xb/\nQ1ygecHxE8TnxJvii+ImicQnoGF/A/za0KkoNMuGPik9ylOHNB90idozT2wC+v8I/VT4rwX6Xxfn\ntMTgqS191Zpdmvana5/WDt/cWlLapXvXf3yopQ1Wq0svXtLSNgy1PIMtrb821PIOVpe1vM1lZ6xp\nrK3eXr19xcbbq8uqm87b2PI15S8eXHD72uFqS5y55mLQs9bUWuNrC53TC9auPX6o5WMzPtnM7WvR\nwCVOA5fIBvD+e0Mt/+Cp1Za3e9Wa09e0blhSaI0vWVuo1apLW7tXrWntXlKorV071Ap0xojfz1+c\nVaMNDrYC/UOtkGrhTLyP19fefru6atRau2+/vXA7ZuBcP62JY2+Mz7yBGS99WrthlXxyQ6NW4I1G\nrVHDiNYuGWrpg6eeuWYphlRbOwSRakFk25rHM6C1vV7QKe/yRfOa2dDAlO/Dzon/LHUipjTnbMrz\nsWVj8lY74A8OtISaT3tDSPt0+/owyAMkz5G8TnKYpBLWrmwvJFlPso1kJ8kPSN4miYa1q9rDJCtJ\nriDZaeLdt0kqJqoMk6wn2UbyAMlzJD8gOUwSNdkKyUKSlSRXkLztVPk0q2BovLQjOBsnWUWyk+Rt\nkuEIhxvBa4d5eQUu6RhT0LgToZET+BUifrgoTO1HIg5vG/f8DpZBQLvVf1+Gb3kFVnuWp9/7qP+l\nwNbADwO/DWaDZwWvCV0e+qb+2/Bp4S+EHwq/ZAij23jUfNictiYin4rmo2P2JbGJ2ObY12J/EzuQ\n/I9UOvX99O8ze3KX5LbmXshfXjilcGHh9sJkYbq4oXRLRVS+VvmbyhvVrdUdtQOIQOr1c+vXdd3e\n9WhPqOfcnlbvpr5Ng/cOTg1tHTowy5z1w+EHh58f/tXIZSMPjbw02jV65ZzpudV5l8z79lh17KwF\nXz7u9uM3H986IXLCwyf8/sSNJ3lOGj3pEwu/sPDBhd9euH9cLJpYNL3oXxaHFy9Y8u2l6aVXLn13\n2e7lkxNLVixbsXvFj05dctrVp019OPThlz5yw0cOrFy18oerxlatXrV71U9W/fr09OmDp0+ecd8Z\n3z+zfOaSM58/69dnB86unv3s6jWrD63pXjO+dvTckXMnzr3w3C987NmPHVqXXHf1+lkbzt2w47w1\n5x3aGN7YfUHgglUXvHHhZZs8myY23XjJpksevuS3lz592QuXhy5fdvm9l//HFR+/4r4r3tic3Lxg\nc+tTOz5911Weq+KfyX7mK9f4ru2/9t5rv3Pdjs+e9Lmxz09d/+ANX/uTxTce/8W5N+Vv+sub/vam\nvTcdutm+uf/m3bc8sXXktk/dduNtk7d/4kuXfelzX/7Uf3vov/3sT/N/etmffvtPX9n2uW3T2/Zv\ne/eO+p32nVfe+fCdu+985c5Df9b1Zz/88xu+kv/K1r84/i+uu2vwbnH3GXdfdvef3f303b+455R7\n7tpe3X7a9s9tv2P7S9v3bP/ZvcvuPePej997yb1X33vjV6/56k1fveOr9311x32R+/L3dd83et9J\n951y30P3/eV9z973/P3x+8v3998/dv/i+z9y/7n3X3j/p+7/wv2333/X/Q/d/5f3P3v/8/f/8P7X\nvrb7a9//2itfe+Nrv35g9IGTHjjlgdUPfOKByx+MPJh/sPvB0QdPevCUB1d/fcnXV339Y1/f9PUr\nv37DQ2se2vjQ5oc+99DWb4x848RvTHzjrG9s+MZl3/jdw+Jh8+GtD08/vPfhAw//7hHxiPlI9pGu\nR0YeOfGRiUfOemTDI5c9cs0jNz1yxyP3PbLj0Tseve/RHY9OPrr7sfHHTntszWMbH9v82Od29O6Y\nu2N8x2k71uzYuGPzjjt23PH4xidGGLbLSFJ4/gGetwHbPiBGW4PDraHh1qDd6p5udQ/vSvvebQ3Z\nrebeXUXfu+KvvFqXb+CvmloO1KdpvoGR2fPnzUn19MydPzY2/yTvvLndjXog2DM2Nmc0nUryLwIG\nUplYLabheG3BPI8VTMfsZNg3VKkMBUaDp4yNLct1NwOB5w5t1P7hkLjq5JOvii3IWaVYNJOI6V2z\nB+eEJhYtP7E6r1FLJOc+7bn4vbs99703iiELoaJ1z196P+3phucXWhBe6XXEDh9qX2Fo6yYXGisN\nzxbajS2TO6PPRT3rpnZHp6P7ot51grZmHe3UOhqhdbQruETNkdlH2r240+5G2e6YbLe90NC2jFsP\nGDuN54wfGK8bbxuBde0rSnxSkk9KO0vPlX5Qer30dimwbmT2B4zzetneQPsKC29xgKJ9mKdvcxgL\n3bF0RoVGZs73nk47fyvbWdleFUPtK2KofQPIlIjZsWrMu2Vqd2w6ti/mxZ2aXavWvKhUY481Dc9q\n07V9NS9ewS3RXp9kX8Vj+/pop69/lH012wvz6Atk3dQD+Z355/Jo4Yq8bKGCFg73qha8sLDCczzs\n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\neZnDvTDnpW15FMecizPZO9u9Le+ZJTtX3t783qOrMa9dC84q3FMTcg5yLytRVqPgq8w9vknuOmc/\nPR5lys63JNwR8+s1z9HZPwdhKHH7aW+r6GPj97OSu8K2X3Fa2ae3o0xbVLqupgrbKrRY99j4tDtj\nszhbi6jkd5v8Ph2TI+ZOMtF/8p5ds0iViz6cPx2Sjntotbi/7rZPlYiNdpxxoLjDn8lFuYhrw2Je\nZ2udK6mzrvmTIOGekF89w7S0DL/j19QeWqQrtV5cDS2uvtZppQ1yXP+pe0bnPS1/+i+gju98rx4v\n7czeXuL+0ijin9cn7+Nv/9TQ2TKOUizWcO/Tc6sMS4nLn1z59Zt1PA/PFsu8VhWOKNP+t8+9rojO\nROTG823graNFjdtWyxJvS1WiP/EsnMM7Tctas9Bpve97vRP973J/lFrpOjj9uah+2dmO8beXQp/v\n3Mln3Hx3lv/5++0zyXJ1ud+2CP+8necX3Ifch638K91VVt7vuOPud93fuI+4q901drWccL/nft/9\ngb0hzbHa/BlvVXusbP0jwn9otflj9/3uF+2NaoG73t3g/sLeGv/enstfdS9bS1+xp/RCu3Pc5P7W\nPedudn9lb0S6Nz1k7f2ivV1Mtdr3WYxnug9YW5e5j7md7i63y93iFrk33Dfcg9bn/tTa9XV3v40V\n3uvOdZ9zx6zHjLkvu0/buOtZqavdq9Z7honI3e497in3K+6Xjatv2ojhp6xHf8ld6n7T/Yy7xD3v\nVrvPGIfvt3fcJ91vuBesl71p7/prLbojxkLb3Wq9Yb17n3vC/bnb4LvcP7gfcf/oNrrLrYd027vo\nqLvH3et+yb1ld6eL3L+4f3X/5A67R91PuvvcZhsTTrdRRK873092L7pzbOy7xe5Uj9to5bfcr7pn\nbGz4a+4rbprbaiOfP3G3ub90D7hZ7jL3bhsXvWTjytvdt9zF7t/cP7vX3efdu9y33R3uE+6T7lPu\ngPF7p9vmPu62u79zR90Pux3ur92Fforv9j2+10/10/x0P8PP9Of4c/15/nx/gb/QX+Tf5S92j/lL\n/KXuJ/y7bWT3AzYS/4L7afdjNhb/df8eG7P+rI3Ofshf7t/rZ/n3+ZL7L/9+d9Jf4T/gP+g/5D/s\nr7QR1Uf81e7f/TV+tr/Wz/Ef9XP9PD/fX+cX+Ov9DT7woY/8Qn+jv8nf7G/xH/OLfJ9f7Je4//RL\n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\n0ALYRzoAqQCkAZACQOv/B6ys2f+vd9C1/wd3UY3cZ2lVVmuyWpHVeqxWY7UWy0qs1mG1Cqs1WK3A\nav1Vq69l2jyL+/BLeBQm0WrV+EJ8E3JNyDMhx4T8EnJLyCshp4R8Ep1PSa2uam1VK6taV9WqqtZU\n8xXV/J1Kf+5/AIGHtqIKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago3MDc0OQplbmRvYmoKMTkg\nMCBvYmoKMTI3MzQwCmVuZG9iagoxNSAwIG9iago8PCAvRmlsdGVyIC9GbGF0ZURlY29kZSAvTGVu\nZ3RoIDY3ID4+CnN0cmVhbQp4nO3NMQ0AIQAEwVNMTYKOV4AZKhosIOQxQUNmuq02uWynZ2WmpWac\nLreHAAAAAAAAAAAAAAAAAAAAAPCY7weB+gXnCmVuZHN0cmVhbQplbmRvYmoKMTggMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAyNjEgPj4Kc3RyZWFtCnicXVE9b8MgEN35FTem\nQ0Rst5UHC6lKFw9Jq7qdogw2HBZSDQjjwf++fCRu1ZPg6T7ece+gx/a11coDfXeGd+hBKi0czmZx\nHGHAUWlSlCAU9zcv3XzqLaGB3K2zx6nV0pCmAfoRkrN3K+xehBnwgQAAfXMCndIj7L6OXQ51i7Xf\nOKH2cCCMgUAZ2p16e+4nBJrI+1aEvPLrPtB+Kz5Xi1Amv8gjcSNwtj1H1+sRSXMIxqCRwRhBLf7l\nq8wa5FZexfIAzwwuf9wiQ5mhyvCY4enOuKYGdXbrW4M6hsuyiNQMl4zXOM/95Tha3OOmmy/OBclp\n2UlrVKk0bv9hjY2seH4AHtCFLgplbmRzdHJlYW0KZW5kb2JqCjEzIDAgb2JqCjw8IC9DSURUb0dJ\nRE1hcCAxNSAwIFIgL0ZvbnREZXNjcmlwdG9yIDEyIDAgUiAvQmFzZUZvbnQgL0F2ZW5pci1Cb29r\nCi9DSURTeXN0ZW1JbmZvIDw8IC9PcmRlcmluZyAoSWRlbnRpdHkpIC9TdXBwbGVtZW50IDAgL1Jl\nZ2lzdHJ5IChBZG9iZSkgPj4KL1N1YnR5cGUgL0NJREZvbnRUeXBlMiAvVyAxNyAwIFIgL1R5cGUg\nL0ZvbnQgPj4KZW5kb2JqCjE0IDAgb2JqCjw8IC9FbmNvZGluZyAvSWRlbnRpdHktSCAvQmFzZUZv\nbnQgL0F2ZW5pci1Cb29rCi9EZXNjZW5kYW50Rm9udHMgWyAxMyAwIFIgXSAvU3VidHlwZSAvVHlw\nZTAgL1RvVW5pY29kZSAxOCAwIFIgL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjEyIDAgb2JqCjw8IC9E\nZXNjZW50IC0zNjYgL0ZvbnRCQm94IFsgLTE2NyAtMjg4IDEwMDAgOTQwIF0gL1N0ZW1WIDAgL0Zs\nYWdzIDMyCi9YSGVpZ2h0IDAgL1R5cGUgL0ZvbnREZXNjcmlwdG9yIC9Gb250RmlsZTIgMTYgMCBS\nIC9Gb250TmFtZSAvQXZlbmlyLUJvb2sKL01heFdpZHRoIDY4MiAvQ2FwSGVpZ2h0IDAgL0l0YWxp\nY0FuZ2xlIDAgL0FzY2VudCAxMDAwID4+CmVuZG9iagoxNyAwIG9iagpbIDQ4ClsgNTY5LjMzMzMz\nMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMKNTY5LjMz\nMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgXQo1NiBbIDU2OS4zMzMzMzMz\nMzMzIF0gODcyMiBbIDY4MiBdIF0KZW5kb2JqCjMgMCBvYmoKPDwgL0YxIDE0IDAgUiA+PgplbmRv\nYmoKNCAwIG9iago8PCAvQTEgPDwgL0NBIDAgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMCA+PgovQTIg\nPDwgL0NBIDEgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMSA+PiA+PgplbmRvYmoKNSAwIG9iago8PCA+\nPgplbmRvYmoKNiAwIG9iago8PCA+PgplbmRvYmoKNyAwIG9iago8PCA+PgplbmRvYmoKMiAwIG9i\nago8PCAvQ291bnQgMSAvS2lkcyBbIDEwIDAgUiBdIC9UeXBlIC9QYWdlcyA+PgplbmRvYmoKMjEg\nMCBvYmoKPDwgL0NyZWF0aW9uRGF0ZSAoRDoyMDE0MDIyMDE3NTMyNS0wNycwMCcpCi9Qcm9kdWNl\nciAobWF0cGxvdGxpYiBwZGYgYmFja2VuZCkKL0NyZWF0b3IgKG1hdHBsb3RsaWIgMS4xLjEsIGh0\ndHA6Ly9tYXRwbG90bGliLnNmLm5ldCkgPj4KZW5kb2JqCnhyZWYKMCAyMgowMDAwMDAwMDAwIDY1\nNTM1IGYgCjAwMDAwMDAwMTYgMDAwMDAgbiAKMDAwMDA3MzYzOCAwMDAwMCBuIAowMDAwMDczNDQ0\nIDAwMDAwIG4gCjAwMDAwNzM0NzYgMDAwMDAgbiAKMDAwMDA3MzU3NSAwMDAwMCBuIAowMDAwMDcz\nNTk2IDAwMDAwIG4gCjAwMDAwNzM2MTcgMDAwMDAgbiAKMDAwMDAwMDA2NSAwMDAwMCBuIAowMDAw\nMDAwMzg4IDAwMDAwIG4gCjAwMDAwMDAyMDggMDAwMDAgbiAKMDAwMDAwMTMzMyAwMDAwMCBuIAow\nMDAwMDczMDYwIDAwMDAwIG4gCjAwMDAwNzI3MTIgMDAwMDAgbiAKMDAwMDA3MjkxOSAwMDAwMCBu\nIAowMDAwMDcyMjM5IDAwMDAwIG4gCjAwMDAwMDEzNTMgMDAwMDAgbiAKMDAwMDA3MzI3NyAwMDAw\nMCBuIAowMDAwMDcyMzc4IDAwMDAwIG4gCjAwMDAwNzIyMTYgMDAwMDAgbiAKMDAwMDA3MjE5NCAw\nMDAwMCBuIAowMDAwMDczNjk4IDAwMDAwIG4gCnRyYWlsZXIKPDwgL0luZm8gMjEgMCBSIC9Sb290\nIDEgMCBSIC9TaXplIDIyID4+CnN0YXJ0eHJlZgo3Mzg0OQolJUVPRgo=\n",
187 "application/pdf": "JVBERi0xLjQKJazcIKu6CjEgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL1BhZ2VzIDIgMCBSID4+\nCmVuZG9iago4IDAgb2JqCjw8IC9YT2JqZWN0IDcgMCBSIC9QYXR0ZXJuIDUgMCBSCi9Qcm9jU2V0\nIFsgL1BERiAvVGV4dCAvSW1hZ2VCIC9JbWFnZUMgL0ltYWdlSSBdIC9FeHRHU3RhdGUgNCAwIFIK\nL1NoYWRpbmcgNiAwIFIgL0ZvbnQgMyAwIFIgPj4KZW5kb2JqCjEwIDAgb2JqCjw8IC9Hcm91cCA8\nPCAvQ1MgL0RldmljZVJHQiAvUyAvVHJhbnNwYXJlbmN5IC9UeXBlIC9Hcm91cCA+PiAvUGFyZW50\nIDIgMCBSCi9NZWRpYUJveCBbIDAgMCAxNTIuMzk4NDM3NSA4Ny4xOTIxODc1IF0gL1Jlc291cmNl\ncyA4IDAgUiAvVHlwZSAvUGFnZQovQ29udGVudHMgOSAwIFIgPj4KZW5kb2JqCjkgMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAxMSAwIFIgPj4Kc3RyZWFtCnicxZi/btwwDMYz\na+wTCJ3aRSEpiZLGHtAG6FbkgL5AmwTBXYCmQ16/dJycRcWq7SV3k81Pf76fzyZpo703l1/Q3v61\nZL9bsE8W7ZUBOTpajOR8ycGnKOcHdZ6Tw0KY5fAgojq9Mw+yKA2Lgiv+9WdvZeCVoewCR6ZoCVyk\njHIkewVw0IYPdTix8y/hao0qKvveiHOhcF5t6qJgqWDPRRXlkwmzm92vHp1g8rYzzf5on8xuby+/\noUWw+xsjO2L0w+gk06Ld/zKfPn64wAv4bPf39uu+XeGZwITgAuSQCQMVZbtRlHWt1fYbZRNCIAdA\n5F/mnjAWEFiiEb0vlGNSCI2iELRWIzTKJoQYXSglJU7PcyeEpf9BDFAJWDhQZgXRKApCazVEo2yC\nSOiQ0efhCnANQQsQhRz5BNHHhEFBNIqC0FoN0SibICR5QCjxde4E4RcgELLDVAqCTPQ6nzSSwmjE\nmqOVNoEgkCuFwuvkiSQskVBwSDTejKhJGkmTaFGRNNI2Esyu5PLyp9QkcYlkLpHr/K4J5jK8Gr/R\nuQ9Sc8bxlW1esL1YD6BjermIrTGdHI8VAXm47sDr8unkz6Pj/Mb1FG1c18Nnw6tcyzM/bIahMryU\neCZzUkOk+rSWp2hjuR4+G15pGUazvjgPle+lJ3RyGIPUvje+p2jjux4+G159qSPIZpXl9fc0RykT\nbyxP0cZyPXw2vNby8yy5p6hynVe77vRaXKeDFemDNxVUuc6JXKqfQWkIJs9/ZpMColBaaSmyffxt\nf9qHsZ12BFKZMbIUZxkbEBOHBCw20unEPk49atUtXxlhoITscwhNv5cdJ5TWC1TVO2ghBUkqYQRX\nS1WC9Mw788O+J9S896ON0gXIxBDZqwp4aBUxFQb3puE9CefA6rk/Dk+NzJQcSZLgFZdSzH+IK+Xd\nwXr2pW/1LnNhOaeowZRiusjnBevZP9o8ZK4i60pTrp8vpZgu8nnBevalSQfHsiYDSJekTCrFdJHP\nC9azL2BFsn2W/MaQGrBaMV3kM4N17A+vI0k8JOZEgM2nESWZLvR50boAwoaylaTvBEneMzSbkkwf\n+8xwPYLx7YtYXAafC2s4JRkpW5B5jtvW0gg3mk4+UZSmm9SHrBX9z/WKNxc9fsvXuu7w+ebt2ph/\nACMXFgplbmRzdHJlYW0KZW5kb2JqCjExIDAgb2JqCjg3MAplbmRvYmoKMTYgMCBvYmoKPDwgL0Zp\nbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aDEgMTkgMCBSIC9MZW5ndGggMjAgMCBSID4+CnN0cmVh\nbQp4nNS9eYAdVZ0vfurudavq3rr7vvftvdOdTtIJi6QTsnQATdhCgsYECRAWIVFAwAUGWQL6JjDj\nAEEQRJYAvsnNnbZZxjfkzVMExhl7HImgeZBRCIn6BnUcRudB8vt8zqm66QScef/+DqnvreXUWb6f\n73pO2QpNCBEH8Ynq8iVLlwleawdAhLl81cozz//y80lcm0LoZyw/8+zFIiXCQvvNBj5feebw6M3v\n9H4RL+zA9YbzP3ne5v959xPrhTj9QSEC2fOvvrIaXKRVhTj3RDyvXrj5ok9etDjUI8Q5T+Od0y+6\n7NoLR5ee8b+EWLdJaGdt2LTxk9fkfn3RLCFCWSFWbN10wXkbn8ze+XPUHcT7Y5twIzjoXYPrjbju\n2vTJK68pvnny6UJ4QujPvvSCT12+7NTTbxHarheEqC+57Irzz1v629+uRv8fE8Ib/uR512z23hfG\n2LWtHM/l533ygq985Ml/EdqPMD/jbzdf8ekr77zla3cJ7fVpjGHW5k9dsPmkX106T4i1eK4NKd6I\n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\nc+tTOz5911Weq+KfyX7mK9f4ru2/9t5rv3Pdjs+e9Lmxz09d/+ANX/uTxTce/8W5N+Vv+sub/vam\nvTcdutm+uf/m3bc8sXXktk/dduNtk7d/4kuXfelzX/7Uf3vov/3sT/N/etmffvtPX9n2uW3T2/Zv\ne/eO+p32nVfe+fCdu+985c5Df9b1Zz/88xu+kv/K1r84/i+uu2vwbnH3GXdfdvef3f303b+455R7\n7tpe3X7a9s9tv2P7S9v3bP/ZvcvuPePej997yb1X33vjV6/56k1fveOr9311x32R+/L3dd83et9J\n951y30P3/eV9z973/P3x+8v3998/dv/i+z9y/7n3X3j/p+7/wv2333/X/Q/d/5f3P3v/8/f/8P7X\nvrb7a9//2itfe+Nrv35g9IGTHjjlgdUPfOKByx+MPJh/sPvB0QdPevCUB1d/fcnXV339Y1/f9PUr\nv37DQ2se2vjQ5oc+99DWb4x848RvTHzjrG9s+MZl3/jdw+Jh8+GtD08/vPfhAw//7hHxiPlI9pGu\nR0YeOfGRiUfOemTDI5c9cs0jNz1yxyP3PbLj0Tseve/RHY9OPrr7sfHHTntszWMbH9v82Od29O6Y\nu2N8x2k71uzYuGPzjjt23PH4xidGGLbLSFJ4/gGetwHbPiBGW4PDraHh1qDd6p5udQ/vSvvebQ3Z\nrebeXUXfu+KvvFqXb+CvmloO1KdpvoGR2fPnzUn19MydPzY2/yTvvLndjXog2DM2Nmc0nUryLwIG\nUplYLabheG3BPI8VTMfsZNg3VKkMBUaDp4yNLct1NwOB5w5t1P7hkLjq5JOvii3IWaVYNJOI6V2z\nB+eEJhYtP7E6r1FLJOc+7bn4vbs99703iiELoaJ1z196P+3phucXWhBe6XXEDh9qX2Fo6yYXGisN\nzxbajS2TO6PPRT3rpnZHp6P7ot51grZmHe3UOhqhdbQruETNkdlH2r240+5G2e6YbLe90NC2jFsP\nGDuN54wfGK8bbxuBde0rSnxSkk9KO0vPlX5Qer30dimwbmT2B4zzetneQPsKC29xgKJ9mKdvcxgL\n3bF0RoVGZs73nk47fyvbWdleFUPtK2KofQPIlIjZsWrMu2Vqd2w6ti/mxZ2aXavWvKhUY481Dc9q\n07V9NS9ewS3RXp9kX8Vj+/pop69/lH012wvz6Atk3dQD+Z355/Jo4Yq8bKGCFg73qha8sLDCczzs\n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\neZnDvTDnpW15FMecizPZO9u9Le+ZJTtX3t783qOrMa9dC84q3FMTcg5yLytRVqPgq8w9vknuOmc/\nPR5lys63JNwR8+s1z9HZPwdhKHH7aW+r6GPj97OSu8K2X3Fa2ae3o0xbVLqupgrbKrRY99j4tDtj\nszhbi6jkd5v8Ph2TI+ZOMtF/8p5ds0iViz6cPx2Sjntotbi/7rZPlYiNdpxxoLjDn8lFuYhrw2Je\nZ2udK6mzrvmTIOGekF89w7S0DL/j19QeWqQrtV5cDS2uvtZppQ1yXP+pe0bnPS1/+i+gju98rx4v\n7czeXuL+0ijin9cn7+Nv/9TQ2TKOUizWcO/Tc6sMS4nLn1z59Zt1PA/PFsu8VhWOKNP+t8+9rojO\nROTG823graNFjdtWyxJvS1WiP/EsnMM7Tctas9Bpve97vRP973J/lFrpOjj9uah+2dmO8beXQp/v\n3Mln3Hx3lv/5++0zyXJ1ud+2CP+8necX3Ifch638K91VVt7vuOPud93fuI+4q901drWccL/nft/9\ngb0hzbHa/BlvVXusbP0jwn9otflj9/3uF+2NaoG73t3g/sLeGv/enstfdS9bS1+xp/RCu3Pc5P7W\nPedudn9lb0S6Nz1k7f2ivV1Mtdr3WYxnug9YW5e5j7md7i63y93iFrk33Dfcg9bn/tTa9XV3v40V\n3uvOdZ9zx6zHjLkvu0/buOtZqavdq9Z7honI3e497in3K+6Xjatv2ojhp6xHf8ld6n7T/Yy7xD3v\nVrvPGIfvt3fcJ91vuBesl71p7/prLbojxkLb3Wq9Yb17n3vC/bnb4LvcP7gfcf/oNrrLrYd027vo\nqLvH3et+yb1ld6eL3L+4f3X/5A67R91PuvvcZhsTTrdRRK873092L7pzbOy7xe5Uj9to5bfcr7pn\nbGz4a+4rbprbaiOfP3G3ub90D7hZ7jL3bhsXvWTjytvdt9zF7t/cP7vX3efdu9y33R3uE+6T7lPu\ngPF7p9vmPu62u79zR90Pux3ur92Fforv9j2+10/10/x0P8PP9Of4c/15/nx/gb/QX+Tf5S92j/lL\n/KXuJ/y7bWT3AzYS/4L7afdjNhb/df8eG7P+rI3Ofshf7t/rZ/n3+ZL7L/9+d9Jf4T/gP+g/5D/s\nr7QR1Uf81e7f/TV+tr/Wz/Ef9XP9PD/fX+cX+Ov9DT7woY/8Qn+jv8nf7G/xH/OLfJ9f7Je4//RL\n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\n0ALYRzoAqQCkAZACQOv/B6ys2f+vd9C1/wd3UY3cZ2lVVmuyWpHVeqxWY7UWy0qs1mG1Cqs1WK3A\nav1Vq69l2jyL+/BLeBQm0WrV+EJ8E3JNyDMhx4T8EnJLyCshp4R8Ep1PSa2uam1VK6taV9WqqtZU\n8xXV/J1Kf+5/AIGHtqIKZW5kc3RyZWFtCmVuZG9iagoyMCAwIG9iago3MDc0OQplbmRvYmoKMTkg\nMCBvYmoKMTI3MzQwCmVuZG9iagoxNSAwIG9iago8PCAvRmlsdGVyIC9GbGF0ZURlY29kZSAvTGVu\nZ3RoIDY3ID4+CnN0cmVhbQp4nO3NMQ0AIQAEwVNMTYKOV4AZKhosIOQxQUNmuq02uWynZ2WmpWac\nLreHAAAAAAAAAAAAAAAAAAAAAPCY7weB+gXnCmVuZHN0cmVhbQplbmRvYmoKMTggMCBvYmoKPDwg\nL0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAyNjEgPj4Kc3RyZWFtCnicXVE9b8MgEN35FTem\nQ0Rst5UHC6lKFw9Jq7qdogw2HBZSDQjjwf++fCRu1ZPg6T7ece+gx/a11coDfXeGd+hBKi0czmZx\nHGHAUWlSlCAU9zcv3XzqLaGB3K2zx6nV0pCmAfoRkrN3K+xehBnwgQAAfXMCndIj7L6OXQ51i7Xf\nOKH2cCCMgUAZ2p16e+4nBJrI+1aEvPLrPtB+Kz5Xi1Amv8gjcSNwtj1H1+sRSXMIxqCRwRhBLf7l\nq8wa5FZexfIAzwwuf9wiQ5mhyvCY4enOuKYGdXbrW4M6hsuyiNQMl4zXOM/95Tha3OOmmy/OBclp\n2UlrVKk0bv9hjY2seH4AHtCFLgplbmRzdHJlYW0KZW5kb2JqCjEzIDAgb2JqCjw8IC9DSURUb0dJ\nRE1hcCAxNSAwIFIgL0ZvbnREZXNjcmlwdG9yIDEyIDAgUiAvQmFzZUZvbnQgL0F2ZW5pci1Cb29r\nCi9DSURTeXN0ZW1JbmZvIDw8IC9PcmRlcmluZyAoSWRlbnRpdHkpIC9TdXBwbGVtZW50IDAgL1Jl\nZ2lzdHJ5IChBZG9iZSkgPj4KL1N1YnR5cGUgL0NJREZvbnRUeXBlMiAvVyAxNyAwIFIgL1R5cGUg\nL0ZvbnQgPj4KZW5kb2JqCjE0IDAgb2JqCjw8IC9FbmNvZGluZyAvSWRlbnRpdHktSCAvQmFzZUZv\nbnQgL0F2ZW5pci1Cb29rCi9EZXNjZW5kYW50Rm9udHMgWyAxMyAwIFIgXSAvU3VidHlwZSAvVHlw\nZTAgL1RvVW5pY29kZSAxOCAwIFIgL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjEyIDAgb2JqCjw8IC9E\nZXNjZW50IC0zNjYgL0ZvbnRCQm94IFsgLTE2NyAtMjg4IDEwMDAgOTQwIF0gL1N0ZW1WIDAgL0Zs\nYWdzIDMyCi9YSGVpZ2h0IDAgL1R5cGUgL0ZvbnREZXNjcmlwdG9yIC9Gb250RmlsZTIgMTYgMCBS\nIC9Gb250TmFtZSAvQXZlbmlyLUJvb2sKL01heFdpZHRoIDY4MiAvQ2FwSGVpZ2h0IDAgL0l0YWxp\nY0FuZ2xlIDAgL0FzY2VudCAxMDAwID4+CmVuZG9iagoxNyAwIG9iagpbIDQ4ClsgNTY5LjMzMzMz\nMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMKNTY5LjMz\nMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgNTY5LjMzMzMzMzMzMzMgXQo1NiBbIDU2OS4zMzMzMzMz\nMzMzIF0gODcyMiBbIDY4MiBdIF0KZW5kb2JqCjMgMCBvYmoKPDwgL0YxIDE0IDAgUiA+PgplbmRv\nYmoKNCAwIG9iago8PCAvQTEgPDwgL0NBIDAgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMCA+PgovQTIg\nPDwgL0NBIDEgL1R5cGUgL0V4dEdTdGF0ZSAvY2EgMSA+PiA+PgplbmRvYmoKNSAwIG9iago8PCA+\nPgplbmRvYmoKNiAwIG9iago8PCA+PgplbmRvYmoKNyAwIG9iago8PCA+PgplbmRvYmoKMiAwIG9i\nago8PCAvQ291bnQgMSAvS2lkcyBbIDEwIDAgUiBdIC9UeXBlIC9QYWdlcyA+PgplbmRvYmoKMjEg\nMCBvYmoKPDwgL0NyZWF0aW9uRGF0ZSAoRDoyMDE0MDIyMDE3NTMyNS0wNycwMCcpCi9Qcm9kdWNl\nciAobWF0cGxvdGxpYiBwZGYgYmFja2VuZCkKL0NyZWF0b3IgKG1hdHBsb3RsaWIgMS4xLjEsIGh0\ndHA6Ly9tYXRwbG90bGliLnNmLm5ldCkgPj4KZW5kb2JqCnhyZWYKMCAyMgowMDAwMDAwMDAwIDY1\nNTM1IGYgCjAwMDAwMDAwMTYgMDAwMDAgbiAKMDAwMDA3MzYzOCAwMDAwMCBuIAowMDAwMDczNDQ0\nIDAwMDAwIG4gCjAwMDAwNzM0NzYgMDAwMDAgbiAKMDAwMDA3MzU3NSAwMDAwMCBuIAowMDAwMDcz\nNTk2IDAwMDAwIG4gCjAwMDAwNzM2MTcgMDAwMDAgbiAKMDAwMDAwMDA2NSAwMDAwMCBuIAowMDAw\nMDAwMzg4IDAwMDAwIG4gCjAwMDAwMDAyMDggMDAwMDAgbiAKMDAwMDAwMTMzMyAwMDAwMCBuIAow\nMDAwMDczMDYwIDAwMDAwIG4gCjAwMDAwNzI3MTIgMDAwMDAgbiAKMDAwMDA3MjkxOSAwMDAwMCBu\nIAowMDAwMDcyMjM5IDAwMDAwIG4gCjAwMDAwMDEzNTMgMDAwMDAgbiAKMDAwMDA3MzI3NyAwMDAw\nMCBuIAowMDAwMDcyMzc4IDAwMDAwIG4gCjAwMDAwNzIyMTYgMDAwMDAgbiAKMDAwMDA3MjE5NCAw\nMDAwMCBuIAowMDAwMDczNjk4IDAwMDAwIG4gCnRyYWlsZXIKPDwgL0luZm8gMjEgMCBSIC9Sb290\nIDEgMCBSIC9TaXplIDIyID4+CnN0YXJ0eHJlZgo3Mzg0OQolJUVPRgo=\n",
187 "image/png": "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\n",
188 "image/png": "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\n",
188 "metadata": {},
189 "metadata": {},
189 "output_type": "display_data",
190 "output_type": "display_data",
190 "text/plain": [
191 "text/plain": [
191 "<matplotlib.figure.Figure at 0x10b0ecf10>"
192 "<matplotlib.figure.Figure at 0x10b0ecf10>"
192 ]
193 ]
193 }
194 }
194 ],
195 ],
195 "prompt_number": 9,
196 "source": [
196 "source": [
197 "plt.hist(evs.real)"
197 "plt.hist(evs.real)"
198 ]
198 ]
199 },
199 },
200 {
200 {
201 "cell_type": "markdown",
201 "cell_type": "markdown",
202 "metadata": {},
202 "metadata": {},
203 "source": [
203 "source": [
204 "```python\n",
204 "```python\n",
205 "def foo(bar=1):\n",
205 "def foo(bar=1):\n",
206 " \"\"\"docstring\"\"\"\n",
206 " \"\"\"docstring\"\"\"\n",
207 " raise Exception(\"message\")\n",
207 " raise Exception(\"message\")\n",
208 "```"
208 "```"
209 ]
209 ]
210 }
210 }
211 ],
211 ],
212 "metadata": {},
212 "metadata": {},
213 "nbformat": 4,
213 "nbformat": 4,
214 "nbformat_minor": 0
214 "nbformat_minor": 0
215 } No newline at end of file
215 }
@@ -1,310 +1,310 b''
1 """Functions for signing notebooks"""
1 """Functions for signing notebooks"""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import base64
6 import base64
7 from contextlib import contextmanager
7 from contextlib import contextmanager
8 import hashlib
8 import hashlib
9 from hmac import HMAC
9 from hmac import HMAC
10 import io
10 import io
11 import os
11 import os
12
12
13 from IPython.utils.py3compat import string_types, unicode_type, cast_bytes
13 from IPython.utils.py3compat import string_types, unicode_type, cast_bytes
14 from IPython.utils.traitlets import Instance, Bytes, Enum, Any, Unicode, Bool
14 from IPython.utils.traitlets import Instance, Bytes, Enum, Any, Unicode, Bool
15 from IPython.config import LoggingConfigurable, MultipleInstanceError
15 from IPython.config import LoggingConfigurable, MultipleInstanceError
16 from IPython.core.application import BaseIPythonApplication, base_flags
16 from IPython.core.application import BaseIPythonApplication, base_flags
17
17
18 from .current import read, write
18 from .current import read, write
19
19
20 try:
20 try:
21 # Python 3
21 # Python 3
22 algorithms = hashlib.algorithms_guaranteed
22 algorithms = hashlib.algorithms_guaranteed
23 except AttributeError:
23 except AttributeError:
24 algorithms = hashlib.algorithms
24 algorithms = hashlib.algorithms
25
25
26
26
27 def yield_everything(obj):
27 def yield_everything(obj):
28 """Yield every item in a container as bytes
28 """Yield every item in a container as bytes
29
29
30 Allows any JSONable object to be passed to an HMAC digester
30 Allows any JSONable object to be passed to an HMAC digester
31 without having to serialize the whole thing.
31 without having to serialize the whole thing.
32 """
32 """
33 if isinstance(obj, dict):
33 if isinstance(obj, dict):
34 for key in sorted(obj):
34 for key in sorted(obj):
35 value = obj[key]
35 value = obj[key]
36 yield cast_bytes(key)
36 yield cast_bytes(key)
37 for b in yield_everything(value):
37 for b in yield_everything(value):
38 yield b
38 yield b
39 elif isinstance(obj, (list, tuple)):
39 elif isinstance(obj, (list, tuple)):
40 for element in obj:
40 for element in obj:
41 for b in yield_everything(element):
41 for b in yield_everything(element):
42 yield b
42 yield b
43 elif isinstance(obj, unicode_type):
43 elif isinstance(obj, unicode_type):
44 yield obj.encode('utf8')
44 yield obj.encode('utf8')
45 else:
45 else:
46 yield unicode_type(obj).encode('utf8')
46 yield unicode_type(obj).encode('utf8')
47
47
48
48
49 @contextmanager
49 @contextmanager
50 def signature_removed(nb):
50 def signature_removed(nb):
51 """Context manager for operating on a notebook with its signature removed
51 """Context manager for operating on a notebook with its signature removed
52
52
53 Used for excluding the previous signature when computing a notebook's signature.
53 Used for excluding the previous signature when computing a notebook's signature.
54 """
54 """
55 save_signature = nb['metadata'].pop('signature', None)
55 save_signature = nb['metadata'].pop('signature', None)
56 try:
56 try:
57 yield
57 yield
58 finally:
58 finally:
59 if save_signature is not None:
59 if save_signature is not None:
60 nb['metadata']['signature'] = save_signature
60 nb['metadata']['signature'] = save_signature
61
61
62
62
63 class NotebookNotary(LoggingConfigurable):
63 class NotebookNotary(LoggingConfigurable):
64 """A class for computing and verifying notebook signatures."""
64 """A class for computing and verifying notebook signatures."""
65
65
66 profile_dir = Instance("IPython.core.profiledir.ProfileDir")
66 profile_dir = Instance("IPython.core.profiledir.ProfileDir")
67 def _profile_dir_default(self):
67 def _profile_dir_default(self):
68 from IPython.core.application import BaseIPythonApplication
68 from IPython.core.application import BaseIPythonApplication
69 app = None
69 app = None
70 try:
70 try:
71 if BaseIPythonApplication.initialized():
71 if BaseIPythonApplication.initialized():
72 app = BaseIPythonApplication.instance()
72 app = BaseIPythonApplication.instance()
73 except MultipleInstanceError:
73 except MultipleInstanceError:
74 pass
74 pass
75 if app is None:
75 if app is None:
76 # create an app, without the global instance
76 # create an app, without the global instance
77 app = BaseIPythonApplication()
77 app = BaseIPythonApplication()
78 app.initialize(argv=[])
78 app.initialize(argv=[])
79 return app.profile_dir
79 return app.profile_dir
80
80
81 algorithm = Enum(algorithms, default_value='sha256', config=True,
81 algorithm = Enum(algorithms, default_value='sha256', config=True,
82 help="""The hashing algorithm used to sign notebooks."""
82 help="""The hashing algorithm used to sign notebooks."""
83 )
83 )
84 def _algorithm_changed(self, name, old, new):
84 def _algorithm_changed(self, name, old, new):
85 self.digestmod = getattr(hashlib, self.algorithm)
85 self.digestmod = getattr(hashlib, self.algorithm)
86
86
87 digestmod = Any()
87 digestmod = Any()
88 def _digestmod_default(self):
88 def _digestmod_default(self):
89 return getattr(hashlib, self.algorithm)
89 return getattr(hashlib, self.algorithm)
90
90
91 secret_file = Unicode(config=True,
91 secret_file = Unicode(config=True,
92 help="""The file where the secret key is stored."""
92 help="""The file where the secret key is stored."""
93 )
93 )
94 def _secret_file_default(self):
94 def _secret_file_default(self):
95 if self.profile_dir is None:
95 if self.profile_dir is None:
96 return ''
96 return ''
97 return os.path.join(self.profile_dir.security_dir, 'notebook_secret')
97 return os.path.join(self.profile_dir.security_dir, 'notebook_secret')
98
98
99 secret = Bytes(config=True,
99 secret = Bytes(config=True,
100 help="""The secret key with which notebooks are signed."""
100 help="""The secret key with which notebooks are signed."""
101 )
101 )
102 def _secret_default(self):
102 def _secret_default(self):
103 # note : this assumes an Application is running
103 # note : this assumes an Application is running
104 if os.path.exists(self.secret_file):
104 if os.path.exists(self.secret_file):
105 with io.open(self.secret_file, 'rb') as f:
105 with io.open(self.secret_file, 'rb') as f:
106 return f.read()
106 return f.read()
107 else:
107 else:
108 secret = base64.encodestring(os.urandom(1024))
108 secret = base64.encodestring(os.urandom(1024))
109 self._write_secret_file(secret)
109 self._write_secret_file(secret)
110 return secret
110 return secret
111
111
112 def _write_secret_file(self, secret):
112 def _write_secret_file(self, secret):
113 """write my secret to my secret_file"""
113 """write my secret to my secret_file"""
114 self.log.info("Writing notebook-signing key to %s", self.secret_file)
114 self.log.info("Writing notebook-signing key to %s", self.secret_file)
115 with io.open(self.secret_file, 'wb') as f:
115 with io.open(self.secret_file, 'wb') as f:
116 f.write(secret)
116 f.write(secret)
117 try:
117 try:
118 os.chmod(self.secret_file, 0o600)
118 os.chmod(self.secret_file, 0o600)
119 except OSError:
119 except OSError:
120 self.log.warn(
120 self.log.warn(
121 "Could not set permissions on %s",
121 "Could not set permissions on %s",
122 self.secret_file
122 self.secret_file
123 )
123 )
124 return secret
124 return secret
125
125
126 def compute_signature(self, nb):
126 def compute_signature(self, nb):
127 """Compute a notebook's signature
127 """Compute a notebook's signature
128
128
129 by hashing the entire contents of the notebook via HMAC digest.
129 by hashing the entire contents of the notebook via HMAC digest.
130 """
130 """
131 hmac = HMAC(self.secret, digestmod=self.digestmod)
131 hmac = HMAC(self.secret, digestmod=self.digestmod)
132 # don't include the previous hash in the content to hash
132 # don't include the previous hash in the content to hash
133 with signature_removed(nb):
133 with signature_removed(nb):
134 # sign the whole thing
134 # sign the whole thing
135 for b in yield_everything(nb):
135 for b in yield_everything(nb):
136 hmac.update(b)
136 hmac.update(b)
137
137
138 return hmac.hexdigest()
138 return hmac.hexdigest()
139
139
140 def check_signature(self, nb):
140 def check_signature(self, nb):
141 """Check a notebook's stored signature
141 """Check a notebook's stored signature
142
142
143 If a signature is stored in the notebook's metadata,
143 If a signature is stored in the notebook's metadata,
144 a new signature is computed and compared with the stored value.
144 a new signature is computed and compared with the stored value.
145
145
146 Returns True if the signature is found and matches, False otherwise.
146 Returns True if the signature is found and matches, False otherwise.
147
147
148 The following conditions must all be met for a notebook to be trusted:
148 The following conditions must all be met for a notebook to be trusted:
149 - a signature is stored in the form 'scheme:hexdigest'
149 - a signature is stored in the form 'scheme:hexdigest'
150 - the stored scheme matches the requested scheme
150 - the stored scheme matches the requested scheme
151 - the requested scheme is available from hashlib
151 - the requested scheme is available from hashlib
152 - the computed hash from notebook_signature matches the stored hash
152 - the computed hash from notebook_signature matches the stored hash
153 """
153 """
154 stored_signature = nb['metadata'].get('signature', None)
154 stored_signature = nb['metadata'].get('signature', None)
155 if not stored_signature \
155 if not stored_signature \
156 or not isinstance(stored_signature, string_types) \
156 or not isinstance(stored_signature, string_types) \
157 or ':' not in stored_signature:
157 or ':' not in stored_signature:
158 return False
158 return False
159 stored_algo, sig = stored_signature.split(':', 1)
159 stored_algo, sig = stored_signature.split(':', 1)
160 if self.algorithm != stored_algo:
160 if self.algorithm != stored_algo:
161 return False
161 return False
162 my_signature = self.compute_signature(nb)
162 my_signature = self.compute_signature(nb)
163 return my_signature == sig
163 return my_signature == sig
164
164
165 def sign(self, nb):
165 def sign(self, nb):
166 """Sign a notebook, indicating that its output is trusted
166 """Sign a notebook, indicating that its output is trusted
167
167
168 stores 'algo:hmac-hexdigest' in notebook.metadata.signature
168 stores 'algo:hmac-hexdigest' in notebook.metadata.signature
169
169
170 e.g. 'sha256:deadbeef123...'
170 e.g. 'sha256:deadbeef123...'
171 """
171 """
172 signature = self.compute_signature(nb)
172 signature = self.compute_signature(nb)
173 nb['metadata']['signature'] = "%s:%s" % (self.algorithm, signature)
173 nb['metadata']['signature'] = "%s:%s" % (self.algorithm, signature)
174
174
175 def mark_cells(self, nb, trusted):
175 def mark_cells(self, nb, trusted):
176 """Mark cells as trusted if the notebook's signature can be verified
176 """Mark cells as trusted if the notebook's signature can be verified
177
177
178 Sets ``cell.metadata.trusted = True | False`` on all code cells,
178 Sets ``cell.metadata.trusted = True | False`` on all code cells,
179 depending on whether the stored signature can be verified.
179 depending on whether the stored signature can be verified.
180
180
181 This function is the inverse of check_cells
181 This function is the inverse of check_cells
182 """
182 """
183 if not nb['cells']:
183 if not nb['cells']:
184 # nothing to mark if there are no cells
184 # nothing to mark if there are no cells
185 return
185 return
186 for cell in nb['cells']:
186 for cell in nb['cells']:
187 if cell['cell_type'] == 'code':
187 if cell['cell_type'] == 'code':
188 cell['metadata']['trusted'] = trusted
188 cell['metadata']['trusted'] = trusted
189
189
190 def _check_cell(self, cell):
190 def _check_cell(self, cell):
191 """Do we trust an individual cell?
191 """Do we trust an individual cell?
192
192
193 Return True if:
193 Return True if:
194
194
195 - cell is explicitly trusted
195 - cell is explicitly trusted
196 - cell has no potentially unsafe rich output
196 - cell has no potentially unsafe rich output
197
197
198 If a cell has no output, or only simple print statements,
198 If a cell has no output, or only simple print statements,
199 it will always be trusted.
199 it will always be trusted.
200 """
200 """
201 # explicitly trusted
201 # explicitly trusted
202 if cell['metadata'].pop("trusted", False):
202 if cell['metadata'].pop("trusted", False):
203 return True
203 return True
204
204
205 # explicitly safe output
205 # explicitly safe output
206 safe = {
206 safe = {
207 'text/plain', 'image/png', 'image/jpeg',
207 'text/plain', 'image/png', 'image/jpeg',
208 }
208 }
209
209
210 for output in cell['outputs']:
210 for output in cell['outputs']:
211 output_type = output['output_type']
211 output_type = output['output_type']
212 if output_type in {'execute_result', 'display_data'}:
212 if output_type in {'execute_result', 'display_data'}:
213 # if there are any data keys not in the safe whitelist
213 # if there are any data keys not in the safe whitelist
214 output_keys = set(output).difference({"output_type", "prompt_number", "metadata"})
214 output_keys = set(output).difference({"output_type", "execution_count", "metadata"})
215 if output_keys.difference(safe):
215 if output_keys.difference(safe):
216 return False
216 return False
217
217
218 return True
218 return True
219
219
220 def check_cells(self, nb):
220 def check_cells(self, nb):
221 """Return whether all code cells are trusted
221 """Return whether all code cells are trusted
222
222
223 If there are no code cells, return True.
223 If there are no code cells, return True.
224
224
225 This function is the inverse of mark_cells.
225 This function is the inverse of mark_cells.
226 """
226 """
227 if not nb['cells']:
227 if not nb['cells']:
228 return True
228 return True
229 trusted = True
229 trusted = True
230 for cell in nb['cells']:
230 for cell in nb['cells']:
231 if cell['cell_type'] != 'code':
231 if cell['cell_type'] != 'code':
232 continue
232 continue
233 # only distrust a cell if it actually has some output to distrust
233 # only distrust a cell if it actually has some output to distrust
234 if not self._check_cell(cell):
234 if not self._check_cell(cell):
235 trusted = False
235 trusted = False
236
236
237 return trusted
237 return trusted
238
238
239
239
240 trust_flags = {
240 trust_flags = {
241 'reset' : (
241 'reset' : (
242 {'TrustNotebookApp' : { 'reset' : True}},
242 {'TrustNotebookApp' : { 'reset' : True}},
243 """Generate a new key for notebook signature.
243 """Generate a new key for notebook signature.
244 All previously signed notebooks will become untrusted.
244 All previously signed notebooks will become untrusted.
245 """
245 """
246 ),
246 ),
247 }
247 }
248 trust_flags.update(base_flags)
248 trust_flags.update(base_flags)
249 trust_flags.pop('init')
249 trust_flags.pop('init')
250
250
251
251
252 class TrustNotebookApp(BaseIPythonApplication):
252 class TrustNotebookApp(BaseIPythonApplication):
253
253
254 description="""Sign one or more IPython notebooks with your key,
254 description="""Sign one or more IPython notebooks with your key,
255 to trust their dynamic (HTML, Javascript) output.
255 to trust their dynamic (HTML, Javascript) output.
256
256
257 Trusting a notebook only applies to the current IPython profile.
257 Trusting a notebook only applies to the current IPython profile.
258 To trust a notebook for use with a profile other than default,
258 To trust a notebook for use with a profile other than default,
259 add `--profile [profile name]`.
259 add `--profile [profile name]`.
260
260
261 Otherwise, you will have to re-execute the notebook to see output.
261 Otherwise, you will have to re-execute the notebook to see output.
262 """
262 """
263
263
264 examples = """
264 examples = """
265 ipython trust mynotebook.ipynb and_this_one.ipynb
265 ipython trust mynotebook.ipynb and_this_one.ipynb
266 ipython trust --profile myprofile mynotebook.ipynb
266 ipython trust --profile myprofile mynotebook.ipynb
267 """
267 """
268
268
269 flags = trust_flags
269 flags = trust_flags
270
270
271 reset = Bool(False, config=True,
271 reset = Bool(False, config=True,
272 help="""If True, generate a new key for notebook signature.
272 help="""If True, generate a new key for notebook signature.
273 After reset, all previously signed notebooks will become untrusted.
273 After reset, all previously signed notebooks will become untrusted.
274 """
274 """
275 )
275 )
276
276
277 notary = Instance(NotebookNotary)
277 notary = Instance(NotebookNotary)
278 def _notary_default(self):
278 def _notary_default(self):
279 return NotebookNotary(parent=self, profile_dir=self.profile_dir)
279 return NotebookNotary(parent=self, profile_dir=self.profile_dir)
280
280
281 def sign_notebook(self, notebook_path):
281 def sign_notebook(self, notebook_path):
282 if not os.path.exists(notebook_path):
282 if not os.path.exists(notebook_path):
283 self.log.error("Notebook missing: %s" % notebook_path)
283 self.log.error("Notebook missing: %s" % notebook_path)
284 self.exit(1)
284 self.exit(1)
285 with io.open(notebook_path, encoding='utf8') as f:
285 with io.open(notebook_path, encoding='utf8') as f:
286 nb = read(f, 'json')
286 nb = read(f, 'json')
287 if self.notary.check_signature(nb):
287 if self.notary.check_signature(nb):
288 print("Notebook already signed: %s" % notebook_path)
288 print("Notebook already signed: %s" % notebook_path)
289 else:
289 else:
290 print("Signing notebook: %s" % notebook_path)
290 print("Signing notebook: %s" % notebook_path)
291 self.notary.sign(nb)
291 self.notary.sign(nb)
292 with io.open(notebook_path, 'w', encoding='utf8') as f:
292 with io.open(notebook_path, 'w', encoding='utf8') as f:
293 write(nb, f, 'json')
293 write(nb, f, 'json')
294
294
295 def generate_new_key(self):
295 def generate_new_key(self):
296 """Generate a new notebook signature key"""
296 """Generate a new notebook signature key"""
297 print("Generating new notebook key: %s" % self.notary.secret_file)
297 print("Generating new notebook key: %s" % self.notary.secret_file)
298 self.notary._write_secret_file(os.urandom(1024))
298 self.notary._write_secret_file(os.urandom(1024))
299
299
300 def start(self):
300 def start(self):
301 if self.reset:
301 if self.reset:
302 self.generate_new_key()
302 self.generate_new_key()
303 return
303 return
304 if not self.extra_args:
304 if not self.extra_args:
305 self.log.critical("Specify at least one notebook to sign.")
305 self.log.critical("Specify at least one notebook to sign.")
306 self.exit(1)
306 self.exit(1)
307
307
308 for notebook_path in self.extra_args:
308 for notebook_path in self.extra_args:
309 self.sign_notebook(notebook_path)
309 self.sign_notebook(notebook_path)
310
310
@@ -1,155 +1,155 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "cell_tags": ["<None>", null],
3 "cell_tags": ["<None>", null],
4 "name": "",
4 "name": "",
5 "kernel_info": {
5 "kernel_info": {
6 "name": "python",
6 "name": "python",
7 "language": "python"
7 "language": "python"
8 }
8 }
9 },
9 },
10 "nbformat": 4,
10 "nbformat": 4,
11 "nbformat_minor": 0,
11 "nbformat_minor": 0,
12 "cells": [
12 "cells": [
13 {
13 {
14 "cell_type": "heading",
14 "cell_type": "heading",
15 "level": 1,
15 "level": 1,
16 "metadata": {},
16 "metadata": {},
17 "source": [
17 "source": [
18 "nbconvert latex test"
18 "nbconvert latex test"
19 ]
19 ]
20 },
20 },
21 {
21 {
22 "cell_type": "markdown",
22 "cell_type": "markdown",
23 "metadata": {},
23 "metadata": {},
24 "source": [
24 "source": [
25 "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis."
25 "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus bibendum felis dictum sodales. Ut suscipit, orci ut interdum imperdiet, purus ligula mollis *justo*, non malesuada nisl augue eget lorem. Donec bibendum, erat sit amet porttitor aliquam, urna lorem ornare libero, in vehicula diam diam ut ante. Nam non urna rhoncus, accumsan elit sit amet, mollis tellus. Vestibulum nec tellus metus. Vestibulum tempor, ligula et vehicula rhoncus, sapien turpis faucibus lorem, id dapibus turpis mauris ac orci. Sed volutpat vestibulum venenatis."
26 ]
26 ]
27 },
27 },
28 {
28 {
29 "cell_type": "heading",
29 "cell_type": "heading",
30 "level": 2,
30 "level": 2,
31 "metadata": {},
31 "metadata": {},
32 "source": [
32 "source": [
33 "Printed Using Python"
33 "Printed Using Python"
34 ]
34 ]
35 },
35 },
36 {
36 {
37 "cell_type": "code",
37 "cell_type": "code",
38 "source": [
38 "source": [
39 "print(\"hello\")"
39 "print(\"hello\")"
40 ],
40 ],
41 "metadata": {
41 "metadata": {
42 "collapsed": false,
42 "collapsed": false,
43 "autoscroll": false
43 "autoscroll": false
44 },
44 },
45 "outputs": [
45 "outputs": [
46 {
46 {
47 "output_type": "stream",
47 "output_type": "stream",
48 "metadata": {},
48 "metadata": {},
49 "name": "stdout",
49 "name": "stdout",
50 "text": [
50 "text": [
51 "hello\n"
51 "hello\n"
52 ]
52 ]
53 }
53 }
54 ],
54 ],
55 "prompt_number": 1
55 "execution_count": 1
56 },
56 },
57 {
57 {
58 "cell_type": "heading",
58 "cell_type": "heading",
59 "level": 2,
59 "level": 2,
60 "metadata": {},
60 "metadata": {},
61 "source": [
61 "source": [
62 "Pyout"
62 "Pyout"
63 ]
63 ]
64 },
64 },
65 {
65 {
66 "cell_type": "code",
66 "cell_type": "code",
67 "source": [
67 "source": [
68 "from IPython.display import HTML\n",
68 "from IPython.display import HTML\n",
69 "HTML(\"\"\"\n",
69 "HTML(\"\"\"\n",
70 "<script>\n",
70 "<script>\n",
71 "console.log(\"hello\");\n",
71 "console.log(\"hello\");\n",
72 "</script>\n",
72 "</script>\n",
73 "<b>HTML</b>\n",
73 "<b>HTML</b>\n",
74 "\"\"\")"
74 "\"\"\")"
75 ],
75 ],
76 "metadata": {
76 "metadata": {
77 "collapsed": false,
77 "collapsed": false,
78 "autoscroll": false
78 "autoscroll": false
79 },
79 },
80 "outputs": [
80 "outputs": [
81 {
81 {
82 "text/html": [
82 "text/html": [
83 "\n",
83 "\n",
84 "<script>\n",
84 "<script>\n",
85 "console.log(\"hello\");\n",
85 "console.log(\"hello\");\n",
86 "</script>\n",
86 "</script>\n",
87 "<b>HTML</b>\n"
87 "<b>HTML</b>\n"
88 ],
88 ],
89 "metadata": {},
89 "metadata": {},
90 "output_type": "execute_result",
90 "output_type": "execute_result",
91 "prompt_number": 3,
91 "execution_count": 3,
92 "text/plain": [
92 "text/plain": [
93 "<IPython.core.display.HTML at 0x1112757d0>"
93 "<IPython.core.display.HTML at 0x1112757d0>"
94 ]
94 ]
95 }
95 }
96 ],
96 ],
97 "prompt_number": 3
97 "execution_count": 3
98 },
98 },
99 {
99 {
100 "cell_type": "code",
100 "cell_type": "code",
101 "source": [
101 "source": [
102 "%%javascript\n",
102 "%%javascript\n",
103 "console.log(\"hi\");"
103 "console.log(\"hi\");"
104 ],
104 ],
105 "metadata": {
105 "metadata": {
106 "collapsed": false,
106 "collapsed": false,
107 "autoscroll": false
107 "autoscroll": false
108 },
108 },
109 "outputs": [
109 "outputs": [
110 {
110 {
111 "text/javascript": [
111 "text/javascript": [
112 "console.log(\"hi\");"
112 "console.log(\"hi\");"
113 ],
113 ],
114 "metadata": {},
114 "metadata": {},
115 "output_type": "display_data",
115 "output_type": "display_data",
116 "text/plain": [
116 "text/plain": [
117 "<IPython.core.display.Javascript at 0x1112b4b50>"
117 "<IPython.core.display.Javascript at 0x1112b4b50>"
118 ]
118 ]
119 }
119 }
120 ],
120 ],
121 "prompt_number": 7
121 "execution_count": 7
122 },
122 },
123 {
123 {
124 "cell_type": "heading",
124 "cell_type": "heading",
125 "level": 3,
125 "level": 3,
126 "metadata": {},
126 "metadata": {},
127 "source": [
127 "source": [
128 "Image"
128 "Image"
129 ]
129 ]
130 },
130 },
131 {
131 {
132 "cell_type": "code",
132 "cell_type": "code",
133 "source": [
133 "source": [
134 "from IPython.display import Image\n",
134 "from IPython.display import Image\n",
135 "Image(\"http://ipython.org/_static/IPy_header.png\")"
135 "Image(\"http://ipython.org/_static/IPy_header.png\")"
136 ],
136 ],
137 "metadata": {
137 "metadata": {
138 "collapsed": false,
138 "collapsed": false,
139 "autoscroll": false
139 "autoscroll": false
140 },
140 },
141 "outputs": [
141 "outputs": [
142 {
142 {
143 "metadata": {},
143 "metadata": {},
144 "output_type": "execute_result",
144 "output_type": "execute_result",
145 "image/png": "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\n",
145 "image/png": "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\n",
146 "prompt_number": 6,
146 "execution_count": 6,
147 "text/plain": [
147 "text/plain": [
148 "<IPython.core.display.Image at 0x111275490>"
148 "<IPython.core.display.Image at 0x111275490>"
149 ]
149 ]
150 }
150 }
151 ],
151 ],
152 "prompt_number": 6
152 "execution_count": 6
153 }
153 }
154 ]
154 ]
155 }
155 }
@@ -1,209 +1,221 b''
1 """Code for converting notebooks to and from v3."""
1 """Code for converting notebooks to and from v3."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import json
6 import json
7
7
8 from .nbbase import (
8 from .nbbase import (
9 nbformat, nbformat_minor,
9 nbformat, nbformat_minor,
10 NotebookNode,
10 NotebookNode,
11 )
11 )
12
12
13 from IPython.nbformat import v3
13 from IPython.nbformat import v3
14 from IPython.utils.log import get_logger
14 from IPython.utils.log import get_logger
15
15
16
16
17 def upgrade(nb, from_version=3, from_minor=0):
17 def upgrade(nb, from_version=3, from_minor=0):
18 """Convert a notebook to v4.
18 """Convert a notebook to v4.
19
19
20 Parameters
20 Parameters
21 ----------
21 ----------
22 nb : NotebookNode
22 nb : NotebookNode
23 The Python representation of the notebook to convert.
23 The Python representation of the notebook to convert.
24 from_version : int
24 from_version : int
25 The original version of the notebook to convert.
25 The original version of the notebook to convert.
26 from_minor : int
26 from_minor : int
27 The original minor version of the notebook to convert (only relevant for v >= 3).
27 The original minor version of the notebook to convert (only relevant for v >= 3).
28 """
28 """
29 from IPython.nbformat.current import validate, ValidationError
29 from IPython.nbformat.current import validate, ValidationError
30 if from_version == 3:
30 if from_version == 3:
31 # Validate the notebook before conversion
31 # Validate the notebook before conversion
32 try:
32 try:
33 validate(nb, version=from_version)
33 validate(nb, version=from_version)
34 except ValidationError as e:
34 except ValidationError as e:
35 get_logger().error("Notebook JSON is not valid v%i: %s", from_version, e)
35 get_logger().error("Notebook JSON is not valid v%i: %s", from_version, e)
36
36
37 # Mark the original nbformat so consumers know it has been converted
37 # Mark the original nbformat so consumers know it has been converted
38 orig_nbformat = nb.pop('orig_nbformat', None)
38 orig_nbformat = nb.pop('orig_nbformat', None)
39 nb.metadata.orig_nbformat = orig_nbformat or 3
39 nb.metadata.orig_nbformat = orig_nbformat or 3
40
40
41 # Mark the new format
41 # Mark the new format
42 nb.nbformat = nbformat
42 nb.nbformat = nbformat
43 nb.nbformat_minor = nbformat_minor
43 nb.nbformat_minor = nbformat_minor
44
44
45 # remove worksheet(s)
45 # remove worksheet(s)
46 nb['cells'] = cells = []
46 nb['cells'] = cells = []
47 # In the unlikely event of multiple worksheets,
47 # In the unlikely event of multiple worksheets,
48 # they will be flattened
48 # they will be flattened
49 for ws in nb.pop('worksheets', []):
49 for ws in nb.pop('worksheets', []):
50 # upgrade each cell
50 # upgrade each cell
51 for cell in ws['cells']:
51 for cell in ws['cells']:
52 cells.append(upgrade_cell(cell))
52 cells.append(upgrade_cell(cell))
53 # upgrade metadata
53 # upgrade metadata
54 nb.metadata.pop('name', '')
54 nb.metadata.pop('name', '')
55 # Validate the converted notebook before returning it
55 # Validate the converted notebook before returning it
56 try:
56 try:
57 validate(nb, version=nbformat)
57 validate(nb, version=nbformat)
58 except ValidationError as e:
58 except ValidationError as e:
59 get_logger().error("Notebook JSON is not valid v%i: %s", nbformat, e)
59 get_logger().error("Notebook JSON is not valid v%i: %s", nbformat, e)
60 return nb
60 return nb
61 elif from_version == 4:
61 elif from_version == 4:
62 # nothing to do
62 # nothing to do
63 if from_minor != nbformat_minor:
63 if from_minor != nbformat_minor:
64 nb.metadata.orig_nbformat_minor = from_minor
64 nb.metadata.orig_nbformat_minor = from_minor
65 nb.nbformat_minor = nbformat_minor
65 nb.nbformat_minor = nbformat_minor
66
66
67 return nb
67 return nb
68 else:
68 else:
69 raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \
69 raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \
70 'Try using the IPython.nbformat.convert module.' % from_version)
70 'Try using the IPython.nbformat.convert module.' % from_version)
71
71
72 def upgrade_cell(cell):
72 def upgrade_cell(cell):
73 """upgrade a cell from v3 to v4
73 """upgrade a cell from v3 to v4
74
74
75 code cell:
75 code cell:
76 - remove language metadata
76 - remove language metadata
77 - cell.input -> cell.source
77 - cell.input -> cell.source
78 - cell.prompt_number -> cell.execution_count
78 - update outputs
79 - update outputs
79 """
80 """
80 cell.setdefault('metadata', NotebookNode())
81 cell.setdefault('metadata', NotebookNode())
81 if cell.cell_type == 'code':
82 if cell.cell_type == 'code':
82 cell.pop('language', '')
83 cell.pop('language', '')
83 cell.metadata.collapsed = cell.pop('collapsed')
84 cell.metadata.collapsed = cell.pop('collapsed')
84 cell.source = cell.pop('input')
85 cell.source = cell.pop('input')
85 cell.setdefault('prompt_number', None)
86 cell.execution_count = cell.pop('prompt_number', None)
86 cell.outputs = upgrade_outputs(cell.outputs)
87 cell.outputs = upgrade_outputs(cell.outputs)
87 elif cell.cell_type == 'html':
88 elif cell.cell_type == 'html':
88 # Technically, this exists. It will never happen in practice.
89 # Technically, this exists. It will never happen in practice.
89 cell.cell_type = 'markdown'
90 cell.cell_type = 'markdown'
90 return cell
91 return cell
91
92
92 def downgrade_cell(cell):
93 def downgrade_cell(cell):
94 """downgrade a cell from v4 to v3
95
96 code cell:
97 - set cell.language
98 - cell.input <- cell.source
99 - cell.prompt_number <- cell.execution_count
100 - update outputs
101 """
93 if cell.cell_type == 'code':
102 if cell.cell_type == 'code':
94 cell.language = 'python'
103 cell.language = 'python'
95 cell.input = cell.pop('source', '')
104 cell.input = cell.pop('source', '')
105 cell.prompt_number = cell.pop('execution_count', None)
96 cell.collapsed = cell.metadata.pop('collapsed', False)
106 cell.collapsed = cell.metadata.pop('collapsed', False)
97 cell.outputs = downgrade_outputs(cell.outputs)
107 cell.outputs = downgrade_outputs(cell.outputs)
98 return cell
108 return cell
99
109
100 _mime_map = {
110 _mime_map = {
101 "text" : "text/plain",
111 "text" : "text/plain",
102 "html" : "text/html",
112 "html" : "text/html",
103 "svg" : "image/svg+xml",
113 "svg" : "image/svg+xml",
104 "png" : "image/png",
114 "png" : "image/png",
105 "jpeg" : "image/jpeg",
115 "jpeg" : "image/jpeg",
106 "latex" : "text/latex",
116 "latex" : "text/latex",
107 "json" : "application/json",
117 "json" : "application/json",
108 "javascript" : "application/javascript",
118 "javascript" : "application/javascript",
109 };
119 };
110
120
111 def to_mime_key(d):
121 def to_mime_key(d):
112 """convert dict with v3 aliases to plain mime-type keys"""
122 """convert dict with v3 aliases to plain mime-type keys"""
113 for alias, mime in _mime_map.items():
123 for alias, mime in _mime_map.items():
114 if alias in d:
124 if alias in d:
115 d[mime] = d.pop(alias)
125 d[mime] = d.pop(alias)
116 return d
126 return d
117
127
118 def from_mime_key(d):
128 def from_mime_key(d):
119 """convert dict with mime-type keys to v3 aliases"""
129 """convert dict with mime-type keys to v3 aliases"""
120 for alias, mime in _mime_map.items():
130 for alias, mime in _mime_map.items():
121 if mime in d:
131 if mime in d:
122 d[alias] = d.pop(mime)
132 d[alias] = d.pop(mime)
123 return d
133 return d
124
134
125 def upgrade_output(output):
135 def upgrade_output(output):
126 """upgrade a single code cell output from v3 to v4
136 """upgrade a single code cell output from v3 to v4
127
137
128 - pyout -> execute_result
138 - pyout -> execute_result
129 - pyerr -> error
139 - pyerr -> error
130 - mime-type keys
140 - mime-type keys
131 - stream.stream -> stream.name
141 - stream.stream -> stream.name
132 """
142 """
133 output.setdefault('metadata', NotebookNode())
143 output.setdefault('metadata', NotebookNode())
134 if output['output_type'] in {'pyout', 'display_data'}:
144 if output['output_type'] in {'pyout', 'display_data'}:
135 if output['output_type'] == 'pyout':
145 if output['output_type'] == 'pyout':
136 output['output_type'] = 'execute_result'
146 output['output_type'] = 'execute_result'
147 output['execution_count'] = output.pop('prompt_number', None)
137 to_mime_key(output)
148 to_mime_key(output)
138 to_mime_key(output.metadata)
149 to_mime_key(output.metadata)
139 if 'application/json' in output:
150 if 'application/json' in output:
140 output['application/json'] = json.loads(output['application/json'])
151 output['application/json'] = json.loads(output['application/json'])
141 # promote ascii bytes (from v2) to unicode
152 # promote ascii bytes (from v2) to unicode
142 for key in ('image/png', 'image/jpeg'):
153 for key in ('image/png', 'image/jpeg'):
143 if key in output and isinstance(output[key], bytes):
154 if key in output and isinstance(output[key], bytes):
144 output[key] = output[key].decode('ascii')
155 output[key] = output[key].decode('ascii')
145 elif output['output_type'] == 'pyerr':
156 elif output['output_type'] == 'pyerr':
146 output['output_type'] = 'error'
157 output['output_type'] = 'error'
147 elif output['output_type'] == 'stream':
158 elif output['output_type'] == 'stream':
148 output['name'] = output.pop('stream')
159 output['name'] = output.pop('stream')
149 return output
160 return output
150
161
151 def downgrade_output(output):
162 def downgrade_output(output):
152 """downgrade a single code cell output to v3 from v4
163 """downgrade a single code cell output to v3 from v4
153
164
154 - pyout <- execute_result
165 - pyout <- execute_result
155 - pyerr <- error
166 - pyerr <- error
156 - un-mime-type keys
167 - un-mime-type keys
157 - stream.stream <- stream.name
168 - stream.stream <- stream.name
158 """
169 """
159 if output['output_type'] == 'execute_result':
170 if output['output_type'] == 'execute_result':
160 output['output_type'] = 'pyout'
171 output['output_type'] = 'pyout'
172 output['prompt_number'] = output.pop('execution_count', None)
161 if 'application/json' in output:
173 if 'application/json' in output:
162 output['application/json'] = json.dumps(output['application/json'])
174 output['application/json'] = json.dumps(output['application/json'])
163 from_mime_key(output)
175 from_mime_key(output)
164 from_mime_key(output.get('metadata', {}))
176 from_mime_key(output.get('metadata', {}))
165 elif output['output_type'] == 'error':
177 elif output['output_type'] == 'error':
166 output['output_type'] = 'pyerr'
178 output['output_type'] = 'pyerr'
167 elif output['output_type'] == 'display_data':
179 elif output['output_type'] == 'display_data':
168 if 'application/json' in output:
180 if 'application/json' in output:
169 output['application/json'] = json.dumps(output['application/json'])
181 output['application/json'] = json.dumps(output['application/json'])
170 from_mime_key(output)
182 from_mime_key(output)
171 from_mime_key(output.get('metadata', {}))
183 from_mime_key(output.get('metadata', {}))
172 elif output['output_type'] == 'stream':
184 elif output['output_type'] == 'stream':
173 output['stream'] = output.pop('name')
185 output['stream'] = output.pop('name')
174 output.pop('metadata')
186 output.pop('metadata')
175 return output
187 return output
176
188
177 def upgrade_outputs(outputs):
189 def upgrade_outputs(outputs):
178 """upgrade outputs of a code cell from v3 to v4"""
190 """upgrade outputs of a code cell from v3 to v4"""
179 return [upgrade_output(op) for op in outputs]
191 return [upgrade_output(op) for op in outputs]
180
192
181 def downgrade_outputs(outputs):
193 def downgrade_outputs(outputs):
182 """downgrade outputs of a code cell to v3 from v4"""
194 """downgrade outputs of a code cell to v3 from v4"""
183 return [downgrade_output(op) for op in outputs]
195 return [downgrade_output(op) for op in outputs]
184
196
185 def downgrade(nb):
197 def downgrade(nb):
186 """Convert a v4 notebook to v3.
198 """Convert a v4 notebook to v3.
187
199
188 Parameters
200 Parameters
189 ----------
201 ----------
190 nb : NotebookNode
202 nb : NotebookNode
191 The Python representation of the notebook to convert.
203 The Python representation of the notebook to convert.
192 """
204 """
193 from IPython.nbformat.current import validate
205 from IPython.nbformat.current import validate
194 # Validate the notebook before conversion
206 # Validate the notebook before conversion
195 validate(nb, version=nbformat)
207 validate(nb, version=nbformat)
196
208
197 if nb.nbformat != 4:
209 if nb.nbformat != 4:
198 return nb
210 return nb
199 nb.nbformat = v3.nbformat
211 nb.nbformat = v3.nbformat
200 nb.nbformat_minor = v3.nbformat_minor
212 nb.nbformat_minor = v3.nbformat_minor
201 cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ]
213 cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ]
202 nb.worksheets = [v3.new_worksheet(cells=cells)]
214 nb.worksheets = [v3.new_worksheet(cells=cells)]
203 nb.metadata.setdefault('name', '')
215 nb.metadata.setdefault('name', '')
204 nb.metadata.pop('orig_nbformat', None)
216 nb.metadata.pop('orig_nbformat', None)
205 nb.metadata.pop('orig_nbformat_minor', None)
217 nb.metadata.pop('orig_nbformat_minor', None)
206
218
207 # Validate the converted notebook before returning it
219 # Validate the converted notebook before returning it
208 validate(nb, version=v3.nbformat)
220 validate(nb, version=v3.nbformat)
209 return nb
221 return nb
@@ -1,148 +1,148 b''
1 """Python API for composing notebook elements
1 """Python API for composing notebook elements
2
2
3 The Python representation of a notebook is a nested structure of
3 The Python representation of a notebook is a nested structure of
4 dictionary subclasses that support attribute access
4 dictionary subclasses that support attribute access
5 (IPython.utils.ipstruct.Struct). The functions in this module are merely
5 (IPython.utils.ipstruct.Struct). The functions in this module are merely
6 helpers to build the structs in the right form.
6 helpers to build the structs in the right form.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 from IPython.utils.ipstruct import Struct
12 from IPython.utils.ipstruct import Struct
13
13
14 # Change this when incrementing the nbformat version
14 # Change this when incrementing the nbformat version
15 nbformat = 4
15 nbformat = 4
16 nbformat_minor = 0
16 nbformat_minor = 0
17 nbformat_schema = 'nbformat.v4.schema.json'
17 nbformat_schema = 'nbformat.v4.schema.json'
18
18
19
19
20 def validate(node, ref=None):
20 def validate(node, ref=None):
21 """validate a v4 node"""
21 """validate a v4 node"""
22 from ..current import validate
22 from ..current import validate
23 return validate(node, ref=ref, version=nbformat)
23 return validate(node, ref=ref, version=nbformat)
24
24
25
25
26 class NotebookNode(Struct):
26 class NotebookNode(Struct):
27 pass
27 pass
28
28
29 def from_dict(d):
29 def from_dict(d):
30 if isinstance(d, dict):
30 if isinstance(d, dict):
31 newd = NotebookNode()
31 newd = NotebookNode()
32 for k,v in d.items():
32 for k,v in d.items():
33 newd[k] = from_dict(v)
33 newd[k] = from_dict(v)
34 return newd
34 return newd
35 elif isinstance(d, (tuple, list)):
35 elif isinstance(d, (tuple, list)):
36 return [from_dict(i) for i in d]
36 return [from_dict(i) for i in d]
37 else:
37 else:
38 return d
38 return d
39
39
40
40
41 def new_output(output_type, mime_bundle=None, **kwargs):
41 def new_output(output_type, mime_bundle=None, **kwargs):
42 """Create a new output, to go in the ``cell.outputs`` list of a code cell."""
42 """Create a new output, to go in the ``cell.outputs`` list of a code cell."""
43 output = NotebookNode(output_type=output_type)
43 output = NotebookNode(output_type=output_type)
44 output.update(from_dict(kwargs))
44 output.update(from_dict(kwargs))
45 if mime_bundle:
45 if mime_bundle:
46 output.update(mime_bundle)
46 output.update(mime_bundle)
47 # populate defaults:
47 # populate defaults:
48 output.setdefault('metadata', NotebookNode())
48 output.setdefault('metadata', NotebookNode())
49 if output_type == 'stream':
49 if output_type == 'stream':
50 output.setdefault('name', 'stdout')
50 output.setdefault('name', 'stdout')
51 output.setdefault('text', '')
51 output.setdefault('text', '')
52 validate(output, output_type)
52 validate(output, output_type)
53 return output
53 return output
54
54
55
55
56 def output_from_msg(msg):
56 def output_from_msg(msg):
57 """Create a NotebookNode for an output from a kernel's IOPub message.
57 """Create a NotebookNode for an output from a kernel's IOPub message.
58
58
59 Returns
59 Returns
60 -------
60 -------
61
61
62 NotebookNode: the output as a notebook node.
62 NotebookNode: the output as a notebook node.
63
63
64 Raises
64 Raises
65 ------
65 ------
66
66
67 ValueError: if the message is not an output message.
67 ValueError: if the message is not an output message.
68
68
69 """
69 """
70 msg_type = msg['header']['msg_type']
70 msg_type = msg['header']['msg_type']
71 content = msg['content']
71 content = msg['content']
72
72
73 if msg_type == 'execute_result':
73 if msg_type == 'execute_result':
74 return new_output(output_type=msg_type,
74 return new_output(output_type=msg_type,
75 metadata=content['metadata'],
75 metadata=content['metadata'],
76 mime_bundle=content['data'],
76 mime_bundle=content['data'],
77 prompt_number=content['execution_count'],
77 execution_count=content['execution_count'],
78 )
78 )
79
79
80 elif msg_type == 'stream':
80 elif msg_type == 'stream':
81 return new_output(output_type=msg_type,
81 return new_output(output_type=msg_type,
82 name=content['name'],
82 name=content['name'],
83 data=content['data'],
83 data=content['data'],
84 )
84 )
85 elif msg_type == 'display_data':
85 elif msg_type == 'display_data':
86 return new_output(output_type=msg_type,
86 return new_output(output_type=msg_type,
87 metadata=content['metadata'],
87 metadata=content['metadata'],
88 mime_bundle=content['data'],
88 mime_bundle=content['data'],
89 )
89 )
90 elif msg_type == 'error':
90 elif msg_type == 'error':
91 return new_output(output_type=msg_type,
91 return new_output(output_type=msg_type,
92 ename=content['ename'],
92 ename=content['ename'],
93 evalue=content['evalue'],
93 evalue=content['evalue'],
94 traceback=content['traceback'],
94 traceback=content['traceback'],
95 )
95 )
96 else:
96 else:
97 raise ValueError("Unrecognized output msg type: %r" % msg_type)
97 raise ValueError("Unrecognized output msg type: %r" % msg_type)
98
98
99
99
100 def new_code_cell(source='', **kwargs):
100 def new_code_cell(source='', **kwargs):
101 """Create a new code cell"""
101 """Create a new code cell"""
102 cell = NotebookNode(cell_type='code', source=source)
102 cell = NotebookNode(cell_type='code', source=source)
103 cell.update(from_dict(kwargs))
103 cell.update(from_dict(kwargs))
104 cell.setdefault('metadata', NotebookNode())
104 cell.setdefault('metadata', NotebookNode())
105 cell.setdefault('source', '')
105 cell.setdefault('source', '')
106 cell.setdefault('prompt_number', None)
106 cell.setdefault('execution_count', None)
107 cell.setdefault('outputs', [])
107 cell.setdefault('outputs', [])
108
108
109 validate(cell, 'code_cell')
109 validate(cell, 'code_cell')
110 return cell
110 return cell
111
111
112 def new_markdown_cell(source='', **kwargs):
112 def new_markdown_cell(source='', **kwargs):
113 """Create a new markdown cell"""
113 """Create a new markdown cell"""
114 cell = NotebookNode(cell_type='markdown', source=source)
114 cell = NotebookNode(cell_type='markdown', source=source)
115 cell.update(from_dict(kwargs))
115 cell.update(from_dict(kwargs))
116 cell.setdefault('metadata', NotebookNode())
116 cell.setdefault('metadata', NotebookNode())
117
117
118 validate(cell, 'markdown_cell')
118 validate(cell, 'markdown_cell')
119 return cell
119 return cell
120
120
121 def new_heading_cell(source='', **kwargs):
121 def new_heading_cell(source='', **kwargs):
122 """Create a new heading cell"""
122 """Create a new heading cell"""
123 cell = NotebookNode(cell_type='heading', source=source)
123 cell = NotebookNode(cell_type='heading', source=source)
124 cell.update(from_dict(kwargs))
124 cell.update(from_dict(kwargs))
125 cell.setdefault('metadata', NotebookNode())
125 cell.setdefault('metadata', NotebookNode())
126 cell.setdefault('level', 1)
126 cell.setdefault('level', 1)
127
127
128 validate(cell, 'heading_cell')
128 validate(cell, 'heading_cell')
129 return cell
129 return cell
130
130
131 def new_raw_cell(source='', **kwargs):
131 def new_raw_cell(source='', **kwargs):
132 """Create a new raw cell"""
132 """Create a new raw cell"""
133 cell = NotebookNode(cell_type='raw', source=source)
133 cell = NotebookNode(cell_type='raw', source=source)
134 cell.update(from_dict(kwargs))
134 cell.update(from_dict(kwargs))
135 cell.setdefault('metadata', NotebookNode())
135 cell.setdefault('metadata', NotebookNode())
136
136
137 validate(cell, 'raw_cell')
137 validate(cell, 'raw_cell')
138 return cell
138 return cell
139
139
140 def new_notebook(**kwargs):
140 def new_notebook(**kwargs):
141 """Create a new notebook"""
141 """Create a new notebook"""
142 nb = from_dict(kwargs)
142 nb = from_dict(kwargs)
143 nb.nbformat = nbformat
143 nb.nbformat = nbformat
144 nb.nbformat_minor = nbformat_minor
144 nb.nbformat_minor = nbformat_minor
145 nb.setdefault('cells', [])
145 nb.setdefault('cells', [])
146 nb.setdefault('metadata', NotebookNode())
146 nb.setdefault('metadata', NotebookNode())
147 validate(nb)
147 validate(nb)
148 return nb
148 return nb
@@ -1,346 +1,346 b''
1 {
1 {
2 "$schema": "http://json-schema.org/draft-04/schema#",
2 "$schema": "http://json-schema.org/draft-04/schema#",
3 "description": "IPython Notebook v4.0 JSON schema.",
3 "description": "IPython Notebook v4.0 JSON schema.",
4 "type": "object",
4 "type": "object",
5 "additionalProperties": false,
5 "additionalProperties": false,
6 "required": ["metadata", "nbformat_minor", "nbformat", "cells"],
6 "required": ["metadata", "nbformat_minor", "nbformat", "cells"],
7 "properties": {
7 "properties": {
8 "metadata": {
8 "metadata": {
9 "description": "Notebook root-level metadata.",
9 "description": "Notebook root-level metadata.",
10 "type": "object",
10 "type": "object",
11 "additionalProperties": true,
11 "additionalProperties": true,
12 "properties": {
12 "properties": {
13 "kernel_info": {
13 "kernel_info": {
14 "description": "Kernel information.",
14 "description": "Kernel information.",
15 "type": "object",
15 "type": "object",
16 "required": ["name", "language"],
16 "required": ["name", "language"],
17 "properties": {
17 "properties": {
18 "name": {
18 "name": {
19 "description": "Name of the kernel specification.",
19 "description": "Name of the kernel specification.",
20 "type": "string"
20 "type": "string"
21 },
21 },
22 "language": {
22 "language": {
23 "description": "The programming language which this kernel runs.",
23 "description": "The programming language which this kernel runs.",
24 "type": "string"
24 "type": "string"
25 },
25 },
26 "codemirror_mode": {
26 "codemirror_mode": {
27 "description": "The codemirror mode to use for code in this language.",
27 "description": "The codemirror mode to use for code in this language.",
28 "type": "string"
28 "type": "string"
29 }
29 }
30 }
30 }
31 },
31 },
32 "signature": {
32 "signature": {
33 "description": "Hash of the notebook.",
33 "description": "Hash of the notebook.",
34 "type": "string"
34 "type": "string"
35 },
35 },
36 "orig_nbformat": {
36 "orig_nbformat": {
37 "description": "Original notebook format (major number) before converting the notebook between versions. This should never be written to a file.",
37 "description": "Original notebook format (major number) before converting the notebook between versions. This should never be written to a file.",
38 "type": "integer",
38 "type": "integer",
39 "minimum": 1
39 "minimum": 1
40 }
40 }
41 }
41 }
42 },
42 },
43 "nbformat_minor": {
43 "nbformat_minor": {
44 "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.",
44 "description": "Notebook format (minor number). Incremented for backward compatible changes to the notebook format.",
45 "type": "integer",
45 "type": "integer",
46 "minimum": 0
46 "minimum": 0
47 },
47 },
48 "nbformat": {
48 "nbformat": {
49 "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.",
49 "description": "Notebook format (major number). Incremented between backwards incompatible changes to the notebook format.",
50 "type": "integer",
50 "type": "integer",
51 "minimum": 4,
51 "minimum": 4,
52 "maximum": 4
52 "maximum": 4
53 },
53 },
54 "cells": {
54 "cells": {
55 "description": "Array of cells of the current notebook.",
55 "description": "Array of cells of the current notebook.",
56 "type": "array",
56 "type": "array",
57 "items": {
57 "items": {
58 "type": "object",
58 "type": "object",
59 "oneOf": [
59 "oneOf": [
60 {"$ref": "#/definitions/raw_cell"},
60 {"$ref": "#/definitions/raw_cell"},
61 {"$ref": "#/definitions/markdown_cell"},
61 {"$ref": "#/definitions/markdown_cell"},
62 {"$ref": "#/definitions/heading_cell"},
62 {"$ref": "#/definitions/heading_cell"},
63 {"$ref": "#/definitions/code_cell"}
63 {"$ref": "#/definitions/code_cell"}
64 ]
64 ]
65 }
65 }
66 }
66 }
67 },
67 },
68
68
69 "definitions": {
69 "definitions": {
70
70
71 "raw_cell": {
71 "raw_cell": {
72 "description": "Notebook raw nbconvert cell.",
72 "description": "Notebook raw nbconvert cell.",
73 "type": "object",
73 "type": "object",
74 "additionalProperties": false,
74 "additionalProperties": false,
75 "required": ["cell_type", "metadata", "source"],
75 "required": ["cell_type", "metadata", "source"],
76 "properties": {
76 "properties": {
77 "cell_type": {
77 "cell_type": {
78 "description": "String identifying the type of cell.",
78 "description": "String identifying the type of cell.",
79 "enum": ["raw"]
79 "enum": ["raw"]
80 },
80 },
81 "metadata": {
81 "metadata": {
82 "description": "Cell-level metadata.",
82 "description": "Cell-level metadata.",
83 "type": "object",
83 "type": "object",
84 "additionalProperties": true,
84 "additionalProperties": true,
85 "properties": {
85 "properties": {
86 "format": {
86 "format": {
87 "description": "Raw cell metadata format for nbconvert.",
87 "description": "Raw cell metadata format for nbconvert.",
88 "type": "string"
88 "type": "string"
89 },
89 },
90 "name": {"$ref": "#/definitions/misc/metadata_name"},
90 "name": {"$ref": "#/definitions/misc/metadata_name"},
91 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
91 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
92 }
92 }
93 },
93 },
94 "source": {"$ref": "#/definitions/misc/source"}
94 "source": {"$ref": "#/definitions/misc/source"}
95 }
95 }
96 },
96 },
97
97
98 "markdown_cell": {
98 "markdown_cell": {
99 "description": "Notebook markdown cell.",
99 "description": "Notebook markdown cell.",
100 "type": "object",
100 "type": "object",
101 "additionalProperties": false,
101 "additionalProperties": false,
102 "required": ["cell_type", "metadata", "source"],
102 "required": ["cell_type", "metadata", "source"],
103 "properties": {
103 "properties": {
104 "cell_type": {
104 "cell_type": {
105 "description": "String identifying the type of cell.",
105 "description": "String identifying the type of cell.",
106 "enum": ["markdown"]
106 "enum": ["markdown"]
107 },
107 },
108 "metadata": {
108 "metadata": {
109 "description": "Cell-level metadata.",
109 "description": "Cell-level metadata.",
110 "type": "object",
110 "type": "object",
111 "properties": {
111 "properties": {
112 "name": {"$ref": "#/definitions/misc/metadata_name"},
112 "name": {"$ref": "#/definitions/misc/metadata_name"},
113 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
113 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
114 },
114 },
115 "additionalProperties": true
115 "additionalProperties": true
116 },
116 },
117 "source": {"$ref": "#/definitions/misc/source"}
117 "source": {"$ref": "#/definitions/misc/source"}
118 }
118 }
119 },
119 },
120
120
121 "heading_cell": {
121 "heading_cell": {
122 "description": "Notebook heading cell.",
122 "description": "Notebook heading cell.",
123 "type": "object",
123 "type": "object",
124 "additionalProperties": false,
124 "additionalProperties": false,
125 "required": ["cell_type", "metadata", "source", "level"],
125 "required": ["cell_type", "metadata", "source", "level"],
126 "properties": {
126 "properties": {
127 "cell_type": {
127 "cell_type": {
128 "description": "String identifying the type of cell.",
128 "description": "String identifying the type of cell.",
129 "enum": ["heading"]
129 "enum": ["heading"]
130 },
130 },
131 "metadata": {
131 "metadata": {
132 "description": "Cell-level metadata.",
132 "description": "Cell-level metadata.",
133 "type": "object",
133 "type": "object",
134 "properties": {
134 "properties": {
135 "name": {"$ref": "#/definitions/misc/metadata_name"},
135 "name": {"$ref": "#/definitions/misc/metadata_name"},
136 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
136 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
137 },
137 },
138 "additionalProperties": true
138 "additionalProperties": true
139 },
139 },
140 "source": {"$ref": "#/definitions/misc/source"},
140 "source": {"$ref": "#/definitions/misc/source"},
141 "level": {
141 "level": {
142 "description": "Level of heading cells.",
142 "description": "Level of heading cells.",
143 "type": "integer",
143 "type": "integer",
144 "minimum": 1
144 "minimum": 1
145 }
145 }
146 }
146 }
147 },
147 },
148
148
149 "code_cell": {
149 "code_cell": {
150 "description": "Notebook code cell.",
150 "description": "Notebook code cell.",
151 "type": "object",
151 "type": "object",
152 "additionalProperties": false,
152 "additionalProperties": false,
153 "required": ["cell_type", "metadata", "source", "outputs", "prompt_number"],
153 "required": ["cell_type", "metadata", "source", "outputs", "execution_count"],
154 "properties": {
154 "properties": {
155 "cell_type": {
155 "cell_type": {
156 "description": "String identifying the type of cell.",
156 "description": "String identifying the type of cell.",
157 "enum": ["code"]
157 "enum": ["code"]
158 },
158 },
159 "metadata": {
159 "metadata": {
160 "description": "Cell-level metadata.",
160 "description": "Cell-level metadata.",
161 "type": "object",
161 "type": "object",
162 "additionalProperties": true,
162 "additionalProperties": true,
163 "properties": {
163 "properties": {
164 "collapsed": {
164 "collapsed": {
165 "description": "Whether the cell is collapsed/expanded.",
165 "description": "Whether the cell is collapsed/expanded.",
166 "type": "boolean"
166 "type": "boolean"
167 },
167 },
168 "autoscroll": {
168 "autoscroll": {
169 "description": "Whether the cell's output is scrolled, unscrolled, or autoscrolled.",
169 "description": "Whether the cell's output is scrolled, unscrolled, or autoscrolled.",
170 "enum": [true, false, "auto"]
170 "enum": [true, false, "auto"]
171 },
171 },
172 "name": {"$ref": "#/definitions/misc/metadata_name"},
172 "name": {"$ref": "#/definitions/misc/metadata_name"},
173 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
173 "tags": {"$ref": "#/definitions/misc/metadata_tags"}
174 }
174 }
175 },
175 },
176 "source": {"$ref": "#/definitions/misc/source"},
176 "source": {"$ref": "#/definitions/misc/source"},
177 "outputs": {
177 "outputs": {
178 "description": "Execution, display, or stream outputs.",
178 "description": "Execution, display, or stream outputs.",
179 "type": "array",
179 "type": "array",
180 "items": {"$ref": "#/definitions/output"}
180 "items": {"$ref": "#/definitions/output"}
181 },
181 },
182 "prompt_number": {
182 "execution_count": {
183 "description": "The code cell's prompt number. Will be null if the cell has not been run.",
183 "description": "The code cell's prompt number. Will be null if the cell has not been run.",
184 "type": ["integer", "null"],
184 "type": ["integer", "null"],
185 "minimum": 0
185 "minimum": 0
186 }
186 }
187 }
187 }
188 },
188 },
189 "output": {
189 "output": {
190 "type": "object",
190 "type": "object",
191 "oneOf": [
191 "oneOf": [
192 {"$ref": "#/definitions/execute_result"},
192 {"$ref": "#/definitions/execute_result"},
193 {"$ref": "#/definitions/display_data"},
193 {"$ref": "#/definitions/display_data"},
194 {"$ref": "#/definitions/stream"},
194 {"$ref": "#/definitions/stream"},
195 {"$ref": "#/definitions/error"}
195 {"$ref": "#/definitions/error"}
196 ]
196 ]
197 },
197 },
198 "execute_result": {
198 "execute_result": {
199 "description": "Result of executing a code cell.",
199 "description": "Result of executing a code cell.",
200 "type": "object",
200 "type": "object",
201 "additionalProperties": false,
201 "additionalProperties": false,
202 "required": ["output_type", "metadata", "prompt_number"],
202 "required": ["output_type", "metadata", "execution_count"],
203 "properties": {
203 "properties": {
204 "output_type": {
204 "output_type": {
205 "description": "Type of cell output.",
205 "description": "Type of cell output.",
206 "enum": ["execute_result"]
206 "enum": ["execute_result"]
207 },
207 },
208 "prompt_number": {
208 "execution_count": {
209 "description": "A result's prompt number.",
209 "description": "A result's prompt number.",
210 "type": ["integer"],
210 "type": ["integer", "null"],
211 "minimum": 0
211 "minimum": 0
212 },
212 },
213 "application/json": {
213 "application/json": {
214 "type": "object"
214 "type": "object"
215 },
215 },
216 "metadata": {"$ref": "#/definitions/misc/output_metadata"}
216 "metadata": {"$ref": "#/definitions/misc/output_metadata"}
217 },
217 },
218 "patternProperties": {
218 "patternProperties": {
219 "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": {
219 "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": {
220 "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
220 "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
221 "$ref": "#/definitions/misc/multiline_string"
221 "$ref": "#/definitions/misc/multiline_string"
222 }
222 }
223 }
223 }
224 },
224 },
225
225
226 "display_data": {
226 "display_data": {
227 "description": "Data displayed as a result of code cell execution.",
227 "description": "Data displayed as a result of code cell execution.",
228 "type": "object",
228 "type": "object",
229 "additionalProperties": false,
229 "additionalProperties": false,
230 "required": ["output_type", "metadata"],
230 "required": ["output_type", "metadata"],
231 "properties": {
231 "properties": {
232 "output_type": {
232 "output_type": {
233 "description": "Type of cell output.",
233 "description": "Type of cell output.",
234 "enum": ["display_data"]
234 "enum": ["display_data"]
235 },
235 },
236 "application/json": {
236 "application/json": {
237 "type": "object"
237 "type": "object"
238 },
238 },
239 "metadata": {"$ref": "#/definitions/misc/output_metadata"}
239 "metadata": {"$ref": "#/definitions/misc/output_metadata"}
240 },
240 },
241 "patternProperties": {
241 "patternProperties": {
242 "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": {
242 "^(?!application/json$)[a-zA-Z0-9]+/[a-zA-Z0-9\\-\\+\\.]+$": {
243 "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
243 "description": "mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
244 "$ref": "#/definitions/misc/multiline_string"
244 "$ref": "#/definitions/misc/multiline_string"
245 }
245 }
246 }
246 }
247 },
247 },
248
248
249 "stream": {
249 "stream": {
250 "description": "Stream output from a code cell.",
250 "description": "Stream output from a code cell.",
251 "type": "object",
251 "type": "object",
252 "additionalProperties": false,
252 "additionalProperties": false,
253 "required": ["output_type", "metadata", "name", "text"],
253 "required": ["output_type", "metadata", "name", "text"],
254 "properties": {
254 "properties": {
255 "output_type": {
255 "output_type": {
256 "description": "Type of cell output.",
256 "description": "Type of cell output.",
257 "enum": ["stream"]
257 "enum": ["stream"]
258 },
258 },
259 "metadata": {"$ref": "#/definitions/misc/output_metadata"},
259 "metadata": {"$ref": "#/definitions/misc/output_metadata"},
260 "name": {
260 "name": {
261 "description": "The name of the stream (stdout, stderr).",
261 "description": "The name of the stream (stdout, stderr).",
262 "type": "string"
262 "type": "string"
263 },
263 },
264 "text": {
264 "text": {
265 "description": "The stream's text output, represented as an array of strings.",
265 "description": "The stream's text output, represented as an array of strings.",
266 "$ref": "#/definitions/misc/multiline_string"
266 "$ref": "#/definitions/misc/multiline_string"
267 }
267 }
268 }
268 }
269 },
269 },
270
270
271 "error": {
271 "error": {
272 "description": "Output of an error that occurred during code cell execution.",
272 "description": "Output of an error that occurred during code cell execution.",
273 "type": "object",
273 "type": "object",
274 "additionalProperties": false,
274 "additionalProperties": false,
275 "required": ["output_type", "metadata", "ename", "evalue", "traceback"],
275 "required": ["output_type", "metadata", "ename", "evalue", "traceback"],
276 "properties": {
276 "properties": {
277 "output_type": {
277 "output_type": {
278 "description": "Type of cell output.",
278 "description": "Type of cell output.",
279 "enum": ["error"]
279 "enum": ["error"]
280 },
280 },
281 "metadata": {"$ref": "#/definitions/misc/output_metadata"},
281 "metadata": {"$ref": "#/definitions/misc/output_metadata"},
282 "ename": {
282 "ename": {
283 "description": "The name of the error.",
283 "description": "The name of the error.",
284 "type": "string"
284 "type": "string"
285 },
285 },
286 "evalue": {
286 "evalue": {
287 "description": "The value, or message, of the error.",
287 "description": "The value, or message, of the error.",
288 "type": "string"
288 "type": "string"
289 },
289 },
290 "traceback": {
290 "traceback": {
291 "description": "The error's traceback, represented as an array of strings.",
291 "description": "The error's traceback, represented as an array of strings.",
292 "type": "array",
292 "type": "array",
293 "items": {"type": "string"}
293 "items": {"type": "string"}
294 }
294 }
295 }
295 }
296 },
296 },
297
297
298 "misc": {
298 "misc": {
299 "metadata_name": {
299 "metadata_name": {
300 "description": "The cell's name. If present, must be a non-empty string.",
300 "description": "The cell's name. If present, must be a non-empty string.",
301 "type": "string",
301 "type": "string",
302 "pattern": "^.+$"
302 "pattern": "^.+$"
303 },
303 },
304 "metadata_tags": {
304 "metadata_tags": {
305 "description": "The cell's tags. Tags must be unique, and must not contain commas.",
305 "description": "The cell's tags. Tags must be unique, and must not contain commas.",
306 "type": "array",
306 "type": "array",
307 "uniqueItems": true,
307 "uniqueItems": true,
308 "items": {
308 "items": {
309 "type": "string",
309 "type": "string",
310 "pattern": "^[^,]+$"
310 "pattern": "^[^,]+$"
311 }
311 }
312 },
312 },
313 "source": {
313 "source": {
314 "description": "Contents of the cell, represented as an array of lines.",
314 "description": "Contents of the cell, represented as an array of lines.",
315 "$ref": "#/definitions/misc/multiline_string"
315 "$ref": "#/definitions/misc/multiline_string"
316 },
316 },
317 "prompt_number": {
317 "execution_count": {
318 "description": "The code cell's prompt number. Will be null if the cell has not been run.",
318 "description": "The code cell's prompt number. Will be null if the cell has not been run.",
319 "type": ["integer", "null"],
319 "type": ["integer", "null"],
320 "minimum": 0
320 "minimum": 0
321 },
321 },
322 "mimetype": {
322 "mimetype": {
323 "patternProperties": {
323 "patternProperties": {
324 "^[a-zA-Z0-9\\-\\+]+/[a-zA-Z0-9\\-\\+]+": {
324 "^[a-zA-Z0-9\\-\\+]+/[a-zA-Z0-9\\-\\+]+": {
325 "description": "The cell's mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
325 "description": "The cell's mimetype output (e.g. text/plain), represented as either an array of strings or a string.",
326 "$ref": "#/definitions/misc/multiline_string"
326 "$ref": "#/definitions/misc/multiline_string"
327 }
327 }
328 }
328 }
329 },
329 },
330 "output_metadata": {
330 "output_metadata": {
331 "description": "Cell output metadata.",
331 "description": "Cell output metadata.",
332 "type": "object",
332 "type": "object",
333 "additionalProperties": true
333 "additionalProperties": true
334 },
334 },
335 "multiline_string": {
335 "multiline_string": {
336 "oneOf" : [
336 "oneOf" : [
337 {"type": "string"},
337 {"type": "string"},
338 {
338 {
339 "type": "array",
339 "type": "array",
340 "items": {"type": "string"}
340 "items": {"type": "string"}
341 }
341 }
342 ]
342 ]
343 }
343 }
344 }
344 }
345 }
345 }
346 }
346 }
@@ -1,105 +1,105 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 import os
3 import os
4 from base64 import encodestring
4 from base64 import encodestring
5
5
6 from ..nbbase import (
6 from ..nbbase import (
7 new_code_cell, new_heading_cell, new_markdown_cell, new_notebook,
7 new_code_cell, new_heading_cell, new_markdown_cell, new_notebook,
8 new_output, new_raw_cell
8 new_output, new_raw_cell
9 )
9 )
10
10
11 # some random base64-encoded *text*
11 # some random base64-encoded *text*
12 png = encodestring(os.urandom(5)).decode('ascii')
12 png = encodestring(os.urandom(5)).decode('ascii')
13 jpeg = encodestring(os.urandom(6)).decode('ascii')
13 jpeg = encodestring(os.urandom(6)).decode('ascii')
14
14
15 cells = []
15 cells = []
16 cells.append(new_markdown_cell(
16 cells.append(new_markdown_cell(
17 source='Some NumPy Examples',
17 source='Some NumPy Examples',
18 ))
18 ))
19
19
20
20
21 cells.append(new_code_cell(
21 cells.append(new_code_cell(
22 source='import numpy',
22 source='import numpy',
23 prompt_number=1,
23 execution_count=1,
24 ))
24 ))
25
25
26 cells.append(new_markdown_cell(
26 cells.append(new_markdown_cell(
27 source='A random array',
27 source='A random array',
28 ))
28 ))
29
29
30 cells.append(new_raw_cell(
30 cells.append(new_raw_cell(
31 source='A random array',
31 source='A random array',
32 ))
32 ))
33
33
34 cells.append(new_heading_cell(
34 cells.append(new_heading_cell(
35 source=u'My Heading',
35 source=u'My Heading',
36 level=2,
36 level=2,
37 ))
37 ))
38
38
39 cells.append(new_code_cell(
39 cells.append(new_code_cell(
40 source='a = numpy.random.rand(100)',
40 source='a = numpy.random.rand(100)',
41 prompt_number=2,
41 execution_count=2,
42 ))
42 ))
43 cells.append(new_code_cell(
43 cells.append(new_code_cell(
44 source='a = 10\nb = 5\n',
44 source='a = 10\nb = 5\n',
45 prompt_number=3,
45 execution_count=3,
46 ))
46 ))
47 cells.append(new_code_cell(
47 cells.append(new_code_cell(
48 source='a = 10\nb = 5',
48 source='a = 10\nb = 5',
49 prompt_number=4,
49 execution_count=4,
50 ))
50 ))
51
51
52 cells.append(new_code_cell(
52 cells.append(new_code_cell(
53 source=u'print "ünîcødé"',
53 source=u'print "ünîcødé"',
54 prompt_number=3,
54 execution_count=3,
55 outputs=[new_output(
55 outputs=[new_output(
56 output_type=u'execute_result',
56 output_type=u'execute_result',
57 mime_bundle={
57 mime_bundle={
58 'text/plain': u'<array a>',
58 'text/plain': u'<array a>',
59 'text/html': u'The HTML rep',
59 'text/html': u'The HTML rep',
60 'text/latex': u'$a$',
60 'text/latex': u'$a$',
61 'image/png': png,
61 'image/png': png,
62 'image/jpeg': jpeg,
62 'image/jpeg': jpeg,
63 'image/svg+xml': u'<svg>',
63 'image/svg+xml': u'<svg>',
64 'application/json': {
64 'application/json': {
65 'key': 'value'
65 'key': 'value'
66 },
66 },
67 'application/javascript': u'var i=0;'
67 'application/javascript': u'var i=0;'
68 },
68 },
69 prompt_number=3
69 execution_count=3
70 ),new_output(
70 ),new_output(
71 output_type=u'display_data',
71 output_type=u'display_data',
72 mime_bundle={
72 mime_bundle={
73 'text/plain': u'<array a>',
73 'text/plain': u'<array a>',
74 'text/html': u'The HTML rep',
74 'text/html': u'The HTML rep',
75 'text/latex': u'$a$',
75 'text/latex': u'$a$',
76 'image/png': png,
76 'image/png': png,
77 'image/jpeg': jpeg,
77 'image/jpeg': jpeg,
78 'image/svg+xml': u'<svg>',
78 'image/svg+xml': u'<svg>',
79 'application/json': {
79 'application/json': {
80 'key': 'value'
80 'key': 'value'
81 },
81 },
82 'application/javascript': u'var i=0;'
82 'application/javascript': u'var i=0;'
83 },
83 },
84 ),new_output(
84 ),new_output(
85 output_type=u'error',
85 output_type=u'error',
86 ename=u'NameError',
86 ename=u'NameError',
87 evalue=u'NameError was here',
87 evalue=u'NameError was here',
88 traceback=[u'frame 0', u'frame 1', u'frame 2']
88 traceback=[u'frame 0', u'frame 1', u'frame 2']
89 ),new_output(
89 ),new_output(
90 output_type=u'stream',
90 output_type=u'stream',
91 text='foo\rbar\r\n'
91 text='foo\rbar\r\n'
92 ),new_output(
92 ),new_output(
93 output_type=u'stream',
93 output_type=u'stream',
94 name='stderr',
94 name='stderr',
95 text='\rfoo\rbar\n'
95 text='\rfoo\rbar\n'
96 )]
96 )]
97 ))
97 ))
98
98
99 nb0 = new_notebook(cells=cells,
99 nb0 = new_notebook(cells=cells,
100 metadata={
100 metadata={
101 'language': 'python',
101 'language': 'python',
102 }
102 }
103 )
103 )
104
104
105
105
@@ -1,112 +1,112 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for the Python API for composing notebook elements"""
2 """Tests for the Python API for composing notebook elements"""
3
3
4 import nose.tools as nt
4 import nose.tools as nt
5
5
6 from IPython.nbformat.validator import isvalid, validate, ValidationError
6 from IPython.nbformat.validator import isvalid, validate, ValidationError
7 from ..nbbase import (
7 from ..nbbase import (
8 NotebookNode, nbformat,
8 NotebookNode, nbformat,
9 new_code_cell, new_heading_cell, new_markdown_cell, new_notebook,
9 new_code_cell, new_heading_cell, new_markdown_cell, new_notebook,
10 new_output, new_raw_cell,
10 new_output, new_raw_cell,
11 )
11 )
12
12
13 def test_empty_notebook():
13 def test_empty_notebook():
14 nb = new_notebook()
14 nb = new_notebook()
15 nt.assert_equal(nb.cells, [])
15 nt.assert_equal(nb.cells, [])
16 nt.assert_equal(nb.metadata, NotebookNode())
16 nt.assert_equal(nb.metadata, NotebookNode())
17 nt.assert_equal(nb.nbformat, nbformat)
17 nt.assert_equal(nb.nbformat, nbformat)
18
18
19 def test_empty_markdown_cell():
19 def test_empty_markdown_cell():
20 cell = new_markdown_cell()
20 cell = new_markdown_cell()
21 nt.assert_equal(cell.cell_type, 'markdown')
21 nt.assert_equal(cell.cell_type, 'markdown')
22 nt.assert_equal(cell.source, '')
22 nt.assert_equal(cell.source, '')
23
23
24 def test_markdown_cell():
24 def test_markdown_cell():
25 cell = new_markdown_cell(u'* Søme markdown')
25 cell = new_markdown_cell(u'* Søme markdown')
26 nt.assert_equal(cell.source, u'* Søme markdown')
26 nt.assert_equal(cell.source, u'* Søme markdown')
27
27
28 def test_empty_raw_cell():
28 def test_empty_raw_cell():
29 cell = new_raw_cell()
29 cell = new_raw_cell()
30 nt.assert_equal(cell.cell_type, u'raw')
30 nt.assert_equal(cell.cell_type, u'raw')
31 nt.assert_equal(cell.source, '')
31 nt.assert_equal(cell.source, '')
32
32
33 def test_raw_cell():
33 def test_raw_cell():
34 cell = new_raw_cell('hi')
34 cell = new_raw_cell('hi')
35 nt.assert_equal(cell.source, u'hi')
35 nt.assert_equal(cell.source, u'hi')
36
36
37 def test_empty_heading_cell():
37 def test_empty_heading_cell():
38 cell = new_heading_cell()
38 cell = new_heading_cell()
39 nt.assert_equal(cell.cell_type, u'heading')
39 nt.assert_equal(cell.cell_type, u'heading')
40 nt.assert_equal(cell.source, '')
40 nt.assert_equal(cell.source, '')
41 nt.assert_equal(cell.level, 1)
41 nt.assert_equal(cell.level, 1)
42
42
43 def test_heading_cell():
43 def test_heading_cell():
44 cell = new_heading_cell(u'hi', level=2)
44 cell = new_heading_cell(u'hi', level=2)
45 nt.assert_equal(cell.source, u'hi')
45 nt.assert_equal(cell.source, u'hi')
46 nt.assert_equal(cell.level, 2)
46 nt.assert_equal(cell.level, 2)
47
47
48 def test_empty_code_cell():
48 def test_empty_code_cell():
49 cell = new_code_cell('hi')
49 cell = new_code_cell('hi')
50 nt.assert_equal(cell.cell_type, 'code')
50 nt.assert_equal(cell.cell_type, 'code')
51 nt.assert_equal(cell.source, u'hi')
51 nt.assert_equal(cell.source, u'hi')
52
52
53 def test_empty_display_data():
53 def test_empty_display_data():
54 output = new_output('display_data')
54 output = new_output('display_data')
55 nt.assert_equal(output.output_type, 'display_data')
55 nt.assert_equal(output.output_type, 'display_data')
56
56
57 def test_empty_stream():
57 def test_empty_stream():
58 output = new_output('stream')
58 output = new_output('stream')
59 nt.assert_equal(output.output_type, 'stream')
59 nt.assert_equal(output.output_type, 'stream')
60 nt.assert_equal(output.name, 'stdout')
60 nt.assert_equal(output.name, 'stdout')
61 nt.assert_equal(output.text, '')
61 nt.assert_equal(output.text, '')
62
62
63 def test_empty_execute_result():
63 def test_empty_execute_result():
64 output = new_output('execute_result', prompt_number=1)
64 output = new_output('execute_result', execution_count=1)
65 nt.assert_equal(output.output_type, 'execute_result')
65 nt.assert_equal(output.output_type, 'execute_result')
66
66
67 mimebundle = {
67 mimebundle = {
68 'text/plain': "some text",
68 'text/plain': "some text",
69 "application/json": {
69 "application/json": {
70 "key": "value"
70 "key": "value"
71 },
71 },
72 "image/svg+xml": 'ABCDEF',
72 "image/svg+xml": 'ABCDEF',
73 "application/octet-stream": 'ABC-123',
73 "application/octet-stream": 'ABC-123',
74 "application/vnd.foo+bar": "Some other stuff",
74 "application/vnd.foo+bar": "Some other stuff",
75 }
75 }
76
76
77 def test_display_data():
77 def test_display_data():
78 output = new_output('display_data', mimebundle)
78 output = new_output('display_data', mimebundle)
79 for key, expected in mimebundle.items():
79 for key, expected in mimebundle.items():
80 nt.assert_equal(output[key], expected)
80 nt.assert_equal(output[key], expected)
81
81
82 def test_execute_result():
82 def test_execute_result():
83 output = new_output('execute_result', mimebundle, prompt_number=10)
83 output = new_output('execute_result', mimebundle, execution_count=10)
84 nt.assert_equal(output.prompt_number, 10)
84 nt.assert_equal(output.execution_count, 10)
85 for key, expected in mimebundle.items():
85 for key, expected in mimebundle.items():
86 nt.assert_equal(output[key], expected)
86 nt.assert_equal(output[key], expected)
87
87
88 def test_error():
88 def test_error():
89 o = new_output(output_type=u'error', ename=u'NameError',
89 o = new_output(output_type=u'error', ename=u'NameError',
90 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
90 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
91 )
91 )
92 nt.assert_equal(o.output_type, u'error')
92 nt.assert_equal(o.output_type, u'error')
93 nt.assert_equal(o.ename, u'NameError')
93 nt.assert_equal(o.ename, u'NameError')
94 nt.assert_equal(o.evalue, u'Name not found')
94 nt.assert_equal(o.evalue, u'Name not found')
95 nt.assert_equal(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
95 nt.assert_equal(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
96
96
97 def test_code_cell_with_outputs():
97 def test_code_cell_with_outputs():
98 cell = new_code_cell(prompt_number=10, outputs=[
98 cell = new_code_cell(execution_count=10, outputs=[
99 new_output('display_data', mimebundle),
99 new_output('display_data', mimebundle),
100 new_output('stream', text='hello'),
100 new_output('stream', text='hello'),
101 new_output('execute_result', mimebundle, prompt_number=10),
101 new_output('execute_result', mimebundle, execution_count=10),
102 ])
102 ])
103 nt.assert_equal(cell.prompt_number, 10)
103 nt.assert_equal(cell.execution_count, 10)
104 nt.assert_equal(len(cell.outputs), 3)
104 nt.assert_equal(len(cell.outputs), 3)
105 er = cell.outputs[-1]
105 er = cell.outputs[-1]
106 nt.assert_equal(er.prompt_number, 10)
106 nt.assert_equal(er.execution_count, 10)
107 nt.assert_equal(er['output_type'], 'execute_result')
107 nt.assert_equal(er['output_type'], 'execute_result')
108
108
109 def test_stream():
109 def test_stream():
110 output = new_output('stream', name='stderr', text='hello there')
110 output = new_output('stream', name='stderr', text='hello there')
111 nt.assert_equal(output.name, 'stderr')
111 nt.assert_equal(output.name, 'stderr')
112 nt.assert_equal(output.text, 'hello there')
112 nt.assert_equal(output.text, 'hello there')
General Comments 0
You need to be logged in to leave comments. Login now