Show More
@@ -11,7 +11,7 b' import requests' | |||
|
11 | 11 | from IPython.html.utils import url_path_join |
|
12 | 12 | from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error |
|
13 | 13 | from IPython.nbformat.current import (new_notebook, write, |
|
14 |
new_ |
|
|
14 | new_markdown_cell, new_code_cell, | |
|
15 | 15 | new_output) |
|
16 | 16 | |
|
17 | 17 | from IPython.testing.decorators import onlyif_cmds_exist |
@@ -55,7 +55,7 b' class APITest(NotebookTestBase):' | |||
|
55 | 55 | |
|
56 | 56 | nb = new_notebook() |
|
57 | 57 | |
|
58 |
nb.cells.append(new_ |
|
|
58 | nb.cells.append(new_markdown_cell(u'Created by test Β³')) | |
|
59 | 59 | cc1 = new_code_cell(source=u'print(2*6)') |
|
60 | 60 | cc1.outputs.append(new_output(output_type="stream", text=u'12')) |
|
61 | 61 | cc1.outputs.append(new_output(output_type="execute_result", |
@@ -255,7 +255,7 b' class FileContentsManager(ContentsManager):' | |||
|
255 | 255 | try: |
|
256 | 256 | nb = current.read(f, u'json') |
|
257 | 257 | except Exception as e: |
|
258 |
raise web.HTTPError(400, u"Unreadable Notebook: %s % |
|
|
258 | raise web.HTTPError(400, u"Unreadable Notebook: %s %r" % (os_path, e)) | |
|
259 | 259 | self.mark_trusted_cells(nb, name, path) |
|
260 | 260 | model['content'] = nb |
|
261 | 261 | model['format'] = 'json' |
@@ -16,7 +16,7 b' from IPython.html.utils import url_path_join, url_escape' | |||
|
16 | 16 | from IPython.html.tests.launchnotebook import NotebookTestBase, assert_http_error |
|
17 | 17 | from IPython.nbformat import current |
|
18 | 18 | from IPython.nbformat.current import (new_notebook, write, read, |
|
19 |
new_ |
|
|
19 | new_markdown_cell, to_notebook_json) | |
|
20 | 20 | from IPython.nbformat import v2 |
|
21 | 21 | from IPython.utils import py3compat |
|
22 | 22 | from IPython.utils.data import uniq_stable |
@@ -415,7 +415,7 b' class APITest(NotebookTestBase):' | |||
|
415 | 415 | resp = self.api.read('a.ipynb', 'foo') |
|
416 | 416 | nbcontent = json.loads(resp.text)['content'] |
|
417 | 417 | nb = to_notebook_json(nbcontent) |
|
418 |
nb.cells.append(new_ |
|
|
418 | nb.cells.append(new_markdown_cell(u'Created by test Β³')) | |
|
419 | 419 | |
|
420 | 420 | nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb, 'type': 'notebook'} |
|
421 | 421 | resp = self.api.save('a.ipynb', path='foo', body=json.dumps(nbmodel)) |
@@ -452,7 +452,7 b' class APITest(NotebookTestBase):' | |||
|
452 | 452 | # Modify it |
|
453 | 453 | nbcontent = json.loads(resp.text)['content'] |
|
454 | 454 | nb = to_notebook_json(nbcontent) |
|
455 |
hcell = new_ |
|
|
455 | hcell = new_markdown_cell('Created by test') | |
|
456 | 456 | nb.cells.append(hcell) |
|
457 | 457 | # Save |
|
458 | 458 | nbmodel= {'name': 'a.ipynb', 'path':'foo', 'content': nb, 'type': 'notebook'} |
@@ -139,12 +139,6 b' define([' | |||
|
139 | 139 | .append($('<option/>').attr('value','code').text('Code')) |
|
140 | 140 | .append($('<option/>').attr('value','markdown').text('Markdown')) |
|
141 | 141 | .append($('<option/>').attr('value','raw').text('Raw NBConvert')) |
|
142 | .append($('<option/>').attr('value','heading1').text('Heading 1')) | |
|
143 | .append($('<option/>').attr('value','heading2').text('Heading 2')) | |
|
144 | .append($('<option/>').attr('value','heading3').text('Heading 3')) | |
|
145 | .append($('<option/>').attr('value','heading4').text('Heading 4')) | |
|
146 | .append($('<option/>').attr('value','heading5').text('Heading 5')) | |
|
147 | .append($('<option/>').attr('value','heading6').text('Heading 6')) | |
|
148 | 142 | ); |
|
149 | 143 | }; |
|
150 | 144 | |
@@ -190,24 +184,18 b' define([' | |||
|
190 | 184 | |
|
191 | 185 | this.element.find('#cell_type').change(function () { |
|
192 | 186 | var cell_type = $(this).val(); |
|
193 |
|
|
|
187 | switch (cell_type) { | |
|
188 | case 'code': | |
|
194 | 189 | that.notebook.to_code(); |
|
195 | } else if (cell_type === 'markdown') { | |
|
190 | break; | |
|
191 | case 'markdown': | |
|
196 | 192 | that.notebook.to_markdown(); |
|
197 | } else if (cell_type === 'raw') { | |
|
193 | break; | |
|
194 | case 'raw': | |
|
198 | 195 | that.notebook.to_raw(); |
|
199 | } else if (cell_type === 'heading1') { | |
|
200 | that.notebook.to_heading(undefined, 1); | |
|
201 | } else if (cell_type === 'heading2') { | |
|
202 | that.notebook.to_heading(undefined, 2); | |
|
203 | } else if (cell_type === 'heading3') { | |
|
204 | that.notebook.to_heading(undefined, 3); | |
|
205 | } else if (cell_type === 'heading4') { | |
|
206 | that.notebook.to_heading(undefined, 4); | |
|
207 | } else if (cell_type === 'heading5') { | |
|
208 | that.notebook.to_heading(undefined, 5); | |
|
209 | } else if (cell_type === 'heading6') { | |
|
210 | that.notebook.to_heading(undefined, 6); | |
|
196 | break; | |
|
197 | default: | |
|
198 | console.log("unrecognized cell type:", cell_type); | |
|
211 | 199 | } |
|
212 | 200 | }); |
|
213 | 201 | this.events.on('selected_cell_type_changed.Notebook', function (event, data) { |
@@ -824,7 +824,7 b' define([' | |||
|
824 | 824 | * Index will be brought back into the accessible range [0,n] |
|
825 | 825 | * |
|
826 | 826 | * @method insert_cell_at_index |
|
827 |
* @param [type] {string} in ['code','markdown', |
|
|
827 | * @param [type] {string} in ['code','markdown', 'raw'], defaults to 'code' | |
|
828 | 828 | * @param [index] {int} a valid index where to insert cell |
|
829 | 829 | * |
|
830 | 830 | * @return cell {cell|null} created cell or null |
@@ -860,15 +860,19 b' define([' | |||
|
860 | 860 | notebook: this, |
|
861 | 861 | tooltip: this.tooltip, |
|
862 | 862 | }; |
|
863 |
|
|
|
863 | switch(type) { | |
|
864 | case 'code': | |
|
864 | 865 | cell = new codecell.CodeCell(this.kernel, cell_options); |
|
865 | 866 | cell.set_input_prompt(); |
|
866 | } else if (type === 'markdown') { | |
|
867 | break; | |
|
868 | case 'markdown': | |
|
867 | 869 | cell = new textcell.MarkdownCell(cell_options); |
|
868 | } else if (type === 'raw') { | |
|
870 | break; | |
|
871 | case 'raw': | |
|
869 | 872 | cell = new textcell.RawCell(cell_options); |
|
870 | } else if (type === 'heading') { | |
|
871 | cell = new textcell.HeadingCell(cell_options); | |
|
873 | break; | |
|
874 | default: | |
|
875 | console.log("invalid cell type: ", type); | |
|
872 | 876 | } |
|
873 | 877 | |
|
874 | 878 | if(this._insert_element_at_index(cell.element,index)) { |
@@ -1090,10 +1094,10 b' define([' | |||
|
1090 | 1094 | if (this.is_valid_cell_index(i)) { |
|
1091 | 1095 | var source_cell = this.get_cell(i); |
|
1092 | 1096 | var target_cell = null; |
|
1093 |
if (source_cell instanceof textcell. |
|
|
1094 | source_cell.set_level(level); | |
|
1097 | if (source_cell instanceof textcell.MarkdownCell) { | |
|
1098 | source_cell.set_heading_level(level); | |
|
1095 | 1099 | } else { |
|
1096 |
target_cell = this.insert_cell_below(' |
|
|
1100 | target_cell = this.insert_cell_below('markdown',i); | |
|
1097 | 1101 | var text = source_cell.get_text(); |
|
1098 | 1102 | if (text === source_cell.placeholder) { |
|
1099 | 1103 | text = ''; |
@@ -1101,9 +1105,9 b' define([' | |||
|
1101 | 1105 | //metadata |
|
1102 | 1106 | target_cell.metadata = source_cell.metadata; |
|
1103 | 1107 | // We must show the editor before setting its contents |
|
1104 | target_cell.set_level(level); | |
|
1105 | 1108 | target_cell.unrender(); |
|
1106 | 1109 | target_cell.set_text(text); |
|
1110 | target_cell.set_heading_level(level); | |
|
1107 | 1111 | // make this value the starting point, so that we can only undo |
|
1108 | 1112 | // to this state, instead of a blank cell |
|
1109 | 1113 | target_cell.code_mirror.clearHistory(); |
@@ -1117,7 +1121,7 b' define([' | |||
|
1117 | 1121 | } |
|
1118 | 1122 | this.set_dirty(true); |
|
1119 | 1123 | this.events.trigger('selected_cell_type_changed.Notebook', |
|
1120 |
{'cell_type':' |
|
|
1124 | {'cell_type':'markdown',level:level} | |
|
1121 | 1125 | ); |
|
1122 | 1126 | } |
|
1123 | 1127 | }; |
@@ -1526,7 +1530,7 b' define([' | |||
|
1526 | 1530 | } |
|
1527 | 1531 | this.codemirror_mode = newmode; |
|
1528 | 1532 | codecell.CodeCell.options_default.cm_config.mode = newmode; |
|
1529 | modename = newmode.mode || newmode.name || newmode | |
|
1533 | modename = newmode.mode || newmode.name || newmode; | |
|
1530 | 1534 | |
|
1531 | 1535 | that = this; |
|
1532 | 1536 | utils.requireCodeMirrorMode(modename, function () { |
@@ -1539,7 +1543,7 b' define([' | |||
|
1539 | 1543 | cell.cm_config.mode = newmode; |
|
1540 | 1544 | } |
|
1541 | 1545 | }); |
|
1542 | }) | |
|
1546 | }); | |
|
1543 | 1547 | }; |
|
1544 | 1548 | |
|
1545 | 1549 | // Session related things |
@@ -2383,13 +2387,13 b' define([' | |||
|
2383 | 2387 | Notebook.prototype.load_notebook_error = function (xhr, status, error) { |
|
2384 | 2388 | this.events.trigger('notebook_load_failed.Notebook', [xhr, status, error]); |
|
2385 | 2389 | utils.log_ajax_error(xhr, status, error); |
|
2386 | var msg; | |
|
2390 | var msg = $("<div>"); | |
|
2387 | 2391 | if (xhr.status === 400) { |
|
2388 |
msg |
|
|
2392 | msg.text(utils.ajax_error_msg(xhr)); | |
|
2389 | 2393 | } else if (xhr.status === 500) { |
|
2390 |
msg |
|
|
2394 | msg.text("An unknown error occurred while loading this notebook. " + | |
|
2391 | 2395 | "This version can load notebook formats " + |
|
2392 | "v" + this.nbformat + " or earlier. See the server log for details."; | |
|
2396 | "v" + this.nbformat + " or earlier. See the server log for details."); | |
|
2393 | 2397 | } |
|
2394 | 2398 | dialog.modal({ |
|
2395 | 2399 | notebook: this, |
@@ -222,6 +222,26 b' define([' | |||
|
222 | 222 | |
|
223 | 223 | MarkdownCell.prototype = Object.create(TextCell.prototype); |
|
224 | 224 | |
|
225 | MarkdownCell.prototype.set_heading_level = function (level) { | |
|
226 | // make a markdown cell a heading | |
|
227 | level = level || 1; | |
|
228 | var source = this.get_text(); | |
|
229 | // \s\S appears to be the js version of multi-line dot-all | |
|
230 | var match = source.match(/(#*)\s*([\s\S]*)/); | |
|
231 | // strip the leading `#` if it's already there | |
|
232 | if (match) { | |
|
233 | source = match[2]; | |
|
234 | } | |
|
235 | // add `#` markdown heading prefix | |
|
236 | var new_text = new Array(level + 1).join('#') + ' ' + source; | |
|
237 | ||
|
238 | this.set_text(new_text); | |
|
239 | this.refresh(); | |
|
240 | if (this.rendered) { | |
|
241 | this.render(); | |
|
242 | } | |
|
243 | }; | |
|
244 | ||
|
225 | 245 | /** |
|
226 | 246 | * @method render |
|
227 | 247 | */ |
@@ -238,6 +258,19 b' define([' | |||
|
238 | 258 | html = mathjaxutils.replace_math(html, math); |
|
239 | 259 | html = security.sanitize_html(html); |
|
240 | 260 | html = $($.parseHTML(html)); |
|
261 | // add anchors to headings | |
|
262 | // console.log(html); | |
|
263 | html.find(":header").addBack(":header").each(function (i, h) { | |
|
264 | h = $(h); | |
|
265 | var hash = h.text().replace(/ /g, '-'); | |
|
266 | h.attr('id', hash); | |
|
267 | h.append( | |
|
268 | $('<a/>') | |
|
269 | .addClass('anchor-link') | |
|
270 | .attr('href', '#' + hash) | |
|
271 | .text('ΒΆ') | |
|
272 | ); | |
|
273 | }) | |
|
241 | 274 | // links in markdown cells should open in new tabs |
|
242 | 275 | html.find("a[href]").not('[href^="#"]').attr("target", "_blank"); |
|
243 | 276 | this.set_rendered(html); |
@@ -305,121 +338,15 b' define([' | |||
|
305 | 338 | return cont; |
|
306 | 339 | }; |
|
307 | 340 | |
|
308 | ||
|
309 | var HeadingCell = function (options) { | |
|
310 | // Constructor | |
|
311 | // | |
|
312 | // Parameters: | |
|
313 | // options: dictionary | |
|
314 | // Dictionary of keyword arguments. | |
|
315 | // events: $(Events) instance | |
|
316 | // config: dictionary | |
|
317 | // keyboard_manager: KeyboardManager instance | |
|
318 | // notebook: Notebook instance | |
|
319 | options = options || {}; | |
|
320 | var config = utils.mergeopt(HeadingCell, options.config); | |
|
321 | TextCell.apply(this, [$.extend({}, options, {config: config})]); | |
|
322 | ||
|
323 | this.level = 1; | |
|
324 | this.cell_type = 'heading'; | |
|
325 | }; | |
|
326 | ||
|
327 | HeadingCell.options_default = { | |
|
328 | cm_config: { | |
|
329 | theme: 'heading-1' | |
|
330 | }, | |
|
331 | placeholder: "Type Heading Here" | |
|
332 | }; | |
|
333 | ||
|
334 | HeadingCell.prototype = Object.create(TextCell.prototype); | |
|
335 | ||
|
336 | /** @method fromJSON */ | |
|
337 | HeadingCell.prototype.fromJSON = function (data) { | |
|
338 | if (data.level !== undefined){ | |
|
339 | this.level = data.level; | |
|
340 | } | |
|
341 | TextCell.prototype.fromJSON.apply(this, arguments); | |
|
342 | this.code_mirror.setOption("theme", "heading-"+this.level); | |
|
343 | }; | |
|
344 | ||
|
345 | ||
|
346 | /** @method toJSON */ | |
|
347 | HeadingCell.prototype.toJSON = function () { | |
|
348 | var data = TextCell.prototype.toJSON.apply(this); | |
|
349 | data.level = this.get_level(); | |
|
350 | return data; | |
|
351 | }; | |
|
352 | ||
|
353 | /** | |
|
354 | * Change heading level of cell, and re-render | |
|
355 | * @method set_level | |
|
356 | */ | |
|
357 | HeadingCell.prototype.set_level = function (level) { | |
|
358 | this.level = level; | |
|
359 | this.code_mirror.setOption("theme", "heading-"+level); | |
|
360 | ||
|
361 | if (this.rendered) { | |
|
362 | this.rendered = false; | |
|
363 | this.render(); | |
|
364 | } | |
|
365 | }; | |
|
366 | ||
|
367 | /** The depth of header cell, based on html (h1 to h6) | |
|
368 | * @method get_level | |
|
369 | * @return {integer} level - for 1 to 6 | |
|
370 | */ | |
|
371 | HeadingCell.prototype.get_level = function () { | |
|
372 | return this.level; | |
|
373 | }; | |
|
374 | ||
|
375 | ||
|
376 | HeadingCell.prototype.get_rendered = function () { | |
|
377 | var r = this.element.find("div.text_cell_render"); | |
|
378 | return r.children().first().html(); | |
|
379 | }; | |
|
380 | ||
|
381 | HeadingCell.prototype.render = function () { | |
|
382 | var cont = TextCell.prototype.render.apply(this); | |
|
383 | if (cont) { | |
|
384 | var text = this.get_text(); | |
|
385 | var math = null; | |
|
386 | // Markdown headings must be a single line | |
|
387 | text = text.replace(/\n/g, ' '); | |
|
388 | if (text === "") { text = this.placeholder; } | |
|
389 | text = new Array(this.level + 1).join("#") + " " + text; | |
|
390 | var text_and_math = mathjaxutils.remove_math(text); | |
|
391 | text = text_and_math[0]; | |
|
392 | math = text_and_math[1]; | |
|
393 | var html = marked.parser(marked.lexer(text)); | |
|
394 | html = mathjaxutils.replace_math(html, math); | |
|
395 | html = security.sanitize_html(html); | |
|
396 | var h = $($.parseHTML(html)); | |
|
397 | // add id and linkback anchor | |
|
398 | var hash = h.text().trim().replace(/ /g, '-'); | |
|
399 | h.attr('id', hash); | |
|
400 | h.append( | |
|
401 | $('<a/>') | |
|
402 | .addClass('anchor-link') | |
|
403 | .attr('href', '#' + hash) | |
|
404 | .text('ΒΆ') | |
|
405 | ); | |
|
406 | this.set_rendered(h); | |
|
407 | this.typeset(); | |
|
408 | } | |
|
409 | return cont; | |
|
410 | }; | |
|
411 | ||
|
412 | 341 | // Backwards compatability. |
|
413 | 342 | IPython.TextCell = TextCell; |
|
414 | 343 | IPython.MarkdownCell = MarkdownCell; |
|
415 | 344 | IPython.RawCell = RawCell; |
|
416 | IPython.HeadingCell = HeadingCell; | |
|
417 | 345 | |
|
418 | 346 | var textcell = { |
|
419 |
|
|
|
420 |
|
|
|
421 |
|
|
|
422 | 'HeadingCell': HeadingCell, | |
|
347 | TextCell: TextCell, | |
|
348 | MarkdownCell: MarkdownCell, | |
|
349 | RawCell: RawCell, | |
|
423 | 350 | }; |
|
424 | 351 | return textcell; |
|
425 | 352 | }); |
@@ -189,12 +189,6 b' class="notebook_app"' | |||
|
189 | 189 | <li id="to_raw" |
|
190 | 190 | title="Contents will pass through nbconvert unmodified"> |
|
191 | 191 | <a href="#">Raw NBConvert</a></li> |
|
192 | <li id="to_heading1"><a href="#">Heading 1</a></li> | |
|
193 | <li id="to_heading2"><a href="#">Heading 2</a></li> | |
|
194 | <li id="to_heading3"><a href="#">Heading 3</a></li> | |
|
195 | <li id="to_heading4"><a href="#">Heading 4</a></li> | |
|
196 | <li id="to_heading5"><a href="#">Heading 5</a></li> | |
|
197 | <li id="to_heading6"><a href="#">Heading 6</a></li> | |
|
198 | 192 | </ul> |
|
199 | 193 | </li> |
|
200 | 194 | <li class="divider"></li> |
@@ -52,12 +52,12 b' casper.notebook_test(function () {' | |||
|
52 | 52 | |
|
53 | 53 | this.then(function () { |
|
54 | 54 | this.select_cell(2); |
|
55 |
this.trigger_keydown(' |
|
|
56 |
this.test.assertEquals(this.get_cell(2).cell_type, ' |
|
|
55 | this.trigger_keydown('y'); // switch it to code for the next test | |
|
56 | this.test.assertEquals(this.get_cell(2).cell_type, 'code', 'test cell is code'); | |
|
57 | 57 | this.trigger_keydown('b'); // new cell below |
|
58 |
this.test.assertEquals(this.get_cell(3).cell_type, ' |
|
|
58 | this.test.assertEquals(this.get_cell(3).cell_type, 'code', 'b; inserts a code cell below code cell'); | |
|
59 | 59 | this.trigger_keydown('a'); // new cell above |
|
60 |
this.test.assertEquals(this.get_cell(3).cell_type, ' |
|
|
60 | this.test.assertEquals(this.get_cell(3).cell_type, 'code', 'a; inserts a code cell below code cell'); | |
|
61 | 61 | }); |
|
62 | 62 | |
|
63 | 63 | this.thenEvaluate(function() { |
@@ -4,25 +4,38 b'' | |||
|
4 | 4 | casper.notebook_test(function () { |
|
5 | 5 | this.then(function () { |
|
6 | 6 | // Cell mode change |
|
7 | this.select_cell(0); | |
|
7 | var index = 0; | |
|
8 | this.select_cell(index); | |
|
9 | var a = 'hello\nmulti\nline'; | |
|
10 | this.set_cell_text(index, a); | |
|
8 | 11 | this.trigger_keydown('esc','r'); |
|
9 |
this.test.assertEquals(this.get_cell( |
|
|
12 | this.test.assertEquals(this.get_cell(index).cell_type, 'raw', 'r; cell is raw'); | |
|
10 | 13 | this.trigger_keydown('1'); |
|
11 |
this.test.assertEquals(this.get_cell( |
|
|
12 |
this.test.assertEquals(this.get_cell( |
|
|
14 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '1; cell is markdown'); | |
|
15 | this.test.assertEquals(this.get_cell_text(index), '# ' + a, '1; markdown heading'); | |
|
13 | 16 | this.trigger_keydown('2'); |
|
14 |
this.test.assertEquals(this.get_cell( |
|
|
17 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '2; cell is markdown'); | |
|
18 | this.test.assertEquals(this.get_cell_text(index), '## ' + a, '2; markdown heading'); | |
|
15 | 19 | this.trigger_keydown('3'); |
|
16 |
this.test.assertEquals(this.get_cell( |
|
|
20 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '3; cell is markdown'); | |
|
21 | this.test.assertEquals(this.get_cell_text(index), '### ' + a, '3; markdown heading'); | |
|
17 | 22 | this.trigger_keydown('4'); |
|
18 |
this.test.assertEquals(this.get_cell( |
|
|
23 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '4; cell is markdown'); | |
|
24 | this.test.assertEquals(this.get_cell_text(index), '#### ' + a, '4; markdown heading'); | |
|
19 | 25 | this.trigger_keydown('5'); |
|
20 |
this.test.assertEquals(this.get_cell( |
|
|
26 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '5; cell is markdown'); | |
|
27 | this.test.assertEquals(this.get_cell_text(index), '##### ' + a, '5; markdown heading'); | |
|
21 | 28 | this.trigger_keydown('6'); |
|
22 |
this.test.assertEquals(this.get_cell( |
|
|
29 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '6; cell is markdown'); | |
|
30 | this.test.assertEquals(this.get_cell_text(index), '###### ' + a, '6; markdown heading'); | |
|
23 | 31 | this.trigger_keydown('m'); |
|
24 |
this.test.assertEquals(this.get_cell( |
|
|
32 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', 'm; cell is markdown'); | |
|
33 | this.test.assertEquals(this.get_cell_text(index), '###### ' + a, 'm; still markdown heading'); | |
|
25 | 34 | this.trigger_keydown('y'); |
|
26 |
this.test.assertEquals(this.get_cell( |
|
|
35 | this.test.assertEquals(this.get_cell(index).cell_type, 'code', 'y; cell is code'); | |
|
36 | this.test.assertEquals(this.get_cell_text(index), '###### ' + a, 'y; still has hashes'); | |
|
37 | this.trigger_keydown('1'); | |
|
38 | this.test.assertEquals(this.get_cell(index).cell_type, 'markdown', '1; cell is markdown'); | |
|
39 | this.test.assertEquals(this.get_cell_text(index), '# ' + a, '1; markdown heading'); | |
|
27 | 40 | }); |
|
28 | 41 | }); No newline at end of file |
@@ -10,38 +10,53 b' casper.notebook_test(function () {' | |||
|
10 | 10 | cell.render(); |
|
11 | 11 | return cell.get_rendered(); |
|
12 | 12 | }); |
|
13 |
this.test.assertEquals(output.trim(), '<h1 id=\" |
|
|
13 | this.test.assertEquals(output.trim(), '<h1 id=\"Foo\">Foo<a class=\"anchor-link\" href=\"#Foo\">ΒΆ</a></h1>', 'Markdown JS API works.'); | |
|
14 | 14 | |
|
15 | 15 | // Test menubar entries. |
|
16 | 16 | output = this.evaluate(function () { |
|
17 | 17 | $('#to_code').mouseenter().click(); |
|
18 | 18 | $('#to_markdown').mouseenter().click(); |
|
19 | 19 | var cell = IPython.notebook.get_selected_cell(); |
|
20 |
cell.set_text(' |
|
|
20 | cell.set_text('**Bar**'); | |
|
21 | 21 | $('#run_cell').mouseenter().click(); |
|
22 | 22 | return cell.get_rendered(); |
|
23 | 23 | }); |
|
24 |
this.test.assertEquals(output.trim(), '< |
|
|
24 | this.test.assertEquals(output.trim(), '<p><strong>Bar</strong></p>', 'Markdown menubar items work.'); | |
|
25 | 25 | |
|
26 | 26 | // Test toolbar buttons. |
|
27 | 27 | output = this.evaluate(function () { |
|
28 | 28 | $('#cell_type').val('code').change(); |
|
29 | 29 | $('#cell_type').val('markdown').change(); |
|
30 | 30 | var cell = IPython.notebook.get_selected_cell(); |
|
31 |
cell.set_text(' |
|
|
31 | cell.set_text('*Baz*'); | |
|
32 | 32 | $('#run_b').click(); |
|
33 | 33 | return cell.get_rendered(); |
|
34 | 34 | }); |
|
35 |
this.test.assertEquals(output.trim(), '< |
|
|
35 | this.test.assertEquals(output.trim(), '<p><em>Baz</em></p>', 'Markdown toolbar items work.'); | |
|
36 | 36 | |
|
37 | // Test JavaScript models. | |
|
38 | var output = this.evaluate(function () { | |
|
37 | // Test markdown headings | |
|
39 | 38 | |
|
39 | var text = 'multi\nline'; | |
|
40 | ||
|
41 | this.evaluate(function (text) { | |
|
40 | 42 | var cell = IPython.notebook.insert_cell_at_index('markdown', 0); |
|
41 |
cell.set_text( |
|
|
42 | cell.render(); | |
|
43 | return cell.get_rendered(); | |
|
44 | }); | |
|
45 | this.test.assertEquals(output.trim(), '<h1 id=\"qux\">Qux</h1>', 'Markdown JS API works.'); | |
|
43 | cell.set_text(text); | |
|
44 | }, {text: text}); | |
|
45 | ||
|
46 | var set_level = function (level) { | |
|
47 | return casper.evaluate(function (level) { | |
|
48 | var cell = IPython.notebook.get_cell(0); | |
|
49 | cell.set_heading_level(level); | |
|
50 | return cell.get_text(); | |
|
51 | }, {level: level}); | |
|
52 | }; | |
|
46 | 53 | |
|
54 | var level_text; | |
|
55 | var levels = [ 1, 2, 3, 4, 5, 6, 2, 1 ]; | |
|
56 | for (var idx=0; idx < levels.length; idx++) { | |
|
57 | var level = levels[idx]; | |
|
58 | level_text = set_level(level); | |
|
59 | hashes = new Array(level + 1).join('#'); | |
|
60 | this.test.assertEquals(level_text, hashes + ' ' + text, 'markdown set_heading_level ' + level); | |
|
61 | } | |
|
47 | 62 | }); |
@@ -1,11 +1,10 b'' | |||
|
1 | 1 | { |
|
2 | 2 | "cells": [ |
|
3 | 3 | { |
|
4 |
"cell_type": " |
|
|
5 | "level": 1, | |
|
4 | "cell_type": "markdown", | |
|
6 | 5 | "metadata": {}, |
|
7 | 6 | "source": [ |
|
8 | "NumPy and Matplotlib examples" | |
|
7 | "# NumPy and Matplotlib examples" | |
|
9 | 8 | ] |
|
10 | 9 | }, |
|
11 | 10 | { |
@@ -8,6 +8,7 b' import json' | |||
|
8 | 8 | from .base import ExportersTestsBase |
|
9 | 9 | from ..notebook import NotebookExporter |
|
10 | 10 | |
|
11 | from IPython.nbformat.current import validate | |
|
11 | 12 | from IPython.testing.tools import assert_big_text_equal |
|
12 | 13 | |
|
13 | 14 | class TestNotebookExporter(ExportersTestsBase): |
@@ -29,7 +30,7 b' class TestNotebookExporter(ExportersTestsBase):' | |||
|
29 | 30 | exporter = self.exporter_class(nbformat_version=3) |
|
30 | 31 | (output, resources) = exporter.from_filename(self._get_notebook()) |
|
31 | 32 | nb = json.loads(output) |
|
32 | self.assertEqual(nb['nbformat'], 3) | |
|
33 | validate(nb) | |
|
33 | 34 | |
|
34 | 35 | def test_downgrade_2(self): |
|
35 | 36 | exporter = self.exporter_class(nbformat_version=2) |
@@ -21,6 +21,7 b' from pygments.formatters import HtmlFormatter' | |||
|
21 | 21 | from pygments.util import ClassNotFound |
|
22 | 22 | |
|
23 | 23 | # IPython imports |
|
24 | from IPython.nbconvert.filters.strings import add_anchor | |
|
24 | 25 | from IPython.nbconvert.utils.pandoc import pandoc |
|
25 | 26 | from IPython.nbconvert.utils.exceptions import ConversionException |
|
26 | 27 | from IPython.utils.decorators import undoc |
@@ -146,6 +147,10 b' class IPythonRenderer(mistune.Renderer):' | |||
|
146 | 147 | formatter = HtmlFormatter() |
|
147 | 148 | return highlight(code, lexer, formatter) |
|
148 | 149 | |
|
150 | def header(self, text, level, raw=None): | |
|
151 | html = super(IPythonRenderer, self).header(text, level, raw=raw) | |
|
152 | return add_anchor(html) | |
|
153 | ||
|
149 | 154 | # Pass math through unaltered - mathjax does the rendering in the browser |
|
150 | 155 | def block_math(self, text): |
|
151 | 156 | return '$$%s$$' % text |
@@ -4,17 +4,9 b'' | |||
|
4 | 4 | Contains a collection of useful string manipulation filters for use in Jinja |
|
5 | 5 | templates. |
|
6 | 6 | """ |
|
7 | #----------------------------------------------------------------------------- | |
|
8 | # Copyright (c) 2013, the IPython Development Team. | |
|
9 | # | |
|
10 | # Distributed under the terms of the Modified BSD License. | |
|
11 | # | |
|
12 | # The full license is in the file COPYING.txt, distributed with this software. | |
|
13 | #----------------------------------------------------------------------------- | |
|
14 | 7 | |
|
15 | #----------------------------------------------------------------------------- | |
|
16 | # Imports | |
|
17 | #----------------------------------------------------------------------------- | |
|
8 | # Copyright (c) IPython Development Team. | |
|
9 | # Distributed under the terms of the Modified BSD License. | |
|
18 | 10 | |
|
19 | 11 | import os |
|
20 | 12 | import re |
@@ -28,9 +20,6 b' from xml.etree import ElementTree' | |||
|
28 | 20 | from IPython.core.interactiveshell import InteractiveShell |
|
29 | 21 | from IPython.utils import py3compat |
|
30 | 22 | |
|
31 | #----------------------------------------------------------------------------- | |
|
32 | # Functions | |
|
33 | #----------------------------------------------------------------------------- | |
|
34 | 23 | |
|
35 | 24 | __all__ = [ |
|
36 | 25 | 'wrap_text', |
@@ -88,9 +77,9 b' def html2text(element):' | |||
|
88 | 77 | |
|
89 | 78 | |
|
90 | 79 | def add_anchor(html): |
|
91 |
"""Add an anchor-link to an html header |
|
|
80 | """Add an anchor-link to an html header | |
|
92 | 81 | |
|
93 |
For use |
|
|
82 | For use on markdown headings | |
|
94 | 83 | """ |
|
95 | 84 | try: |
|
96 | 85 | h = ElementTree.fromstring(py3compat.cast_bytes_py2(html, encoding='utf-8')) |
@@ -1,3 +1,4 b'' | |||
|
1 | # coding: utf-8 | |
|
1 | 2 | """Tests for conversions from markdown to other formats""" |
|
2 | 3 | |
|
3 | 4 | # Copyright (c) IPython Development Team. |
@@ -26,7 +27,8 b' class TestMarkdown(TestsBase):' | |||
|
26 | 27 | '#test', |
|
27 | 28 | '##test', |
|
28 | 29 | 'test\n----', |
|
29 |
'test [link](https://google.com/)' |
|
|
30 | 'test [link](https://google.com/)', | |
|
31 | ] | |
|
30 | 32 | |
|
31 | 33 | tokens = [ |
|
32 | 34 | '*test', |
@@ -39,7 +41,8 b' class TestMarkdown(TestsBase):' | |||
|
39 | 41 | 'test', |
|
40 | 42 | 'test', |
|
41 | 43 | 'test', |
|
42 |
('test', 'https://google.com/') |
|
|
44 | ('test', 'https://google.com/'), | |
|
45 | ] | |
|
43 | 46 | |
|
44 | 47 | |
|
45 | 48 | @dec.onlyif_cmds_exist('pandoc') |
@@ -87,6 +90,17 b' class TestMarkdown(TestsBase):' | |||
|
87 | 90 | for index, test in enumerate(self.tests): |
|
88 | 91 | self._try_markdown(markdown2html, test, self.tokens[index]) |
|
89 | 92 | |
|
93 | def test_markdown2html_heading_anchors(self): | |
|
94 | for md, tokens in [ | |
|
95 | ('# test', | |
|
96 | ('<h1', '>test', 'id="test"', u'¶</a>', "anchor-link") | |
|
97 | ), | |
|
98 | ('###test head space', | |
|
99 | ('<h3', '>test head space', 'id="test-head-space"', u'¶</a>', "anchor-link") | |
|
100 | ) | |
|
101 | ]: | |
|
102 | self._try_markdown(markdown2html, md, tokens) | |
|
103 | ||
|
90 | 104 | def test_markdown2html_math(self): |
|
91 | 105 | # Mathematical expressions should be passed through unaltered |
|
92 | 106 | cases = [("\\begin{equation*}\n" |
@@ -79,17 +79,6 b' In [ ]:' | |||
|
79 | 79 | </div> |
|
80 | 80 | {%- endblock markdowncell %} |
|
81 | 81 | |
|
82 | {% block headingcell scoped %} | |
|
83 | <div class="cell border-box-sizing text_cell rendered"> | |
|
84 | {{ self.empty_in_prompt() }} | |
|
85 | <div class="inner_cell"> | |
|
86 | <div class="text_cell_render border-box-sizing rendered_html"> | |
|
87 | {{ ("#" * cell.level + cell.source) | replace('\n', ' ') | markdown2html | strip_files_prefix | add_anchor }} | |
|
88 | </div> | |
|
89 | </div> | |
|
90 | </div> | |
|
91 | {% endblock headingcell %} | |
|
92 | ||
|
93 | 82 | {% block unknowncell scoped %} |
|
94 | 83 | unknown type {{ cell.type }} |
|
95 | 84 | {% endblock unknowncell %} |
@@ -185,27 +185,6 b' This template does not define a docclass, the inheriting class must define this.' | |||
|
185 | 185 | ((*- endblock figure -*)) |
|
186 | 186 | ((*- endmacro *)) |
|
187 | 187 | |
|
188 | % Draw heading cell. Explicitly map different cell levels. | |
|
189 | ((* block headingcell scoped *)) | |
|
190 | ||
|
191 | ((* if cell.level == 1 -*)) | |
|
192 | ((* block h1 -*))\section((* endblock h1 -*)) | |
|
193 | ((* elif cell.level == 2 -*)) | |
|
194 | ((* block h2 -*))\subsection((* endblock h2 -*)) | |
|
195 | ((* elif cell.level == 3 -*)) | |
|
196 | ((* block h3 -*))\subsubsection((* endblock h3 -*)) | |
|
197 | ((* elif cell.level == 4 -*)) | |
|
198 | ((* block h4 -*))\paragraph((* endblock h4 -*)) | |
|
199 | ((* elif cell.level == 5 -*)) | |
|
200 | ((* block h5 -*))\subparagraph((* endblock h5 -*)) | |
|
201 | ((* elif cell.level == 6 -*)) | |
|
202 | ((* block h6 -*))\\*\textit((* endblock h6 -*)) | |
|
203 | ((*- endif -*)) | |
|
204 | {((( cell.source | replace('\n', ' ') | citation2latex | strip_files_prefix | prevent_list_blocks | markdown2latex(markup='markdown_strict+tex_math_dollars') )))} | |
|
205 | ||
|
206 | ||
|
207 | ((* endblock headingcell *)) | |
|
208 | ||
|
209 | 188 | % Redirect execute_result to display data priority. |
|
210 | 189 | ((* block execute_result scoped *)) |
|
211 | 190 | ((* block data_priority scoped *)) |
@@ -75,9 +75,6 b' consider calling super even if it is a leave block, we might insert more blocks ' | |||
|
75 | 75 | ((*- elif cell.cell_type in ['markdown'] -*)) |
|
76 | 76 | ((*- block markdowncell scoped-*)) |
|
77 | 77 | ((*- endblock markdowncell -*)) |
|
78 | ((*- elif cell.cell_type in ['heading'] -*)) | |
|
79 | ((*- block headingcell scoped-*)) | |
|
80 | ((*- endblock headingcell -*)) | |
|
81 | 78 | ((*- elif cell.cell_type in ['raw'] -*)) |
|
82 | 79 | ((*- block rawcell scoped -*)) |
|
83 | 80 | ((* if cell.metadata.get('raw_mimetype', '').lower() in resources.get('raw_mimetypes', ['']) *)) |
@@ -58,11 +58,6 b'' | |||
|
58 | 58 | {{ cell.source }} |
|
59 | 59 | {% endblock markdowncell %} |
|
60 | 60 | |
|
61 | ||
|
62 | {% block headingcell scoped %} | |
|
63 | {{ '#' * cell.level }} {{ cell.source | replace('\n', ' ') }} | |
|
64 | {% endblock headingcell %} | |
|
65 | ||
|
66 | 61 | {% block unknowncell scoped %} |
|
67 | 62 | unknown type {{ cell.type }} |
|
68 | 63 | {% endblock unknowncell %} No newline at end of file |
@@ -15,7 +15,3 b'' | |||
|
15 | 15 | {% block markdowncell scoped %} |
|
16 | 16 | {{ cell.source | comment_lines }} |
|
17 | 17 | {% endblock markdowncell %} |
|
18 | ||
|
19 | {% block headingcell scoped %} | |
|
20 | {{ '#' * cell.level }}{{ cell.source | replace('\n', ' ') | comment_lines }} | |
|
21 | {% endblock headingcell %} |
@@ -71,9 +71,6 b' consider calling super even if it is a leave block, we might insert more blocks ' | |||
|
71 | 71 | {%- elif cell.cell_type in ['markdown'] -%} |
|
72 | 72 | {%- block markdowncell scoped-%} |
|
73 | 73 | {%- endblock markdowncell -%} |
|
74 | {%- elif cell.cell_type in ['heading'] -%} | |
|
75 | {%- block headingcell scoped-%} | |
|
76 | {%- endblock headingcell -%} | |
|
77 | 74 | {%- elif cell.cell_type in ['raw'] -%} |
|
78 | 75 | {%- block rawcell scoped -%} |
|
79 | 76 | {% if cell.metadata.get('raw_mimetype', '').lower() in resources.get('raw_mimetypes', ['']) %} |
@@ -1,11 +1,10 b'' | |||
|
1 | 1 | { |
|
2 | 2 | "cells": [ |
|
3 | 3 | { |
|
4 |
"cell_type": " |
|
|
5 | "level": 1, | |
|
4 | "cell_type": "markdown", | |
|
6 | 5 | "metadata": {}, |
|
7 | 6 | "source": [ |
|
8 | "A simple SymPy example" | |
|
7 | "# A simple SymPy example" | |
|
9 | 8 | ] |
|
10 | 9 | }, |
|
11 | 10 | { |
@@ -1,11 +1,10 b'' | |||
|
1 | 1 | { |
|
2 | 2 | "cells": [ |
|
3 | 3 | { |
|
4 |
"cell_type": " |
|
|
5 | "level": 1, | |
|
4 | "cell_type": "markdown", | |
|
6 | 5 | "metadata": {}, |
|
7 | 6 | "source": [ |
|
8 | "NumPy and Matplotlib examples" | |
|
7 | "# NumPy and Matplotlib examples" | |
|
9 | 8 | ] |
|
10 | 9 | }, |
|
11 | 10 | { |
@@ -157,11 +156,10 b'' | |||
|
157 | 156 | ] |
|
158 | 157 | }, |
|
159 | 158 | { |
|
160 |
"cell_type": " |
|
|
161 | "level": 2, | |
|
159 | "cell_type": "markdown", | |
|
162 | 160 | "metadata": {}, |
|
163 | 161 | "source": [ |
|
164 | "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" | |
|
162 | "## 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" | |
|
165 | 163 | ] |
|
166 | 164 | }, |
|
167 | 165 | { |
@@ -1,18 +1,8 b'' | |||
|
1 | 1 | { |
|
2 | "metadata": { | |
|
3 | "name": 0 | |
|
4 | }, | |
|
5 | "nbformat": 3, | |
|
6 | "nbformat_minor": 0, | |
|
7 | "worksheets": [ | |
|
8 | { | |
|
9 | 2 |
|
|
10 | 3 |
|
|
11 |
|
|
|
12 | "level": 1, | |
|
13 | "source": [ | |
|
14 | "nbconvert latex test" | |
|
15 | ] | |
|
4 | "cell_type": "markdown", | |
|
5 | "metadata": {} | |
|
16 | 6 |
|
|
17 | 7 |
|
|
18 | 8 |
|
@@ -31,115 +21,286 b'' | |||
|
31 | 21 |
|
|
32 | 22 |
|
|
33 | 23 |
|
|
34 | "collapsed": false, | |
|
35 | "input": [ | |
|
36 | "print(\"hello\")" | |
|
37 |
|
|
|
38 | "language": "python", | |
|
24 | "execution_count": 1, | |
|
25 | "metadata": { | |
|
26 | "collapsed": false | |
|
27 | }, | |
|
39 | 28 |
|
|
40 | 29 |
|
|
41 | "output_type": "stream", | |
|
42 | "stream": "stdout", | |
|
30 | "name": "stdout", | |
|
31 | "output_type": "bad stream", | |
|
43 | 32 |
|
|
44 | 33 |
|
|
45 | 34 |
|
|
46 | 35 |
|
|
47 | 36 |
|
|
48 | "prompt_number": 1 | |
|
37 | "source": [ | |
|
38 | "print(\"hello\")" | |
|
39 | ] | |
|
49 | 40 |
|
|
50 | 41 |
|
|
51 |
|
|
|
52 | "level": 1000, | |
|
42 | "cell_type": "markdown", | |
|
53 | 43 |
|
|
54 | 44 |
|
|
55 |
|
|
|
45 | "## Pyout" | |
|
56 | 46 |
|
|
57 | 47 |
|
|
58 | 48 |
|
|
59 | 49 |
|
|
60 | "collapsed": false, | |
|
61 | "input": [ | |
|
62 | "from IPython.display import HTML\n", | |
|
63 | "HTML(\"\"\"\n", | |
|
64 | "<script>\n", | |
|
65 | "console.log(\"hello\");\n", | |
|
66 | "</script>\n", | |
|
67 | "<b>HTML</b>\n", | |
|
68 | "\"\"\")" | |
|
69 | ], | |
|
70 | "language": "python", | |
|
71 | "metadata": {}, | |
|
50 | "execution_count": 3, | |
|
51 | "metadata": { | |
|
52 | "collapsed": false | |
|
53 | }, | |
|
72 | 54 |
|
|
73 | 55 |
|
|
74 |
|
|
|
56 | "data": { | |
|
57 | "text/html": [ | |
|
75 | 58 |
|
|
76 | 59 |
|
|
77 | 60 |
|
|
78 | 61 |
|
|
79 | 62 |
|
|
80 | 63 |
|
|
81 |
|
|
|
82 | "output_type": "pyout", | |
|
83 | "prompt_number": 3, | |
|
84 | "text": [ | |
|
64 | "text/plain": [ | |
|
85 | 65 |
|
|
86 | 66 |
|
|
67 | }, | |
|
68 | "execution_count": 3, | |
|
69 | "metadata": {}, | |
|
70 | "output_type": "execute_result" | |
|
87 | 71 |
|
|
88 | 72 |
|
|
89 | "prompt_number": 3 | |
|
73 | "source": [ | |
|
74 | "from IPython.display import HTML\n", | |
|
75 | "HTML(\"\"\"\n", | |
|
76 | "<script>\n", | |
|
77 | "console.log(\"hello\");\n", | |
|
78 | "</script>\n", | |
|
79 | "<b>HTML</b>\n", | |
|
80 | "\"\"\")" | |
|
81 | ] | |
|
90 | 82 |
|
|
91 | 83 |
|
|
92 | 84 |
|
|
93 | "collapsed": false, | |
|
94 | "input": [ | |
|
95 | "%%javascript\n", | |
|
96 | "console.log(\"hi\");" | |
|
97 | ], | |
|
98 | "language": "python", | |
|
99 | "metadata": {}, | |
|
85 | "execution_count": 7, | |
|
86 | "metadata": { | |
|
87 | "collapsed": false | |
|
88 | }, | |
|
100 | 89 |
|
|
101 | 90 |
|
|
102 |
|
|
|
91 | "data": { | |
|
92 | "application/javascript": [ | |
|
103 | 93 |
|
|
104 | 94 |
|
|
105 |
|
|
|
106 | "output_type": "display_data", | |
|
107 | "text": [ | |
|
95 | "text/plain": [ | |
|
108 | 96 |
|
|
109 | 97 |
|
|
98 | }, | |
|
99 | "metadata": {}, | |
|
100 | "output_type": "display_data" | |
|
110 | 101 |
|
|
111 | 102 |
|
|
112 | "prompt_number": 7 | |
|
103 | "source": [ | |
|
104 | "%%javascript\n", | |
|
105 | "console.log(\"hi\");" | |
|
106 | ] | |
|
113 | 107 |
|
|
114 | 108 |
|
|
115 |
|
|
|
116 | "level": 3, | |
|
117 | "metadata": {} | |
|
109 | "cell_type": "markdown", | |
|
110 | "metadata": {}, | |
|
111 | "source": [ | |
|
112 | "### Image" | |
|
113 | ] | |
|
118 | 114 |
|
|
119 | 115 |
|
|
120 | 116 |
|
|
121 | "collapsed": false, | |
|
122 | "input": [ | |
|
123 | "from IPython.display import Image\n", | |
|
124 | "Image(\"http://ipython.org/_static/IPy_header.png\")" | |
|
125 | ], | |
|
126 | "language": "python", | |
|
127 | "metadata": {}, | |
|
117 | "execution_count": 6, | |
|
118 | "metadata": { | |
|
119 | "collapsed": false | |
|
120 | }, | |
|
128 | 121 |
|
|
129 | 122 |
|
|
130 |
|
|
|
131 | "output_type": "pyout", | |
|
132 | "png": "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\n", | |
|
133 | "prompt_number": 6, | |
|
134 | "text": [ | |
|
123 | "data": { | |
|
124 | "image/png": [ | |
|
125 | "iVBORw0KGgoAAAANSUhEUgAAAggAAABDCAYAAAD5/P3lAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\n", | |
|
126 | "AAAH3AAAB9wBYvxo6AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURB\n", | |
|
127 | "VHic7Z15uBxF1bjfugkJhCWBsCSAJGACNg4QCI3RT1lEAVE+UEBNOmwCDcjHT1wQgU+WD3dFxA1o\n", | |
|
128 | "CAikAZFFVlnCjizpsCUjHQjBIAkQlpCFJGS79fvjdGf69vTsc2fuza33eeaZmeqq6jM9vZw6dc4p\n", | |
|
129 | "BUwC+tE+fqW1fqmRDpRSHjCggS40sBxYDCxKvL8KzNBaL21EPoPB0DPIWVY/4NlE0ffzYfhgu+Qx\n", | |
|
130 | "GHoy/YFjaK+CcB3QkIIAHAWs3wRZsuhUSs0CXgQeBm7UWi/spn0Z+jA5yxpEfYruqnwYllRic5a1\n", | |
|
131 | "MaWv8U5gaT4M19Sx396IAnZLfB/SLkEMhp5O/3YL0AvoAHaKXl8HLlZK3QZcpbWe0lbJDOsaHuDU\n", | |
|
132 | "0e4u4JAy2wPk/C1JzrKWArOQ0fUtwH35MOysQxaDwbCO0NFuAXoh6wPjgQeUUvcqpUa0WyCDoQls\n", | |
|
133 | "CIwBjgfuAV7KWdY+7RWpmJxlXZezrEdylvXxdstiMKzrGAtCYxwI/EspdZbW+g/tFsbQ67kQuBHY\n", | |
|
134 | "FNgseh9FV6vCbUAeWBC9PgBeq2EfS6J2MQOBrRDTe5KdgAdzlvW1fBjeUUP/3UbOsoYBE6OvG7VT\n", | |
|
135 | "FoOhL9Af+BUwFLkZpV+DaY6V4UPkRpb1+ncT+m8nGwK/V0oN01qf025hDL2XfBi+DLycLMtZVo6u\n", | |
|
136 | "CsKfGnSq8/NheEpqHwOBEcDBwJnAsGhTP2ByzrJG5cPwnQb22Sy+0G4BDIa+RH+t9dmlNiqlFKIk\n", | |
|
137 | "JJWGi+jq5JPmq8BbJJQArfXqpkncczlbKbVQa/3rdgtiMNRCPgxXAK8Ar+Qs63LgXmDvaPPGwPeA\n", | |
|
138 | "H7VJvCRfbLcABkNfouwUg9ZaAwuj178BlFLvVejzgR4WFviM1npcuQpKqf6IyXIjxLS7GzAWuUnu\n", | |
|
139 | "XsO+fqWUellr3ZBJdq/jr9+BDn1uve07O9Rz0y6f8PtGZGgWe53oT6SBkZ/q1/nHZy47aloTRTKU\n", | |
|
140 | "IR+Gy3OWNR6Zxtg0Kv4KRkEwGPocxgcBiCwcsSI0F5iOhF+ilPok8C3gVGS+thK/VErdrbWuO2ys\n", | |
|
141 | "s/+aLZTuOKbe9krrIUCPUBB0B+PQ1P1bdKe6EzAKQgvJh+GbOct6gkJkxM45y+qXDIWMHBhjBWJe\n", | |
|
142 | "PgyDWvaRs6zPIVObAG/nw/DpEvUGAp8E9gGGJzbtl7Os7cvs4skqp0V0Yl8jgcOBjyMDhbmIZeWl\n", | |
|
143 | "fBg+UUVfReQsayhwELAnsAXi6/E28BxwTz4MP6iyn92RaSCA+/NhuCwqXx9R4MYhU0MfRTK/AjyW\n", | |
|
144 | "D8MFGd0ZDFVhFIQKaK3/BXxfKXUlklTq0xWafAI4Driyu2UzGLqRlygoCArYHJif2H4gcFb0+Z2c\n", | |
|
145 | "ZW2bD8NV1XScs6yNgH8g/jsAPwCeTmzfFPgjYsnbiez71MUVdnMQcF8V4nyUs6whwB8QX4+0s2Ys\n", | |
|
146 | "0yPAt/NhGFbRZ/wbzgO+DaxXotqqnGX9GbigCkXhf5CBCsDngYdzljURGQhsWqLN+znL+iFwdT4M\n", | |
|
147 | "dYk6BkNJTJhjlWitQ2Bf4P4qqv848t8wGHor6Yd9+ruHJFkC2BI4rIa+D6egHKwmstYlGAxMQCwH\n", | |
|
148 | "rRjEPI5ER5S7ZvcFXsxZ1phKneUsawSi8HyH0soB0bbvAM9Ebaplt5xlnYkct1LKAYiFZhJwSQ19\n", | |
|
149 | "GwxrMRaEGtBar1RKfRX4JxIzXortou3PN1mE+YgJsSwaeoLHOQCqUy3QSr9eqZ6G/gq2aYVMhqrY\n", | |
|
150 | "OfF5FeJwvJZ8GM7JWdY/gC9HRS7wtyr7Pjrx+e6MqYC3KLbU7Qhck/h+FJIKvRRVjfSREXicU8EH\n", | |
|
151 | "pgAvIIqLBZwGfC7avl5Uf29KkLOsTZCMq8npj9sQx89no37HIlaAODplNPBIzrJ2z4dhNVlaT0HC\n", | |
|
152 | "XwFmIkrAC4if2PaIz8/3KCgn385Z1pX5MJxeRd8Gw1qMglAjWutlSqnTgUcqVP0SzVYQtP5mcMXE\n", | |
|
153 | "SvvtUUy9YsK5QEWHy7EnTB6lOtSsFohkqEDOsgYAdqJoagkT9Z8pKAj75yzr4/kwnF2h748ho/GY\n", | |
|
154 | "q9J1oqiKLj4JOctKK8Yz8mH4Yrl9VcnHkXVYTsyHoZ8WJWdZNyPThbF5/3M5yzowH4alpi9+T0E5\n", | |
|
155 | "WA18Nx+Gf0zVeRG4KmdZ90R9bwCMRKwyX69C5h2j91uA4/JhuCSxbTYwJWdZtwNPIFbifsAFSISZ\n", | |
|
156 | "wVA1ZoqhDrTWjyIjjXIc3ApZDIZu4ELgY4nvt5Wody8wJ/qsgBOr6HsihfvOfCRrY7v5dYZyAECk\n", | |
|
157 | "GP0ISEZmZYZ55yxrB8SyEXNxhnKQ7Pt64H8TRUfmLGuXKmWeC4xPKQfJvp9CLCJlZTYYymEUhPq5\n", | |
|
158 | "tcL2XVsihcHQJHKWtU3Osi5GnAZj5iKWgiKitRouTxQdl7OscnPu0HV64dp8GLY7R8pyxEGxJPkw\n", | |
|
159 | "fBcZ9ceUSvN8IoV76upK/UZcgawcG3NKqYopfleFU+gDic/b5SzLWIwNNWFOmPqp5CG9sVJqPa11\n", | |
|
160 | "VZ7dBkOL2D1nWcmcBkOR8MFtgM/QdTXJZcCR+TBcXqa/SYj5egAFZ8VMX4ScZe2FRPnEXF2z9M3n\n", | |
|
161 | "3nwYVsrtAmK6/0z0uVR4ZXLtivvzYfhGpU7zYbgkZ1k3ACdHRQdWIQsUO3ZmkUzB3Q/xjaolLbeh\n", | |
|
162 | "j2MUhDrRWr+mlFpJ+eV5hyIxz4YWs98Fj/Rf8uZbozo0/ZYt7D8rf9ORK9stUw/hU9GrEnMAp1R+\n", | |
|
163 | "gph8GL4bzdNPiIpOorSzYtJ68FS1IYPdTLWp3hcnPm+Q3pizrA7E+TCmFn+aZN0dcpY1LB+G5e4b\n", | |
|
164 | "y6rM8bA49X39GmQyGMwUQ4NUGnkMrbDd0A3sdeLk4z6cN+89pTtDTWd+gyErF+7pTv5eu+XqJbyK\n", | |
|
165 | "TDHsmg/DJ6tsc2ni8+dzljUqXSGaevhmoqjIObFNVBzlV8kQug4W5tbQNl13WGatAv+poW+DoW6M\n", | |
|
166 | "BaExPgC2LrO9nHWhpSilDqI4NPMhrfXUJvS9M/DfqeJXtdY3N9p3rex50uQ9lFKT6BrTvoFCXbTX\n", | |
|
167 | "yZNfmnrZxHtbLVMP4xng74nvK5DzeD7wfIWRayb5MHwiZ1kzgF0oOCuemar2ZQoK8zLgr7Xup5t4\n", | |
|
168 | "s0n9DEl9b0RBSPeV5q0a+jYY6sYoCI1RacnZ91siRXUMAH6eKnsYicdulDOAY1NlpzWh35pRqG9R\n", | |
|
169 | "IuGN7uw4AfG878s8nw/DX3RDv5dScGY8NmdZP86HYXJaJzm9cHMp7/s2UHdK9BTpKaxBNbRN163k\n", | |
|
170 | "t9Rux05DH8FMMTTGZhW2v9sSKarjbopNk/sqpUY30qlSahCSGS/JCuD6RvqtF6UpMm/HaHTJbYaG\n", | |
|
171 | "mQzED/0umRVzlrUZhXwJ0HOmF5pJOlXyxzJrZbNt6rtZP8HQIzAKQp0opTZAlsItxTKtdTnv75YS\n", | |
|
172 | "LR7lpYqrjV0vx2EUH4fbtdZtucnpMqOrDjPy6jYii8DkRFHSYnAEhem22cBjrZKrVeTDcCldTf/p\n", | |
|
173 | "h345ksrEGprnF2EwNIRREOrnMxW2z2uJFLVxJcXmy2OVUo34ShydUda+EaIq7T2u0SZTY/eSdFY8\n", | |
|
174 | "MGdZm0efk86J6/LCQUnFp5pIkZjkcvQz8mH4YZPkMRgawigI9VNp7v7BlkhRA1rr+RQneNqC2hba\n", | |
|
175 | "WYtSajiS9z3JXLomaGktq/VllLIUdKqSWe0MjZMPwxlIel8Q/6Zv5CxrGIX8AJ10XU+hFtIRQ+UW\n", | |
|
176 | "KWoXyYyTu+Qsa79KDXKWNRpJyx5zZ9OlMhjqxCgIdaCU6g98o0K1npBCNotLM8rcOvuagCRgSXKN\n", | |
|
177 | "1rozq3IrCCZNfFkrfRjotWsCaJinUBODK51/tkuuPkTy/DoYOIDCfeb+fBjW4t2/lqhdcmRdbUri\n", | |
|
178 | "VnILXS2HZ1WRvfAcCk61K4A/dYdgBkM9GAWhPr5F6XSrIBf6Qy2SpSaidSReShV/XilV7veUIj29\n", | |
|
179 | "oOkB2fGmXT7x7sCbOGpFf7VZx4A1m0/znG2nehMyc+0bms7NFJxzxwH7J7Y1OvWUPG9/mLOsLRvs\n", | |
|
180 | "r6lEaaOT0TtfBB5ITLWsJWdZg3KWdRNwTKL4wnwYzu9mMQ2GqjFhjjWilBqBpJYtx51a66UV6rST\n", | |
|
181 | "S+maJz52VvxRdvVilFK7UbzexGNa67Kr+bWS6X+ekPYs79HkLGt34JOI+Xyz6D2d1vfMnGUdini6\n", | |
|
182 | "L0C851/Oh2HD+SyaQT4MV+YsaxJyLm1Gwf9gAXBHg93/JNHHtsArOcuajCztPBDYCkkytBXg5sOw\n", | |
|
183 | "5QmF8mF4W86yLgK+HxXtC8zKWVaALMm8CslHsicS7RFzL8VhyAZDWzEKQg0opbYE7qd8prPVdF2h\n", | |
|
184 | "rSdyLfALYMNE2XFKqR/XsHbEURll62L4Wiv5PuBUqPPF6JXkLuCQbpGoPi4HfohYKGMHWD9axrlu\n", | |
|
185 | "8mF4Z7RuwfioaDBwaonqRemQW0U+DH+Qs6xFwHnIFNwQsv+3mMnA8dHiVwZDj8FMMVSJUuow4DkK\n", | |
|
186 | "a7GX4gqt9cstEKlutNaL6boULMho5tBq2iul+lH8IFuCmJcNfZx8GM6hOCFVU5THfBhOQHxfylkH\n", | |
|
187 | "3gY+asb+6iUfhhcCewC3l5BlFbJk/P75MDwqlVTKYOgRKK1rizhSSk2h67ximo1abV5XSi2n9EIk\n", | |
|
188 | "z2itx5XYVqnfQcjI7DiqW2XtfeCTUbRA3ex50nWfUrqjeJEcrfcLrpj4SCN9xyilxgDPp4of0Fof\n", | |
|
189 | "UEXbg4B/pIqv1FrXnVNh7AmTR3V0qIwwRH1E4E28pd5+De0hZ1m/Bb4bfX0+H4Z7dMM+hgGjkDwC\n", | |
|
190 | "S5FpjFk9bR4/Z1mDkGmF4VHR20g4Y3oxJYOhR9EXphg6lFLlVjFbH0mZvDGwCTAayCFe0ntTOZ1y\n", | |
|
191 | "zDLgkEaVg1ahtX5BKfUU8OlE8ReUUjtorSstCduzch8YehSR5/6ERFG3nBvRuhE9frXUfBguA6pd\n", | |
|
192 | "+Mpg6DH0BQXBBro7o+Ea4Bta66e6eT/N5lK6KggKOAE4u1QDpdTGFOdNmNkLf7uh+zgYcRQEMa+3\n", | |
|
193 | "Je22wWBoDOOD0DhLgYla67vaLUgd3ETxglLHRXkeSnEExQ5gbQ9tNPQokis5TsqHoVlbwGDohRgF\n", | |
|
194 | "oTECYHet9Y3tFqQetNYrKDb/DqN46eYk6emF1UhUhMFAzrImUEhDvgr4VRvFMRgMDWAUhPpYAvwf\n", | |
|
195 | "8Bmte31+/8uQBEdJMjMrKqW2o5A2N+YfWusePw9s6F5yltWRs6zxwKRE8RXtyEVgMBiaQ1/wQWgm\n", | |
|
196 | "eWTe/jqtdU9Zz74htNavKaXuAw5KFB+glBqptZ6Tqj6RQlrYGDO90AfJWdY5wNeQFQwHIAmetk5U\n", | |
|
197 | "eZFCsiCDwdALMQpCed5AphEC4NF12BHvUroqCAoJ7TwvVS+d++BdJEmPoe+xKRLnn0UeODwfhm3N\n", | |
|
198 | "RWAwGBqjLygIbwN/LbNdI1MGH6ReL/eWkMUmcDeSeGa7RNlRSqnzdZQoQym1C7Bzqt11NWReNKxb\n", | |
|
199 | "zEMU6GHAesBiYCaSLOviaF0Cg8HQi+kLCsLrWuvT2y1ET0ZrvUYp5SG57mO2Bz4LPB59/2ZRQ5P7\n", | |
|
200 | "oM+SD8OLgYvbLYfBYOg+jJOiIeZKxOs8STJiIb28daC1/lf3imQwGAyGdmEUBAMA0XTKraniI5VS\n", | |
|
201 | "A6O0zOnloI31wGAwGNZhjIJgSHJp6vtgJBNlehW65cANLZHIYDAYDG3BKAiGtWitHwVeShV/muLF\n", | |
|
202 | "uW7VWi9qjVQGg8FgaAd9wUnRUBuXAn9IfN8f+FyqTo/OfbDnSX8brDpXnqEUe2ropzQvdtDx66ev\n", | |
|
203 | "GN9XolIMPQDb9T8LrBd4zsPtlsXQe7Bd/0BgQeA5QbtlMQqCIc21wC+ADaPv6WWu5wAPtVKgWtjt\n", | |
|
204 | "6Os2XG/9jhdQjIzTQ2rFF9bQecy4E2/I9UQlwXb9LYDDK1R7K/Cc21shj6FxbNcfDjwGKNv1Rwae\n", | |
|
205 | "83q7ZWo2tusPBb6ELGW9BbAICX99Gngs8Jx0hlZDBWzXHwvcC6ywXX9o4DlL2ymPURAMXdBaL1ZK\n", | |
|
206 | "+ZRItwz8Jc6N0BMZMFB9GxiZsWnzTjrPAH7QWomqYgTF/h9pngC6RUGwXf+XwC2B50ztjv57M7br\n", | |
|
207 | "XwJMCjxneo1NP0SWgAfJq7LOYLv+esAFwOkUL9wWM912/d0Dz+lsnWQ9A9v1BwEXAT8PPKfWVOML\n", | |
|
208 | "kPVt3kNWQm0rxgfBkEWph5UG/tJCOWqnQ40ttUkrvWcrRamWwHOmAZsguSfGAi9Hmy5AUhgPAz7f\n", | |
|
209 | "Hfu2XX8k8ENgx+7ovzdju/4uwP9D/peaCDxnCbANsF3gOYubLVu7sF1/AHAHcBaiHDwI/C+ywNsE\n", | |
|
210 | "4KfA68BdfVE5iNgbOBmxqtRE4Dn/BoYDnwg8Z02zBasVY0EwFKG1fkEp9RTioJjkIa11zzaVarYq\n", | |
|
211 | "vVFt2TpBaiN6oCwB5tiu/2FUPCvwnLTTaLM5oJv77800dGwCz1kXHXkvRNKydwI/Cjzn1+kKtuuf\n", | |
|
212 | "i2TX7Ks0et681yxBGsUoCIZSBBQrCL0h98EbdW7rddiuPwoYFJu/bdffFNgL2BZ4DZgWKR5ZbRWS\n", | |
|
213 | "2+KIqGiE7fpjUtXmlrtZRdaHscBAYDowM/CckimWbdffFfgw8JzXou/9kfUccojV5MXAcz4s0XYw\n", | |
|
214 | "sCsymu8PzAVmBJ7zVqn9pdoPRVKF7wSsAN4EgqzRve36HcAoZDEqgO0zjs3rged8kGo3gOJ05ADT\n", | |
|
215 | "s0bTkan+k9HXGaVGjNFxykVf81nH2Hb9Ich/MRJJeT291H9fL7brj6CwANfPspQDgOi3rijRx/rI\n", | |
|
216 | "b8kB7wPPBZ4zL6Ne/JvfCDzn/WhufhvgvsBzVkR1dgN2AR4JPGduom38P7wXeM7c6FzfCfgU4iMR\n", | |
|
217 | "lFLebNfPIefXzMBzikz8tusPQyx676bljmTeCfhyVLST7frp//TV9Dluu/6GwOhUvTWB58zIkjFq\n", | |
|
218 | "sykyNfmfwHMW2K7fLzoWeyDTFPnAc14t1T7qYwNgT+Rc/wi5ZyT/N20UBEMRSqn+wNdTxQspTqTU\n", | |
|
219 | "41BaP6yVOipzGzzSYnG6m6uBz0YPv7OQm3dytc35tuuflHZutF3/BuArwEaJ4p/QNdU2wGnAH9M7\n", | |
|
220 | "jRSTG5CbS5LQdv2joymTLKYBzwHjbNc/DomW2TCxfbXt+sMCz3k/sa8RwM+Qh/X6qf5W2q4/CTit\n", | |
|
221 | "zMN1OPB7CopQktW2658YeM5fEvXvRKZzBiXqZaWUPha4JlW2NfB8Rt0hiANfmjWIuf5jiLPfvVm/\n", | |
|
222 | "AfmvbgNmB54zKrkheuD+Bjg11Wap7fpnBJ5TybelFk4E+iE+Fb+ptbHt+scg//nGqfJbgeMDz1mY\n", | |
|
223 | "KN4UOZYX2q7fSWHhuNdt198ZOBc4MypbbLv+5wPPeTb6PiJqe5ft+ichx3WXRN8rbdc/OfCcrGis\n", | |
|
224 | "R4ChiHKSlSn2f4BzkOvitMRvCKJ9DEzU9TPafwGZlkkyBvExSrKUrtdnmoOBycA5tus/iCyat3li\n", | |
|
225 | "u7Zd/0rk2ihS1mzXPwT4E3LulaLTKAiGLL6EaMlJbtBat91pphIjFw289t9DVh4N7Jva9EKnWnpJ\n", | |
|
226 | "G0RqBXcjCa08YCqy/PJE4L8A33b9HQPPeTNR/0bgvujzGchoywPSq5U+nd6R7fp7IDfRjYDrEE99\n", | |
|
227 | "DeyHrPb5lO364xI36zTb2q4/AUnt/SSyLHQHMvJZklQOIhYChyCLid2FWBoGIQrDfwGnAP8Gskzd\n", | |
|
228 | "VvSbBgPvIMdpJjLHuxdikXgg1ewa4Jbo84+BHRAFI/3gT9/QQZa+/iIy9zwccVQrSeA5nbbrX4s8\n", | |
|
229 | "cI6htIIQK7xdFJLIAvEEYjmYBlyP/E4LeXj92Xb94YHnnFtOjhrYJ3q/vtbpE9v1fwqcjYxUL0GO\n", | |
|
230 | "51bI//g1YIzt+mNTSgJIivfNEIXgBOThfx0ySv8Nct7vgzgfj0+1HQf8E5iPKM/vI+vLHA9cZbs+\n", | |
|
231 | "JZSEevgDBZ++3yIKzgVI1FeSrCnD6ci0zebAJxCfjmoZjxzXPPBL5By0gW8jCt3sqHwtkYL1N0RB\n", | |
|
232 | "/R2ymOG2yHE5CLFAHAu8ahQEQxbfyijrDdML3HTTkWvUBRfsb88bPb6TzjEK+oHKL184YHL+Jmdl\n", | |
|
233 | "u+XrJsYBhwaec0dcYLu+hzw0dkcu/AvjbUmLgu36DqIgPB54zuQq9nURMgI8LjnyBibZrj8z2s/l\n", | |
|
234 | "tuvvVcJJbWvkXDoi8JzbKu0s8JxFtut/IqXgAPzOdv0/IiPnb5KhICAjpMGIEjAhPV1iu35HWsbA\n", | |
|
235 | "c25ObD8ZURAeqibENBqpTYnark8FBSHiakRBOMx2/cHpB29kSv4KooSlLRYnIcrBHcBXk7/Fdv0b\n", | |
|
236 | "gReAM23Xvz7wnJlVyFIJK3qfXUsj2/U/jiiiq4B9ktEytuv/Fhlpfx2xEnw31XxHYLfAc6bbrv8k\n", | |
|
237 | "cny/Bnwz8Jy/2q6/DTLd9F8Zu94ceXAeEHhOvM7MNbbrT0UU4vNs15+c2FY3gedcm/hNP0EUhDvL\n", | |
|
238 | "KMrJtkuIFPboWNWiIOSAO4HDE7/Dj67FSxEn21+m2pyOWDpuCDxn7fG2Xf8e4F1EIVsceE5oohgM\n", | |
|
239 | "XVBKjURuSEke11qXMhv3OPR553VO9Sb407yJZwTexO8FnnNV/qYj11XlAOCfSeUA1s4D/y36mp7f\n", | |
|
240 | "rAvb9fdGLDMzU8pBzMXIg2wsMhLKQiFhgxWVg5gM5SDm+uh9VHqD7fr7IlaNFcAJWb4UPcHLPvCc\n", | |
|
241 | "2YgVZn3gyIwq30AsQg8lQ+aiefUfR1/PzlB08sD9Udusfmsi2t+Q6GutjspnIE6L16dDaSN/irMR\n", | |
|
242 | "p8dTbddPOxK/nwgxTZr8747e30SsEkNL7PvXGQrAVYgvwggK/gK9mXMyfuON0fvWkY9Dkp2i97uT\n", | |
|
243 | "hYHnLKNgURsDxknRUMz5FJ8XP22DHIbqSc9pxsSOW8ObtJ89ovdXbNcvpQC8j4zcdiTbnAoy4q2b\n", | |
|
244 | "6Ia3CYV5/Y0zqsXOf4/WEYveaq5GQuOOQaZekhydqJNkW2BLZF2UzhL/R+xE2XAIa+A52nb9lUho\n", | |
|
245 | "Y63hd7GD5d1ZGwPPmW27/iuIUrkLXc/n9xP13rZd/yNgVezoF8n1NjAyyyKETGGl97fGdv1/IlaL\n", | |
|
246 | "3h7e+06WM2PgOQtt11+GTMcNo6vVJ1aWsyK+4nvFQjAKgiGBUmoshfnOmGe11vdl1Tf0GOaUKI9v\n", | |
|
247 | "lqrE9lqJb6b/Hb3KsU2Zba/VslPb9bdDfA0ORLz0N62iWWxVqMkc3iZuRuawP2u7/g6JKI9RSCTR\n", | |
|
248 | "YoodhOP/YgNKK2Ix2zZJzjnINMN2NbaL/4uiaIUE/0EUhB3pqiCkMwl2IscjXZZFJ/B2iW1xRtWR\n", | |
|
249 | "ZWTqDcwps63U9f8Q0TSN7fp/iK0PtuvviPjmrCHyR1qrICilNkTmHjZDLsDke/JzOtwnzY1KqXcR\n", | |
|
250 | "R4cFiBab9XlRT87I19dQSo1GNPz0tJOxHvR8mhrOVobB0XuAOBiWo1zmwaqdXW3X3x+4BzGVv4SM\n", | |
|
251 | "pN9AnPEg21McxMIArTs2dRN4zoe26/8NOA6xGJwfbYqV9b8GnrM81Sz+Lz5A0qOXo2y4Ww3MoT4F\n", | |
|
252 | "IY4+KTfNF58TaXN4VthstVNDitLKcdxvOjKmEj0tv0M953fs87E3Eul0B2JliBflOzfwnFcA+iul\n", | |
|
253 | "5iEmwQFNEBaK569L0amUWggcqrXO8gg2FKHG2CdW4Uem9XvBlUflu7RUaiByU3lPa92ZKN8cSav8\n", | |
|
254 | "fUQBTHKr1rrqueIsxp18/eg1azrLjSYB6NfRsY3G6Is9nDjDYxh4zundvbMotvtm5N50duA5P09t\n", | |
|
255 | "T0faJIkfirU+zNrF1YiC4FBQECZE73/JqB//F+u14r+ImIVEOB1iu/6ZNfhwzEamp7YuU2e7RN1m\n", | |
|
256 | "oZBnW5YVIfZ1qNWfotw51yuIph++hET0bAkcikwpTAEuCjxnSly3PzIP0a8NcnYgD6SBlSoaIhQX\n", | |
|
257 | "V2UtVup24LBU6S7IyG+NUuodZP52awojrTSvIjeshlij9XdQKh2jXYRRDtpGfOCruQfEpmzbdn0V\n", | |
|
258 | "dP9iPLsgjnEryI67Lzd/PCt6/5Tt+v3LJXAqQ/z7ut2ZO/Ccx23XfxUYZbt+7D8xCngl8Jwsa80s\n", | |
|
259 | "ZBS8ke36O7cg4ybA5UgegJ0QE/XN5auvZRaiIMQRF12wXX8TCv9ls6eERpOtIMR+EXNS5YsRh8dS\n", | |
|
260 | "To/V+CzUck21i6uR5++4wHNeKFXJRDH0PfoR5fqmtHKwDDhCa73O5JA3lCSeF04v6Z3FPRTMzBO7\n", | |
|
261 | "S6AE8Q12PbomgYn5Xpm29yMPhu2RUK96iKMn9q6zfa38JXo/NHoly7oQeM5K4Iro60+jKINuJVJC\n", | |
|
262 | "Yu/439uuX805A4VkWyfbrp+V/MdFnOmeCmpfFKsSRYMc2/U/DeyG3OfSjpOx5WmfVHmcuXFcFfus\n", | |
|
263 | "5ZpqObbrb45EtswqpxyAcVI0FDMbOFxrXeT9a+heopvnEArzolvashT0wmbEapdgGpIU5XDb9R9F\n", | |
|
264 | "YqrXQyyL8wPPeTeuGHjOMtv1T0VuqldH6W//jigNmyHOcAcBgwPPcZog20xkRLcJ8DPb9S9CRqM7\n", | |
|
265 | "I7kDvoDE1hfdxwLPWWy7/plI7oCLbNffHXm4zUQeRtsjGRP/EXhOKSfcABkpj49i5+9G/putgHmB\n", | |
|
266 | "5yxIN4iSF21C14V6Rtiu/yYSW15uHv4a4P8oKAedlPcvOAv4KmItfCTKKfAS8v8NR1ILHwnsl5GA\n", | |
|
267 | "qF7ORdYaGA48HGWyfBqYgViDRwCfQR72PkDgOU9E2TvHI4m0TgeeRczb30DyH2iKcyA0ymrgWNv1\n", | |
|
268 | "FyDK1NvIQ3tStN3LCH+9HUl29UPb9echFo8BUbtLEKfJtJ9EmgA59ifbrj8bCR3cGDlvZqdTLcPa\n", | |
|
269 | "9NCbUMhs2GFLKvPFSAKxZl7/CxEL8pgoA+QMxD+kE3HenAHcHnjOGmNB6Dt8iGjHWSFKK4HHkcQr\n", | |
|
270 | "OxvloLXYrr+77fqrEIejNyiE6P0WccZbabv+lFLtG+Ry5AY/BHkYfRDtR9M79QAAA3FJREFUcwYS\n", | |
|
271 | "NdCFwHPuQR6a7wHfAR5GMhk+i9xcT6G6KIOKBJ6zFBn9r0GUmBlIWN9ziHf/5yjO/phsfy2yqt4i\n", | |
|
272 | "xOJxF3INTI9k/Q7ZoV4xv0PC5LZCci4sQm6g08kYHdquvxy5lt4DwsSmF5EENCts1//Idv3M9LbR\n", | |
|
273 | "egJTkEx4NvBA1joFifqLIjkeR6wcfwdeQfIFTEEcjHNU79RXkShvw95Ixs5+yOj/KuSh+ATiAHcq\n", | |
|
274 | "xb4fxwOXRfJMQc6zlxGF6B3g4MBznmmWnBFzEUfP0xDFcCGiAG+JHKushESXIdanjRBF4l3EInAj\n", | |
|
275 | "8vuOqWK/5yNRGaOQFNkfIhkOX6CQgwAA2/W3jkI3V0T7ejjatAFyXb2PXP/LbVnroWGi6bbzo697\n", | |
|
276 | "IlaWk5Br93wkk+jztusP7o94Lna7eaoMZU0cVXIAped7eqGZfP2ZqmPFl+ptrVf3n19UpvVMYLRS\n", | |
|
277 | "agBywxuEjLwWAe9qrTMXV2mUzs7OP/Xrp+6qt33Hmn5Zue3XNeZTOVoky5nqKiQkrNT883Qk3WvJ\n", | |
|
278 | "sMLAc1bbrv9Z5AH6KWRkOB+5wRWlWo7a3Ga7/mOIomAho/GFyI30YeDREru7ELlOq07TG3jONbbr\n", | |
|
279 | "T0Nu9KOQm+i/gFsDz3nTdv2fI2FbpdpfHnlpH4LcnHdAlIz5yLErqXgFnvOR7fo28lDYE7lu3kKO\n", | |
|
280 | "TdZ9K52xrhTl7knnUVB6SqVeTsr4apQU6lDEbG4hCsFbROsRBE1ebjrwnNB2/XGIGf5gRBkYhPyv\n", | |
|
281 | "7yDpjR9MtVkOnGK7/vWIgrFrVPcF4O8ZKbaXIuduWkH6KfL/JbkEsWClfWK2CDzHt10/jzhXjkGO\n", | |
|
282 | "yzNIZEiRD00ga3ocaLv+kUh2xo8hSuVURKmIUyiXVGYCWVzKQlJD7xrJNg85b9LX8RLgF6X6SpFU\n", | |
|
283 | "9Cpe28gaJgORqEEAbNffDLlvHIQoAndR8NEYilwjExD/nwuUiTQ0GAwGw7qC7fqjEUvKqsBzmhWd\n", | |
|
284 | "t05gu/5pyNoifw48J9N5PForxQeeNFMMBoPBYDD0DWL/llvK1In9jt4zCoLBYDAYDH2DePo5MwrJ\n", | |
|
285 | "dv0hFPwTnjBRDAaDwWAw9A3+hPgOHRPl25iK+FhsiuR4OARx0Lwf+J1REAwGg8Fg6AMEnvNklL78\n", | |
|
286 | "HMRRca/E5hVINNIVwI2B56z6/3ExLRI31pXNAAAAAElFTkSuQmCC\n" | |
|
287 | ], | |
|
288 | "text/plain": [ | |
|
135 | 289 |
|
|
136 | 290 |
|
|
291 | }, | |
|
292 | "execution_count": 6, | |
|
293 | "metadata": {}, | |
|
294 | "output_type": "execute_result" | |
|
137 | 295 |
|
|
138 | 296 |
|
|
139 | "prompt_number": 6 | |
|
297 | "source": [ | |
|
298 | "from IPython.display import Image\n", | |
|
299 | "Image(\"http://ipython.org/_static/IPy_header.png\")" | |
|
300 | ] | |
|
140 | 301 |
|
|
141 | 302 |
|
|
142 |
|
|
|
143 | } | |
|
144 | ] | |
|
303 | "metadata": {}, | |
|
304 | "nbformat": 4, | |
|
305 | "nbformat_minor": 0 | |
|
145 | 306 | } No newline at end of file |
@@ -1,11 +1,10 b'' | |||
|
1 | 1 | { |
|
2 | 2 | "cells": [ |
|
3 | 3 | { |
|
4 |
"cell_type": " |
|
|
5 | "level": 1, | |
|
4 | "cell_type": "markdown", | |
|
6 | 5 | "metadata": {}, |
|
7 | 6 | "source": [ |
|
8 | "nbconvert latex test" | |
|
7 | "# nbconvert latex test" | |
|
9 | 8 | ] |
|
10 | 9 | }, |
|
11 | 10 | { |
@@ -16,11 +15,10 b'' | |||
|
16 | 15 | ] |
|
17 | 16 | }, |
|
18 | 17 | { |
|
19 |
"cell_type": " |
|
|
20 | "level": 2, | |
|
18 | "cell_type": "markdown", | |
|
21 | 19 | "metadata": {}, |
|
22 | 20 | "source": [ |
|
23 | "Printed Using Python" | |
|
21 | "## Printed Using Python" | |
|
24 | 22 | ] |
|
25 | 23 | }, |
|
26 | 24 | { |
@@ -43,11 +41,10 b'' | |||
|
43 | 41 | ] |
|
44 | 42 | }, |
|
45 | 43 | { |
|
46 |
"cell_type": " |
|
|
47 | "level": 2, | |
|
44 | "cell_type": "markdown", | |
|
48 | 45 | "metadata": {}, |
|
49 | 46 | "source": [ |
|
50 | "Pyout" | |
|
47 | "## Pyout" | |
|
51 | 48 | ] |
|
52 | 49 | }, |
|
53 | 50 | { |
@@ -111,11 +108,10 b'' | |||
|
111 | 108 | ] |
|
112 | 109 | }, |
|
113 | 110 | { |
|
114 |
"cell_type": " |
|
|
115 | "level": 3, | |
|
111 | "cell_type": "markdown", | |
|
116 | 112 | "metadata": {}, |
|
117 | 113 | "source": [ |
|
118 | "Image" | |
|
114 | "### Image" | |
|
119 | 115 | ] |
|
120 | 116 | }, |
|
121 | 117 | { |
@@ -28,7 +28,7 b' class TestValidator(TestsBase):' | |||
|
28 | 28 | self.assertEqual(isvalid(nb), True) |
|
29 | 29 | |
|
30 | 30 | def test_nb4(self): |
|
31 |
"""Test that a v |
|
|
31 | """Test that a v4 notebook passes validation""" | |
|
32 | 32 | with self.fopen(u'test4.ipynb', u'r') as f: |
|
33 | 33 | nb = read(f, u'json') |
|
34 | 34 | validate(nb) |
@@ -37,9 +37,9 b' class TestValidator(TestsBase):' | |||
|
37 | 37 | def test_invalid(self): |
|
38 | 38 | """Test than an invalid notebook does not pass validation""" |
|
39 | 39 | # this notebook has a few different errors: |
|
40 | # - the name is an integer, rather than a string | |
|
41 | 40 | # - one cell is missing its source |
|
42 |
# - |
|
|
41 | # - invalid cell type | |
|
42 | # - invalid output_type | |
|
43 | 43 | with self.fopen(u'invalid.ipynb', u'r') as f: |
|
44 | 44 | nb = read(f, u'json') |
|
45 | 45 | with self.assertRaises(ValidationError): |
@@ -6,7 +6,7 b'' | |||
|
6 | 6 | from .nbbase import ( |
|
7 | 7 | NotebookNode, from_dict, |
|
8 | 8 | nbformat, nbformat_minor, nbformat_schema, |
|
9 |
new_code_cell |
|
|
9 | new_code_cell, new_markdown_cell, new_notebook, | |
|
10 | 10 | new_output, output_from_msg, |
|
11 | 11 | ) |
|
12 | 12 |
@@ -4,6 +4,7 b'' | |||
|
4 | 4 | # Distributed under the terms of the Modified BSD License. |
|
5 | 5 | |
|
6 | 6 | import json |
|
7 | import re | |
|
7 | 8 | |
|
8 | 9 | from .nbbase import ( |
|
9 | 10 | nbformat, nbformat_minor, |
@@ -72,6 +73,7 b' def upgrade(nb, from_version=3, from_minor=0):' | |||
|
72 | 73 | def upgrade_cell(cell): |
|
73 | 74 | """upgrade a cell from v3 to v4 |
|
74 | 75 | |
|
76 | heading cell -> markdown heading | |
|
75 | 77 | code cell: |
|
76 | 78 | - remove language metadata |
|
77 | 79 | - cell.input -> cell.source |
@@ -82,9 +84,16 b' def upgrade_cell(cell):' | |||
|
82 | 84 | if cell.cell_type == 'code': |
|
83 | 85 | cell.pop('language', '') |
|
84 | 86 | cell.metadata.collapsed = cell.pop('collapsed') |
|
85 | cell.source = cell.pop('input') | |
|
87 | cell.source = cell.pop('input', '') | |
|
86 | 88 | cell.execution_count = cell.pop('prompt_number', None) |
|
87 | 89 | cell.outputs = upgrade_outputs(cell.outputs) |
|
90 | elif cell.cell_type == 'heading': | |
|
91 | cell.cell_type = 'markdown' | |
|
92 | level = cell.pop('level', 1) | |
|
93 | cell.source = '{hashes} {single_line}'.format( | |
|
94 | hashes='#' * level, | |
|
95 | single_line = ' '.join(cell.get('source', '').splitlines()), | |
|
96 | ) | |
|
88 | 97 | elif cell.cell_type == 'html': |
|
89 | 98 | # Technically, this exists. It will never happen in practice. |
|
90 | 99 | cell.cell_type = 'markdown' |
@@ -98,6 +107,8 b' def downgrade_cell(cell):' | |||
|
98 | 107 | - cell.input <- cell.source |
|
99 | 108 | - cell.prompt_number <- cell.execution_count |
|
100 | 109 | - update outputs |
|
110 | markdown cell: | |
|
111 | - single-line heading -> heading cell | |
|
101 | 112 | """ |
|
102 | 113 | if cell.cell_type == 'code': |
|
103 | 114 | cell.language = 'python' |
@@ -105,6 +116,13 b' def downgrade_cell(cell):' | |||
|
105 | 116 | cell.prompt_number = cell.pop('execution_count', None) |
|
106 | 117 | cell.collapsed = cell.metadata.pop('collapsed', False) |
|
107 | 118 | cell.outputs = downgrade_outputs(cell.outputs) |
|
119 | elif cell.cell_type == 'markdown': | |
|
120 | source = cell.get('source', '') | |
|
121 | if '\n' not in source and source.startswith('#'): | |
|
122 | prefix, text = re.match(r'(#+)\s*(.*)', source).groups() | |
|
123 | cell.cell_type = 'heading' | |
|
124 | cell.source = text | |
|
125 | cell.level = len(prefix) | |
|
108 | 126 | return cell |
|
109 | 127 | |
|
110 | 128 | _mime_map = { |
@@ -121,16 +121,6 b" def new_markdown_cell(source='', **kwargs):" | |||
|
121 | 121 | validate(cell, 'markdown_cell') |
|
122 | 122 | return cell |
|
123 | 123 | |
|
124 | def new_heading_cell(source='', **kwargs): | |
|
125 | """Create a new heading cell""" | |
|
126 | cell = NotebookNode(cell_type='heading', source=source) | |
|
127 | cell.update(from_dict(kwargs)) | |
|
128 | cell.setdefault('metadata', NotebookNode()) | |
|
129 | cell.setdefault('level', 1) | |
|
130 | ||
|
131 | validate(cell, 'heading_cell') | |
|
132 | return cell | |
|
133 | ||
|
134 | 124 | def new_raw_cell(source='', **kwargs): |
|
135 | 125 | """Create a new raw cell""" |
|
136 | 126 | cell = NotebookNode(cell_type='raw', source=source) |
@@ -59,7 +59,6 b'' | |||
|
59 | 59 | "oneOf": [ |
|
60 | 60 | {"$ref": "#/definitions/raw_cell"}, |
|
61 | 61 | {"$ref": "#/definitions/markdown_cell"}, |
|
62 | {"$ref": "#/definitions/heading_cell"}, | |
|
63 | 62 | {"$ref": "#/definitions/code_cell"} |
|
64 | 63 | ] |
|
65 | 64 | } |
@@ -118,34 +117,6 b'' | |||
|
118 | 117 | } |
|
119 | 118 | }, |
|
120 | 119 | |
|
121 | "heading_cell": { | |
|
122 | "description": "Notebook heading cell.", | |
|
123 | "type": "object", | |
|
124 | "additionalProperties": false, | |
|
125 | "required": ["cell_type", "metadata", "source", "level"], | |
|
126 | "properties": { | |
|
127 | "cell_type": { | |
|
128 | "description": "String identifying the type of cell.", | |
|
129 | "enum": ["heading"] | |
|
130 | }, | |
|
131 | "metadata": { | |
|
132 | "description": "Cell-level metadata.", | |
|
133 | "type": "object", | |
|
134 | "properties": { | |
|
135 | "name": {"$ref": "#/definitions/misc/metadata_name"}, | |
|
136 | "tags": {"$ref": "#/definitions/misc/metadata_tags"} | |
|
137 | }, | |
|
138 | "additionalProperties": true | |
|
139 | }, | |
|
140 | "source": {"$ref": "#/definitions/misc/source"}, | |
|
141 | "level": { | |
|
142 | "description": "Level of heading cells.", | |
|
143 | "type": "integer", | |
|
144 | "minimum": 1 | |
|
145 | } | |
|
146 | } | |
|
147 | }, | |
|
148 | ||
|
149 | 120 | "code_cell": { |
|
150 | 121 | "description": "Notebook code cell.", |
|
151 | 122 | "type": "object", |
@@ -44,14 +44,15 b' def rejoin_lines(nb):' | |||
|
44 | 44 | for cell in nb.cells: |
|
45 | 45 | if 'source' in cell and isinstance(cell.source, list): |
|
46 | 46 | cell.source = _join_lines(cell.source) |
|
47 | if cell.cell_type == 'code': | |
|
48 | for output in cell.outputs: | |
|
49 | if output.output_type in {'execute_result', 'display_data'}: | |
|
50 | for key, value in output.data.items(): | |
|
47 | if cell.get('cell_type', None) == 'code': | |
|
48 | for output in cell.get('outputs', []): | |
|
49 | output_type = output.get('output_type', '') | |
|
50 | if output_type in {'execute_result', 'display_data'}: | |
|
51 | for key, value in output.get('data', {}).items(): | |
|
51 | 52 | if key != 'application/json' and isinstance(value, list): |
|
52 | 53 | output.data[key] = _join_lines(value) |
|
53 |
elif |
|
|
54 | if isinstance(output.text, list): | |
|
54 | elif output_type: | |
|
55 | if isinstance(output.get('text', ''), list): | |
|
55 | 56 | output.text = _join_lines(output.text) |
|
56 | 57 | return nb |
|
57 | 58 |
@@ -4,7 +4,7 b' import os' | |||
|
4 | 4 | from base64 import encodestring |
|
5 | 5 | |
|
6 | 6 | from ..nbbase import ( |
|
7 |
new_code_cell |
|
|
7 | new_code_cell, new_markdown_cell, new_notebook, | |
|
8 | 8 | new_output, new_raw_cell |
|
9 | 9 | ) |
|
10 | 10 | |
@@ -31,9 +31,8 b' cells.append(new_raw_cell(' | |||
|
31 | 31 | source='A random array', |
|
32 | 32 | )) |
|
33 | 33 | |
|
34 |
cells.append(new_ |
|
|
35 | source=u'My Heading', | |
|
36 | level=2, | |
|
34 | cells.append(new_markdown_cell( | |
|
35 | source=u'## My Heading', | |
|
37 | 36 | )) |
|
38 | 37 | |
|
39 | 38 | cells.append(new_code_cell( |
@@ -1,10 +1,13 b'' | |||
|
1 | 1 | import copy |
|
2 | 2 | |
|
3 | import nose.tools as nt | |
|
4 | ||
|
3 | 5 | from IPython.nbformat.current import validate |
|
4 | 6 | from .. import convert |
|
5 | 7 | |
|
6 | 8 | from . import nbexamples |
|
7 | 9 | from IPython.nbformat.v3.tests import nbexamples as v3examples |
|
10 | from IPython.nbformat import v3, v4 | |
|
8 | 11 | |
|
9 | 12 | def test_upgrade_notebook(): |
|
10 | 13 | nb03 = copy.deepcopy(v3examples.nb0) |
@@ -17,3 +20,48 b' def test_downgrade_notebook():' | |||
|
17 | 20 | validate(nb04) |
|
18 | 21 | nb03 = convert.downgrade(nb04) |
|
19 | 22 | validate(nb03) |
|
23 | ||
|
24 | def test_upgrade_heading(): | |
|
25 | v3h = v3.new_heading_cell | |
|
26 | v4m = v4.new_markdown_cell | |
|
27 | for v3cell, expected in [ | |
|
28 | ( | |
|
29 | v3h(source='foo', level=1), | |
|
30 | v4m(source='# foo'), | |
|
31 | ), | |
|
32 | ( | |
|
33 | v3h(source='foo\nbar\nmulti-line\n', level=4), | |
|
34 | v4m(source='#### foo bar multi-line'), | |
|
35 | ), | |
|
36 | ]: | |
|
37 | upgraded = convert.upgrade_cell(v3cell) | |
|
38 | nt.assert_equal(upgraded, expected) | |
|
39 | ||
|
40 | def test_downgrade_heading(): | |
|
41 | v3h = v3.new_heading_cell | |
|
42 | v4m = v4.new_markdown_cell | |
|
43 | v3m = lambda source: v3.new_text_cell('markdown', source) | |
|
44 | for v4cell, expected in [ | |
|
45 | ( | |
|
46 | v4m(source='# foo'), | |
|
47 | v3h(source='foo', level=1), | |
|
48 | ), | |
|
49 | ( | |
|
50 | v4m(source='#foo'), | |
|
51 | v3h(source='foo', level=1), | |
|
52 | ), | |
|
53 | ( | |
|
54 | v4m(source='#\tfoo'), | |
|
55 | v3h(source='foo', level=1), | |
|
56 | ), | |
|
57 | ( | |
|
58 | v4m(source='# \t foo'), | |
|
59 | v3h(source='foo', level=1), | |
|
60 | ), | |
|
61 | ( | |
|
62 | v4m(source='# foo\nbar'), | |
|
63 | v3m(source='# foo\nbar'), | |
|
64 | ), | |
|
65 | ]: | |
|
66 | downgraded = convert.downgrade_cell(v4cell) | |
|
67 | nt.assert_equal(downgraded, expected) |
@@ -6,7 +6,7 b' import nose.tools as nt' | |||
|
6 | 6 | from IPython.nbformat.validator import isvalid, validate, ValidationError |
|
7 | 7 | from ..nbbase import ( |
|
8 | 8 | NotebookNode, nbformat, |
|
9 |
new_code_cell |
|
|
9 | new_code_cell, new_markdown_cell, new_notebook, | |
|
10 | 10 | new_output, new_raw_cell, |
|
11 | 11 | ) |
|
12 | 12 | |
@@ -34,17 +34,6 b' def test_raw_cell():' | |||
|
34 | 34 | cell = new_raw_cell('hi') |
|
35 | 35 | nt.assert_equal(cell.source, u'hi') |
|
36 | 36 | |
|
37 | def test_empty_heading_cell(): | |
|
38 | cell = new_heading_cell() | |
|
39 | nt.assert_equal(cell.cell_type, u'heading') | |
|
40 | nt.assert_equal(cell.source, '') | |
|
41 | nt.assert_equal(cell.level, 1) | |
|
42 | ||
|
43 | def test_heading_cell(): | |
|
44 | cell = new_heading_cell(u'hi', level=2) | |
|
45 | nt.assert_equal(cell.source, u'hi') | |
|
46 | nt.assert_equal(cell.level, 2) | |
|
47 | ||
|
48 | 37 | def test_empty_code_cell(): |
|
49 | 38 | cell = new_code_cell('hi') |
|
50 | 39 | nt.assert_equal(cell.cell_type, 'code') |
@@ -12,7 +12,7 b' from IPython.nbformat.validator import validate, ValidationError' | |||
|
12 | 12 | from ..nbjson import reads |
|
13 | 13 | from ..nbbase import ( |
|
14 | 14 | nbformat, |
|
15 |
new_code_cell |
|
|
15 | new_code_cell, new_markdown_cell, new_notebook, | |
|
16 | 16 | new_output, new_raw_cell, |
|
17 | 17 | ) |
|
18 | 18 | |
@@ -73,31 +73,6 b' def test_invalid_markdown_cell():' | |||
|
73 | 73 | with nt.assert_raises(ValidationError): |
|
74 | 74 | validate4(cell, 'markdown_cell') |
|
75 | 75 | |
|
76 | def test_invalid_heading_cell(): | |
|
77 | cell = new_heading_cell() | |
|
78 | ||
|
79 | cell['source'] = 5 | |
|
80 | with nt.assert_raises(ValidationError): | |
|
81 | validate4(cell, 'heading_cell') | |
|
82 | ||
|
83 | cell = new_heading_cell() | |
|
84 | del cell['metadata'] | |
|
85 | ||
|
86 | with nt.assert_raises(ValidationError): | |
|
87 | validate4(cell, 'heading_cell') | |
|
88 | ||
|
89 | cell = new_heading_cell() | |
|
90 | del cell['source'] | |
|
91 | ||
|
92 | with nt.assert_raises(ValidationError): | |
|
93 | validate4(cell, 'heading_cell') | |
|
94 | ||
|
95 | cell = new_heading_cell() | |
|
96 | del cell['cell_type'] | |
|
97 | ||
|
98 | with nt.assert_raises(ValidationError): | |
|
99 | validate4(cell, 'heading_cell') | |
|
100 | ||
|
101 | 76 | def test_invalid_raw_cell(): |
|
102 | 77 | cell = new_raw_cell() |
|
103 | 78 |
@@ -82,24 +82,9 b' as defined in `GitHub-flavored markdown`_, and implemented in marked_.' | |||
|
82 | 82 | "source" : ["some *markdown*"], |
|
83 | 83 | } |
|
84 | 84 | |
|
85 | .. versionchanged:: 4.0 | |
|
85 | 86 | |
|
86 | Heading cells | |
|
87 | ------------- | |
|
88 | ||
|
89 | Heading cells are single lines describing a section header (mapping onto h1-h6 tags in HTML). | |
|
90 | These cells indicate structure of the document, | |
|
91 | and are used for things like outline-views and automatically generating HTML anchors | |
|
92 | within the page for quick navigation. | |
|
93 | They have a ``level`` field, with an integer value from 1-6 (inclusive). | |
|
94 | ||
|
95 | .. sourcecode:: python | |
|
96 | ||
|
97 | { | |
|
98 | "cell_type" : "markdown", | |
|
99 | "metadata" : {}, | |
|
100 | "level" : 1, # An integer on [1-6] | |
|
101 | "source" : ["A simple heading"], | |
|
102 | } | |
|
87 | Heading cells have been removed, in favor of simple headings in markdown. | |
|
103 | 88 | |
|
104 | 89 | |
|
105 | 90 | Code cells |
General Comments 0
You need to be logged in to leave comments.
Login now