##// END OF EJS Templates
Merge branch 'master' of github.com:ipython/ipython
Brian E. Granger -
r16053:50c0a9b1 merge
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,78 b''
1 // Test the notebook dual mode feature.
2
3 // Test
4 casper.notebook_test(function () {
5 var a = 'print("a")';
6 var index = this.append_cell(a);
7 this.execute_cell_then(index);
8
9 var b = 'print("b")';
10 index = this.append_cell(b);
11 this.execute_cell_then(index);
12
13 var c = 'print("c")';
14 index = this.append_cell(c);
15 this.execute_cell_then(index);
16
17 this.then(function () {
18 this.validate_notebook_state('initial state', 'edit', 0);
19 this.trigger_keydown('esc');
20 this.validate_notebook_state('esc', 'command', 0);
21 this.trigger_keydown('down');
22 this.validate_notebook_state('down', 'command', 1);
23 this.trigger_keydown('enter');
24 this.validate_notebook_state('enter', 'edit', 1);
25 this.trigger_keydown('j');
26 this.validate_notebook_state('j in edit mode', 'edit', 1);
27 this.trigger_keydown('esc');
28 this.validate_notebook_state('esc', 'command', 1);
29 this.trigger_keydown('j');
30 this.validate_notebook_state('j in command mode', 'command', 2);
31 this.click_cell_editor(0);
32 this.validate_notebook_state('click cell 0', 'edit', 0);
33 this.click_cell_editor(3);
34 this.validate_notebook_state('click cell 3', 'edit', 3);
35 this.trigger_keydown('esc');
36 this.validate_notebook_state('esc', 'command', 3);
37
38 // Open keyboard help
39 this.evaluate(function(){
40 $('#keyboard_shortcuts a').click();
41 }, {});
42
43 this.trigger_keydown('k');
44 this.validate_notebook_state('k in command mode while keyboard help is up', 'command', 3);
45
46 // Close keyboard help
47 this.evaluate(function(){
48 $('div.modal button.close').click();
49 }, {});
50
51 this.trigger_keydown('k');
52 this.validate_notebook_state('k in command mode', 'command', 2);
53 this.click_cell_editor(0);
54 this.validate_notebook_state('click cell 0', 'edit', 0);
55 this.focus_notebook();
56 this.validate_notebook_state('focus #notebook', 'command', 0);
57 this.click_cell_editor(0);
58 this.validate_notebook_state('click cell 0', 'edit', 0);
59 this.focus_notebook();
60 this.validate_notebook_state('focus #notebook', 'command', 0);
61 this.click_cell_editor(3);
62 this.validate_notebook_state('click cell 3', 'edit', 3);
63
64 // Cell deletion
65 this.trigger_keydown('esc', 'd', 'd');
66 this.test.assertEquals(this.get_cells_length(), 3, 'dd actually deletes a cell');
67 this.validate_notebook_state('dd', 'command', 2);
68
69 // Make sure that if the time between d presses is too long, nothing gets removed.
70 this.trigger_keydown('d');
71 });
72 this.wait(1000);
73 this.then(function () {
74 this.trigger_keydown('d');
75 this.test.assertEquals(this.get_cells_length(), 3, "d, 1 second wait, d doesn't delete a cell");
76 this.validate_notebook_state('d, 1 second wait, d', 'command', 2);
77 });
78 });
@@ -0,0 +1,51 b''
1
2 // Test
3 casper.notebook_test(function () {
4 var a = 'print("a")';
5 var index = this.append_cell(a);
6 this.execute_cell_then(index);
7
8 var b = 'print("b")';
9 index = this.append_cell(b);
10 this.execute_cell_then(index);
11
12 var c = 'print("c")';
13 index = this.append_cell(c);
14 this.execute_cell_then(index);
15
16 this.then(function () {
17
18 // Up and down in command mode
19 this.select_cell(3);
20 this.trigger_keydown('j');
21 this.validate_notebook_state('j at end of notebook', 'command', 3);
22 this.trigger_keydown('down');
23 this.validate_notebook_state('down at end of notebook', 'command', 3);
24 this.trigger_keydown('up');
25 this.validate_notebook_state('up', 'command', 2);
26 this.select_cell(0);
27 this.validate_notebook_state('select 0', 'command', 0);
28 this.trigger_keydown('k');
29 this.validate_notebook_state('k at top of notebook', 'command', 0);
30 this.trigger_keydown('up');
31 this.validate_notebook_state('up at top of notebook', 'command', 0);
32 this.trigger_keydown('down');
33 this.validate_notebook_state('down', 'command', 1);
34
35 // Up and down in edit mode
36 this.click_cell_editor(3);
37 this.validate_notebook_state('click cell 3', 'edit', 3);
38 this.trigger_keydown('down');
39 this.validate_notebook_state('down at end of notebook', 'edit', 3);
40 this.set_cell_editor_cursor(3, 0, 0);
41 this.trigger_keydown('up');
42 this.validate_notebook_state('up', 'edit', 2);
43 this.click_cell_editor(0);
44 this.validate_notebook_state('click 0', 'edit', 0);
45 this.trigger_keydown('up');
46 this.validate_notebook_state('up at top of notebook', 'edit', 0);
47 this.set_cell_editor_cursor(0, 0, 10);
48 this.trigger_keydown('down');
49 this.validate_notebook_state('down', 'edit', 1);
50 });
51 });
@@ -0,0 +1,27 b''
1
2 // Test
3 casper.notebook_test(function () {
4 var a = 'print("a")';
5 var index = this.append_cell(a);
6 this.execute_cell_then(index);
7
8 var b = 'print("b")';
9 index = this.append_cell(b);
10 this.execute_cell_then(index);
11
12 var c = 'print("c")';
13 index = this.append_cell(c);
14 this.execute_cell_then(index);
15
16 this.then(function () {
17 // Cell insertion
18 this.select_cell(2);
19 this.trigger_keydown('a'); // Creates one cell
20 this.test.assertEquals(this.get_cell_text(2), '', 'a; New cell 2 text is empty');
21 this.validate_notebook_state('a', 'command', 2);
22 this.trigger_keydown('b'); // Creates one cell
23 this.test.assertEquals(this.get_cell_text(2), '', 'b; Cell 2 text is still empty');
24 this.test.assertEquals(this.get_cell_text(3), '', 'b; New cell 3 text is empty');
25 this.validate_notebook_state('b', 'command', 3);
26 });
27 }); No newline at end of file
@@ -0,0 +1,28 b''
1 // Test keyboard shortcuts that change the cell's mode.
2
3 // Test
4 casper.notebook_test(function () {
5 this.then(function () {
6 // Cell mode change
7 this.select_cell(0);
8 this.trigger_keydown('esc','r');
9 this.test.assertEquals(this.get_cell(0).cell_type, 'raw', 'r; cell is raw');
10 this.trigger_keydown('1');
11 this.test.assertEquals(this.get_cell(0).cell_type, 'heading', '1; cell is heading');
12 this.test.assertEquals(this.get_cell(0).level, 1, '1; cell is level 1 heading');
13 this.trigger_keydown('2');
14 this.test.assertEquals(this.get_cell(0).level, 2, '2; cell is level 2 heading');
15 this.trigger_keydown('3');
16 this.test.assertEquals(this.get_cell(0).level, 3, '3; cell is level 3 heading');
17 this.trigger_keydown('4');
18 this.test.assertEquals(this.get_cell(0).level, 4, '4; cell is level 4 heading');
19 this.trigger_keydown('5');
20 this.test.assertEquals(this.get_cell(0).level, 5, '5; cell is level 5 heading');
21 this.trigger_keydown('6');
22 this.test.assertEquals(this.get_cell(0).level, 6, '6; cell is level 6 heading');
23 this.trigger_keydown('m');
24 this.test.assertEquals(this.get_cell(0).cell_type, 'markdown', 'm; cell is markdown');
25 this.trigger_keydown('y');
26 this.test.assertEquals(this.get_cell(0).cell_type, 'code', 'y; cell is code');
27 });
28 }); No newline at end of file
@@ -0,0 +1,55 b''
1
2
3 // Test
4 casper.notebook_test(function () {
5 var a = 'print("a")';
6 var index = this.append_cell(a);
7 this.execute_cell_then(index);
8
9 var b = 'print("b")';
10 index = this.append_cell(b);
11 this.execute_cell_then(index);
12
13 var c = 'print("c")';
14 index = this.append_cell(c);
15 this.execute_cell_then(index);
16
17 this.then(function () {
18 // Copy/paste/cut
19 var num_cells = this.get_cells_length();
20 this.test.assertEquals(this.get_cell_text(1), a, 'Verify that cell 1 is a');
21 this.select_cell(1);
22 this.trigger_keydown('x'); // Cut
23 this.validate_notebook_state('x', 'command', 1);
24 this.test.assertEquals(this.get_cells_length(), num_cells-1, 'Verify that a cell was removed.');
25 this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 2 is now where cell 1 was.');
26 this.select_cell(2);
27 this.trigger_keydown('v'); // Paste
28 this.validate_notebook_state('v', 'command', 3); // Selection should move to pasted cell, below current cell.
29 this.test.assertEquals(this.get_cell_text(3), a, 'Verify that cell 3 has the cut contents.');
30 this.test.assertEquals(this.get_cells_length(), num_cells, 'Verify a the cell was added.');
31 this.trigger_keydown('v'); // Paste
32 this.validate_notebook_state('v', 'command', 4); // Selection should move to pasted cell, below current cell.
33 this.test.assertEquals(this.get_cell_text(4), a, 'Verify that cell 4 has the cut contents.');
34 this.test.assertEquals(this.get_cells_length(), num_cells+1, 'Verify a the cell was added.');
35 this.select_cell(1);
36 this.trigger_keydown('c'); // Copy
37 this.validate_notebook_state('c', 'command', 1);
38 this.test.assertEquals(this.get_cell_text(1), b, 'Verify that cell 1 is b');
39 this.select_cell(2);
40 this.trigger_keydown('c'); // Copy
41 this.validate_notebook_state('c', 'command', 2);
42 this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 is c');
43 this.select_cell(4);
44 this.trigger_keydown('v'); // Paste
45 this.validate_notebook_state('v', 'command', 5);
46 this.test.assertEquals(this.get_cell_text(2), c, 'Verify that cell 2 still has the copied contents.');
47 this.test.assertEquals(this.get_cell_text(5), c, 'Verify that cell 5 has the copied contents.');
48 this.test.assertEquals(this.get_cells_length(), num_cells+2, 'Verify a the cell was added.');
49 this.select_cell(0);
50 this.trigger_keydown('shift-v'); // Paste
51 this.validate_notebook_state('shift-v', 'command', 0);
52 this.test.assertEquals(this.get_cell_text(0), c, 'Verify that cell 0 has the copied contents.');
53 this.test.assertEquals(this.get_cells_length(), num_cells+3, 'Verify a the cell was added.');
54 });
55 }); No newline at end of file
@@ -0,0 +1,72 b''
1 // Test keyboard invoked execution.
2
3 // Test
4 casper.notebook_test(function () {
5 var a = 'print("a")';
6 var index = this.append_cell(a);
7 this.execute_cell_then(index);
8
9 var b = 'print("b")';
10 index = this.append_cell(b);
11 this.execute_cell_then(index);
12
13 var c = 'print("c")';
14 index = this.append_cell(c);
15 this.execute_cell_then(index);
16
17 this.then(function () {
18
19 // shift-enter
20 // last cell in notebook
21 var base_index = 3;
22 this.select_cell(base_index);
23 this.trigger_keydown('shift-enter'); // Creates one cell
24 this.validate_notebook_state('shift-enter (no cell below)', 'edit', base_index + 1);
25 // not last cell in notebook & starts in edit mode
26 this.click_cell_editor(base_index);
27 this.validate_notebook_state('click cell ' + base_index, 'edit', base_index);
28 this.trigger_keydown('shift-enter');
29 this.validate_notebook_state('shift-enter (cell exists below)', 'command', base_index + 1);
30 // starts in command mode
31 this.trigger_keydown('k');
32 this.validate_notebook_state('k in comand mode', 'command', base_index);
33 this.trigger_keydown('shift-enter');
34 this.validate_notebook_state('shift-enter (start in command mode)', 'command', base_index + 1);
35
36 // ctrl-enter
37 // last cell in notebook
38 base_index++;
39 this.trigger_keydown('ctrl-enter');
40 this.validate_notebook_state('ctrl-enter (no cell below)', 'command', base_index);
41 // not last cell in notebook & starts in edit mode
42 this.click_cell_editor(base_index-1);
43 this.validate_notebook_state('click cell ' + (base_index-1), 'edit', base_index-1);
44 this.trigger_keydown('ctrl-enter');
45 this.validate_notebook_state('ctrl-enter (cell exists below)', 'command', base_index-1);
46 // starts in command mode
47 this.trigger_keydown('j');
48 this.validate_notebook_state('j in comand mode', 'command', base_index);
49 this.trigger_keydown('ctrl-enter');
50 this.validate_notebook_state('ctrl-enter (start in command mode)', 'command', base_index);
51
52 // alt-enter
53 // last cell in notebook
54 this.trigger_keydown('alt-enter'); // Creates one cell
55 this.validate_notebook_state('alt-enter (no cell below)', 'edit', base_index + 1);
56 // not last cell in notebook & starts in edit mode
57 this.click_cell_editor(base_index);
58 this.validate_notebook_state('click cell ' + base_index, 'edit', base_index);
59 this.trigger_keydown('alt-enter'); // Creates one cell
60 this.validate_notebook_state('alt-enter (cell exists below)', 'edit', base_index + 1);
61 // starts in command mode
62 this.trigger_keydown('esc', 'k');
63 this.validate_notebook_state('k in comand mode', 'command', base_index);
64 this.trigger_keydown('alt-enter'); // Creates one cell
65 this.validate_notebook_state('alt-enter (start in command mode)', 'edit', base_index + 1);
66
67 // Notebook will now have 8 cells, the index of the last cell will be 7.
68 this.test.assertEquals(this.get_cells_length(), 8, '*-enter commands added cells where needed.');
69 this.select_cell(7);
70 this.validate_notebook_state('click cell ' + 7 + ' and esc', 'command', 7);
71 });
72 }); No newline at end of file
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,85 +1,74 b''
1 =============================
1 =============================
2 The IPython licensing terms
2 The IPython licensing terms
3 =============================
3 =============================
4
4
5 IPython is licensed under the terms of the Modified BSD License (also known as
5 IPython is licensed under the terms of the Modified BSD License (also known as
6 New or Revised BSD), as follows:
6 New or Revised or 3-Clause BSD), as follows:
7
7
8 Copyright (c) 2008-2010, IPython Development Team
8 - Copyright (c) 2008-2014, IPython Development Team
9 Copyright (c) 2001-2007, Fernando Perez. <fernando.perez@colorado.edu>
9 - Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
10 Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
10 - Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
11 Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
11 - Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
12
12
13 All rights reserved.
13 All rights reserved.
14
14
15 Redistribution and use in source and binary forms, with or without
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions are met:
16 modification, are permitted provided that the following conditions are met:
17
17
18 Redistributions of source code must retain the above copyright notice, this
18 Redistributions of source code must retain the above copyright notice, this
19 list of conditions and the following disclaimer.
19 list of conditions and the following disclaimer.
20
20
21 Redistributions in binary form must reproduce the above copyright notice, this
21 Redistributions in binary form must reproduce the above copyright notice, this
22 list of conditions and the following disclaimer in the documentation and/or
22 list of conditions and the following disclaimer in the documentation and/or
23 other materials provided with the distribution.
23 other materials provided with the distribution.
24
24
25 Neither the name of the IPython Development Team nor the names of its
25 Neither the name of the IPython Development Team nor the names of its
26 contributors may be used to endorse or promote products derived from this
26 contributors may be used to endorse or promote products derived from this
27 software without specific prior written permission.
27 software without specific prior written permission.
28
28
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
30 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
32 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
33 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
39
40 About the IPython Development Team
40 About the IPython Development Team
41 ----------------------------------
41 ----------------------------------
42
42
43 Fernando Perez began IPython in 2001 based on code from Janko Hauser
43 Fernando Perez began IPython in 2001 based on code from Janko Hauser
44 <jhauser@zscout.de> and Nathaniel Gray <n8gray@caltech.edu>. Fernando is still
44 <jhauser@zscout.de> and Nathaniel Gray <n8gray@caltech.edu>. Fernando is still
45 the project lead.
45 the project lead.
46
46
47 The IPython Development Team is the set of all contributors to the IPython
47 The IPython Development Team is the set of all contributors to the IPython
48 project. This includes all of the IPython subprojects. A full list with
48 project. This includes all of the IPython subprojects. A full list with
49 details is kept in the documentation directory, in the file
49 details is kept in the documentation directory, in the file
50 ``about/credits.txt``.
50 ``about/credits.txt``.
51
51
52 The core team that coordinates development on GitHub can be found here:
52 The core team that coordinates development on GitHub can be found here:
53 http://github.com/ipython. As of late 2010, it consists of:
53 https://github.com/ipython/.
54
55 * Brian E. Granger
56 * Jonathan March
57 * Evan Patterson
58 * Fernando Perez
59 * Min Ragan-Kelley
60 * Robert Kern
61
62
54
63 Our Copyright Policy
55 Our Copyright Policy
64 --------------------
56 --------------------
65
57
66 IPython uses a shared copyright model. Each contributor maintains copyright
58 IPython uses a shared copyright model. Each contributor maintains copyright
67 over their contributions to IPython. But, it is important to note that these
59 over their contributions to IPython. But, it is important to note that these
68 contributions are typically only changes to the repositories. Thus, the IPython
60 contributions are typically only changes to the repositories. Thus, the IPython
69 source code, in its entirety is not the copyright of any single person or
61 source code, in its entirety is not the copyright of any single person or
70 institution. Instead, it is the collective copyright of the entire IPython
62 institution. Instead, it is the collective copyright of the entire IPython
71 Development Team. If individual contributors want to maintain a record of what
63 Development Team. If individual contributors want to maintain a record of what
72 changes/contributions they have specific copyright on, they should indicate
64 changes/contributions they have specific copyright on, they should indicate
73 their copyright in the commit message of the change, when they commit the
65 their copyright in the commit message of the change, when they commit the
74 change to one of the IPython repositories.
66 change to one of the IPython repositories.
75
67
76 With this in mind, the following banner should be used in any source code file
68 With this in mind, the following banner should be used in any source code file
77 to indicate the copyright and license terms:
69 to indicate the copyright and license terms:
78
70
79 #-----------------------------------------------------------------------------
71 ::
80 # Copyright (c) 2010, IPython Development Team.
72
81 #
73 # Copyright (c) IPython Development Team.
82 # Distributed under the terms of the Modified BSD License.
74 # Distributed under the terms of the Modified BSD License.
83 #
84 # The full license is in the file COPYING.txt, distributed with this software.
85 #-----------------------------------------------------------------------------
@@ -1,811 +1,854 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2010-2011 The IPython Development Team.
3 # Copyright (C) 2010-2011 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the BSD License.
5 # Distributed under the terms of the BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import datetime
17 import datetime
18 import os
18 import os
19 import re
19 import re
20 try:
20 try:
21 import sqlite3
21 import sqlite3
22 except ImportError:
22 except ImportError:
23 try:
23 try:
24 from pysqlite2 import dbapi2 as sqlite3
24 from pysqlite2 import dbapi2 as sqlite3
25 except ImportError:
25 except ImportError:
26 sqlite3 = None
26 sqlite3 = None
27 import threading
27 import threading
28
28
29 # Our own packages
29 # Our own packages
30 from IPython.config.configurable import Configurable
30 from IPython.config.configurable import Configurable
31 from IPython.external.decorator import decorator
31 from IPython.external.decorator import decorator
32 from IPython.utils.decorators import undoc
32 from IPython.utils.path import locate_profile
33 from IPython.utils.path import locate_profile
33 from IPython.utils import py3compat
34 from IPython.utils import py3compat
34 from IPython.utils.traitlets import (
35 from IPython.utils.traitlets import (
35 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
36 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
36 )
37 )
37 from IPython.utils.warn import warn
38 from IPython.utils.warn import warn
38
39
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40 # Classes and functions
41 # Classes and functions
41 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
42
43
44 @undoc
43 class DummyDB(object):
45 class DummyDB(object):
44 """Dummy DB that will act as a black hole for history.
46 """Dummy DB that will act as a black hole for history.
45
47
46 Only used in the absence of sqlite"""
48 Only used in the absence of sqlite"""
47 def execute(*args, **kwargs):
49 def execute(*args, **kwargs):
48 return []
50 return []
49
51
50 def commit(self, *args, **kwargs):
52 def commit(self, *args, **kwargs):
51 pass
53 pass
52
54
53 def __enter__(self, *args, **kwargs):
55 def __enter__(self, *args, **kwargs):
54 pass
56 pass
55
57
56 def __exit__(self, *args, **kwargs):
58 def __exit__(self, *args, **kwargs):
57 pass
59 pass
58
60
59
61
60 @decorator
62 @decorator
61 def needs_sqlite(f, self, *a, **kw):
63 def needs_sqlite(f, self, *a, **kw):
62 """return an empty list in the absence of sqlite"""
64 """Decorator: return an empty list in the absence of sqlite."""
63 if sqlite3 is None or not self.enabled:
65 if sqlite3 is None or not self.enabled:
64 return []
66 return []
65 else:
67 else:
66 return f(self, *a, **kw)
68 return f(self, *a, **kw)
67
69
68
70
69 if sqlite3 is not None:
71 if sqlite3 is not None:
70 DatabaseError = sqlite3.DatabaseError
72 DatabaseError = sqlite3.DatabaseError
71 else:
73 else:
74 @undoc
72 class DatabaseError(Exception):
75 class DatabaseError(Exception):
73 "Dummy exception when sqlite could not be imported. Should never occur."
76 "Dummy exception when sqlite could not be imported. Should never occur."
74
77
75 @decorator
78 @decorator
76 def catch_corrupt_db(f, self, *a, **kw):
79 def catch_corrupt_db(f, self, *a, **kw):
77 """A decorator which wraps HistoryAccessor method calls to catch errors from
80 """A decorator which wraps HistoryAccessor method calls to catch errors from
78 a corrupt SQLite database, move the old database out of the way, and create
81 a corrupt SQLite database, move the old database out of the way, and create
79 a new one.
82 a new one.
80 """
83 """
81 try:
84 try:
82 return f(self, *a, **kw)
85 return f(self, *a, **kw)
83 except DatabaseError:
86 except DatabaseError:
84 if os.path.isfile(self.hist_file):
87 if os.path.isfile(self.hist_file):
85 # Try to move the file out of the way
88 # Try to move the file out of the way
86 base,ext = os.path.splitext(self.hist_file)
89 base,ext = os.path.splitext(self.hist_file)
87 newpath = base + '-corrupt' + ext
90 newpath = base + '-corrupt' + ext
88 os.rename(self.hist_file, newpath)
91 os.rename(self.hist_file, newpath)
89 self.init_db()
92 self.init_db()
90 print("ERROR! History file wasn't a valid SQLite database.",
93 print("ERROR! History file wasn't a valid SQLite database.",
91 "It was moved to %s" % newpath, "and a new file created.")
94 "It was moved to %s" % newpath, "and a new file created.")
92 return []
95 return []
93
96
94 else:
97 else:
95 # The hist_file is probably :memory: or something else.
98 # The hist_file is probably :memory: or something else.
96 raise
99 raise
97
100
98
101
99
102
100 class HistoryAccessor(Configurable):
103 class HistoryAccessor(Configurable):
101 """Access the history database without adding to it.
104 """Access the history database without adding to it.
102
105
103 This is intended for use by standalone history tools. IPython shells use
106 This is intended for use by standalone history tools. IPython shells use
104 HistoryManager, below, which is a subclass of this."""
107 HistoryManager, below, which is a subclass of this."""
105
108
106 # String holding the path to the history file
109 # String holding the path to the history file
107 hist_file = Unicode(config=True,
110 hist_file = Unicode(config=True,
108 help="""Path to file to use for SQLite history database.
111 help="""Path to file to use for SQLite history database.
109
112
110 By default, IPython will put the history database in the IPython
113 By default, IPython will put the history database in the IPython
111 profile directory. If you would rather share one history among
114 profile directory. If you would rather share one history among
112 profiles, you can set this value in each, so that they are consistent.
115 profiles, you can set this value in each, so that they are consistent.
113
116
114 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
117 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
115 mounts. If you see IPython hanging, try setting this to something on a
118 mounts. If you see IPython hanging, try setting this to something on a
116 local disk, e.g::
119 local disk, e.g::
117
120
118 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
121 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
119
122
120 """)
123 """)
121
124
122 enabled = Bool(True, config=True,
125 enabled = Bool(True, config=True,
123 help="""enable the SQLite history
126 help="""enable the SQLite history
124
127
125 set enabled=False to disable the SQLite history,
128 set enabled=False to disable the SQLite history,
126 in which case there will be no stored history, no SQLite connection,
129 in which case there will be no stored history, no SQLite connection,
127 and no background saving thread. This may be necessary in some
130 and no background saving thread. This may be necessary in some
128 threaded environments where IPython is embedded.
131 threaded environments where IPython is embedded.
129 """
132 """
130 )
133 )
131
134
132 connection_options = Dict(config=True,
135 connection_options = Dict(config=True,
133 help="""Options for configuring the SQLite connection
136 help="""Options for configuring the SQLite connection
134
137
135 These options are passed as keyword args to sqlite3.connect
138 These options are passed as keyword args to sqlite3.connect
136 when establishing database conenctions.
139 when establishing database conenctions.
137 """
140 """
138 )
141 )
139
142
140 # The SQLite database
143 # The SQLite database
141 db = Any()
144 db = Any()
142 def _db_changed(self, name, old, new):
145 def _db_changed(self, name, old, new):
143 """validate the db, since it can be an Instance of two different types"""
146 """validate the db, since it can be an Instance of two different types"""
144 connection_types = (DummyDB,)
147 connection_types = (DummyDB,)
145 if sqlite3 is not None:
148 if sqlite3 is not None:
146 connection_types = (DummyDB, sqlite3.Connection)
149 connection_types = (DummyDB, sqlite3.Connection)
147 if not isinstance(new, connection_types):
150 if not isinstance(new, connection_types):
148 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
151 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
149 (self.__class__.__name__, new)
152 (self.__class__.__name__, new)
150 raise TraitError(msg)
153 raise TraitError(msg)
151
154
152 def __init__(self, profile='default', hist_file=u'', **traits):
155 def __init__(self, profile='default', hist_file=u'', **traits):
153 """Create a new history accessor.
156 """Create a new history accessor.
154
157
155 Parameters
158 Parameters
156 ----------
159 ----------
157 profile : str
160 profile : str
158 The name of the profile from which to open history.
161 The name of the profile from which to open history.
159 hist_file : str
162 hist_file : str
160 Path to an SQLite history database stored by IPython. If specified,
163 Path to an SQLite history database stored by IPython. If specified,
161 hist_file overrides profile.
164 hist_file overrides profile.
162 config :
165 config : :class:`~IPython.config.loader.Config`
163 Config object. hist_file can also be set through this.
166 Config object. hist_file can also be set through this.
164 """
167 """
165 # We need a pointer back to the shell for various tasks.
168 # We need a pointer back to the shell for various tasks.
166 super(HistoryAccessor, self).__init__(**traits)
169 super(HistoryAccessor, self).__init__(**traits)
167 # defer setting hist_file from kwarg until after init,
170 # defer setting hist_file from kwarg until after init,
168 # otherwise the default kwarg value would clobber any value
171 # otherwise the default kwarg value would clobber any value
169 # set by config
172 # set by config
170 if hist_file:
173 if hist_file:
171 self.hist_file = hist_file
174 self.hist_file = hist_file
172
175
173 if self.hist_file == u'':
176 if self.hist_file == u'':
174 # No one has set the hist_file, yet.
177 # No one has set the hist_file, yet.
175 self.hist_file = self._get_hist_file_name(profile)
178 self.hist_file = self._get_hist_file_name(profile)
176
179
177 if sqlite3 is None and self.enabled:
180 if sqlite3 is None and self.enabled:
178 warn("IPython History requires SQLite, your history will not be saved")
181 warn("IPython History requires SQLite, your history will not be saved")
179 self.enabled = False
182 self.enabled = False
180
183
181 self.init_db()
184 self.init_db()
182
185
183 def _get_hist_file_name(self, profile='default'):
186 def _get_hist_file_name(self, profile='default'):
184 """Find the history file for the given profile name.
187 """Find the history file for the given profile name.
185
188
186 This is overridden by the HistoryManager subclass, to use the shell's
189 This is overridden by the HistoryManager subclass, to use the shell's
187 active profile.
190 active profile.
188
191
189 Parameters
192 Parameters
190 ----------
193 ----------
191 profile : str
194 profile : str
192 The name of a profile which has a history file.
195 The name of a profile which has a history file.
193 """
196 """
194 return os.path.join(locate_profile(profile), 'history.sqlite')
197 return os.path.join(locate_profile(profile), 'history.sqlite')
195
198
196 @catch_corrupt_db
199 @catch_corrupt_db
197 def init_db(self):
200 def init_db(self):
198 """Connect to the database, and create tables if necessary."""
201 """Connect to the database, and create tables if necessary."""
199 if not self.enabled:
202 if not self.enabled:
200 self.db = DummyDB()
203 self.db = DummyDB()
201 return
204 return
202
205
203 # use detect_types so that timestamps return datetime objects
206 # use detect_types so that timestamps return datetime objects
204 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
207 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
205 kwargs.update(self.connection_options)
208 kwargs.update(self.connection_options)
206 self.db = sqlite3.connect(self.hist_file, **kwargs)
209 self.db = sqlite3.connect(self.hist_file, **kwargs)
207 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
210 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
208 primary key autoincrement, start timestamp,
211 primary key autoincrement, start timestamp,
209 end timestamp, num_cmds integer, remark text)""")
212 end timestamp, num_cmds integer, remark text)""")
210 self.db.execute("""CREATE TABLE IF NOT EXISTS history
213 self.db.execute("""CREATE TABLE IF NOT EXISTS history
211 (session integer, line integer, source text, source_raw text,
214 (session integer, line integer, source text, source_raw text,
212 PRIMARY KEY (session, line))""")
215 PRIMARY KEY (session, line))""")
213 # Output history is optional, but ensure the table's there so it can be
216 # Output history is optional, but ensure the table's there so it can be
214 # enabled later.
217 # enabled later.
215 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
218 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
216 (session integer, line integer, output text,
219 (session integer, line integer, output text,
217 PRIMARY KEY (session, line))""")
220 PRIMARY KEY (session, line))""")
218 self.db.commit()
221 self.db.commit()
219
222
220 def writeout_cache(self):
223 def writeout_cache(self):
221 """Overridden by HistoryManager to dump the cache before certain
224 """Overridden by HistoryManager to dump the cache before certain
222 database lookups."""
225 database lookups."""
223 pass
226 pass
224
227
225 ## -------------------------------
228 ## -------------------------------
226 ## Methods for retrieving history:
229 ## Methods for retrieving history:
227 ## -------------------------------
230 ## -------------------------------
228 def _run_sql(self, sql, params, raw=True, output=False):
231 def _run_sql(self, sql, params, raw=True, output=False):
229 """Prepares and runs an SQL query for the history database.
232 """Prepares and runs an SQL query for the history database.
230
233
231 Parameters
234 Parameters
232 ----------
235 ----------
233 sql : str
236 sql : str
234 Any filtering expressions to go after SELECT ... FROM ...
237 Any filtering expressions to go after SELECT ... FROM ...
235 params : tuple
238 params : tuple
236 Parameters passed to the SQL query (to replace "?")
239 Parameters passed to the SQL query (to replace "?")
237 raw, output : bool
240 raw, output : bool
238 See :meth:`get_range`
241 See :meth:`get_range`
239
242
240 Returns
243 Returns
241 -------
244 -------
242 Tuples as :meth:`get_range`
245 Tuples as :meth:`get_range`
243 """
246 """
244 toget = 'source_raw' if raw else 'source'
247 toget = 'source_raw' if raw else 'source'
245 sqlfrom = "history"
248 sqlfrom = "history"
246 if output:
249 if output:
247 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
250 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
248 toget = "history.%s, output_history.output" % toget
251 toget = "history.%s, output_history.output" % toget
249 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
252 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
250 (toget, sqlfrom) + sql, params)
253 (toget, sqlfrom) + sql, params)
251 if output: # Regroup into 3-tuples, and parse JSON
254 if output: # Regroup into 3-tuples, and parse JSON
252 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
255 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
253 return cur
256 return cur
254
257
255 @needs_sqlite
258 @needs_sqlite
256 @catch_corrupt_db
259 @catch_corrupt_db
257 def get_session_info(self, session=0):
260 def get_session_info(self, session):
258 """get info about a session
261 """Get info about a session.
259
262
260 Parameters
263 Parameters
261 ----------
264 ----------
262
265
263 session : int
266 session : int
264 Session number to retrieve. The current session is 0, and negative
267 Session number to retrieve.
265 numbers count back from current session, so -1 is previous session.
266
268
267 Returns
269 Returns
268 -------
270 -------
269
271
270 (session_id [int], start [datetime], end [datetime], num_cmds [int],
272 session_id : int
271 remark [unicode])
273 Session ID number
272
274 start : datetime
273 Sessions that are running or did not exit cleanly will have `end=None`
275 Timestamp for the start of the session.
274 and `num_cmds=None`.
276 end : datetime
275
277 Timestamp for the end of the session, or None if IPython crashed.
278 num_cmds : int
279 Number of commands run, or None if IPython crashed.
280 remark : unicode
281 A manually set description.
276 """
282 """
277
278 if session <= 0:
279 session += self.session_number
280
281 query = "SELECT * from sessions where session == ?"
283 query = "SELECT * from sessions where session == ?"
282 return self.db.execute(query, (session,)).fetchone()
284 return self.db.execute(query, (session,)).fetchone()
283
285
284 @catch_corrupt_db
286 @catch_corrupt_db
287 def get_last_session_id(self):
288 """Get the last session ID currently in the database.
289
290 Within IPython, this should be the same as the value stored in
291 :attr:`HistoryManager.session_number`.
292 """
293 for record in self.get_tail(n=1, include_latest=True):
294 return record[0]
295
296 @catch_corrupt_db
285 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
297 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
286 """Get the last n lines from the history database.
298 """Get the last n lines from the history database.
287
299
288 Parameters
300 Parameters
289 ----------
301 ----------
290 n : int
302 n : int
291 The number of lines to get
303 The number of lines to get
292 raw, output : bool
304 raw, output : bool
293 See :meth:`get_range`
305 See :meth:`get_range`
294 include_latest : bool
306 include_latest : bool
295 If False (default), n+1 lines are fetched, and the latest one
307 If False (default), n+1 lines are fetched, and the latest one
296 is discarded. This is intended to be used where the function
308 is discarded. This is intended to be used where the function
297 is called by a user command, which it should not return.
309 is called by a user command, which it should not return.
298
310
299 Returns
311 Returns
300 -------
312 -------
301 Tuples as :meth:`get_range`
313 Tuples as :meth:`get_range`
302 """
314 """
303 self.writeout_cache()
315 self.writeout_cache()
304 if not include_latest:
316 if not include_latest:
305 n += 1
317 n += 1
306 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
318 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
307 (n,), raw=raw, output=output)
319 (n,), raw=raw, output=output)
308 if not include_latest:
320 if not include_latest:
309 return reversed(list(cur)[1:])
321 return reversed(list(cur)[1:])
310 return reversed(list(cur))
322 return reversed(list(cur))
311
323
312 @catch_corrupt_db
324 @catch_corrupt_db
313 def search(self, pattern="*", raw=True, search_raw=True,
325 def search(self, pattern="*", raw=True, search_raw=True,
314 output=False, n=None, unique=False):
326 output=False, n=None, unique=False):
315 """Search the database using unix glob-style matching (wildcards
327 """Search the database using unix glob-style matching (wildcards
316 * and ?).
328 * and ?).
317
329
318 Parameters
330 Parameters
319 ----------
331 ----------
320 pattern : str
332 pattern : str
321 The wildcarded pattern to match when searching
333 The wildcarded pattern to match when searching
322 search_raw : bool
334 search_raw : bool
323 If True, search the raw input, otherwise, the parsed input
335 If True, search the raw input, otherwise, the parsed input
324 raw, output : bool
336 raw, output : bool
325 See :meth:`get_range`
337 See :meth:`get_range`
326 n : None or int
338 n : None or int
327 If an integer is given, it defines the limit of
339 If an integer is given, it defines the limit of
328 returned entries.
340 returned entries.
329 unique : bool
341 unique : bool
330 When it is true, return only unique entries.
342 When it is true, return only unique entries.
331
343
332 Returns
344 Returns
333 -------
345 -------
334 Tuples as :meth:`get_range`
346 Tuples as :meth:`get_range`
335 """
347 """
336 tosearch = "source_raw" if search_raw else "source"
348 tosearch = "source_raw" if search_raw else "source"
337 if output:
349 if output:
338 tosearch = "history." + tosearch
350 tosearch = "history." + tosearch
339 self.writeout_cache()
351 self.writeout_cache()
340 sqlform = "WHERE %s GLOB ?" % tosearch
352 sqlform = "WHERE %s GLOB ?" % tosearch
341 params = (pattern,)
353 params = (pattern,)
342 if unique:
354 if unique:
343 sqlform += ' GROUP BY {0}'.format(tosearch)
355 sqlform += ' GROUP BY {0}'.format(tosearch)
344 if n is not None:
356 if n is not None:
345 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
357 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
346 params += (n,)
358 params += (n,)
347 elif unique:
359 elif unique:
348 sqlform += " ORDER BY session, line"
360 sqlform += " ORDER BY session, line"
349 cur = self._run_sql(sqlform, params, raw=raw, output=output)
361 cur = self._run_sql(sqlform, params, raw=raw, output=output)
350 if n is not None:
362 if n is not None:
351 return reversed(list(cur))
363 return reversed(list(cur))
352 return cur
364 return cur
353
365
354 @catch_corrupt_db
366 @catch_corrupt_db
355 def get_range(self, session, start=1, stop=None, raw=True,output=False):
367 def get_range(self, session, start=1, stop=None, raw=True,output=False):
356 """Retrieve input by session.
368 """Retrieve input by session.
357
369
358 Parameters
370 Parameters
359 ----------
371 ----------
360 session : int
372 session : int
361 Session number to retrieve.
373 Session number to retrieve.
362 start : int
374 start : int
363 First line to retrieve.
375 First line to retrieve.
364 stop : int
376 stop : int
365 End of line range (excluded from output itself). If None, retrieve
377 End of line range (excluded from output itself). If None, retrieve
366 to the end of the session.
378 to the end of the session.
367 raw : bool
379 raw : bool
368 If True, return untranslated input
380 If True, return untranslated input
369 output : bool
381 output : bool
370 If True, attempt to include output. This will be 'real' Python
382 If True, attempt to include output. This will be 'real' Python
371 objects for the current session, or text reprs from previous
383 objects for the current session, or text reprs from previous
372 sessions if db_log_output was enabled at the time. Where no output
384 sessions if db_log_output was enabled at the time. Where no output
373 is found, None is used.
385 is found, None is used.
374
386
375 Returns
387 Returns
376 -------
388 -------
377 An iterator over the desired lines. Each line is a 3-tuple, either
389 entries
378 (session, line, input) if output is False, or
390 An iterator over the desired lines. Each line is a 3-tuple, either
379 (session, line, (input, output)) if output is True.
391 (session, line, input) if output is False, or
392 (session, line, (input, output)) if output is True.
380 """
393 """
381 if stop:
394 if stop:
382 lineclause = "line >= ? AND line < ?"
395 lineclause = "line >= ? AND line < ?"
383 params = (session, start, stop)
396 params = (session, start, stop)
384 else:
397 else:
385 lineclause = "line>=?"
398 lineclause = "line>=?"
386 params = (session, start)
399 params = (session, start)
387
400
388 return self._run_sql("WHERE session==? AND %s" % lineclause,
401 return self._run_sql("WHERE session==? AND %s" % lineclause,
389 params, raw=raw, output=output)
402 params, raw=raw, output=output)
390
403
391 def get_range_by_str(self, rangestr, raw=True, output=False):
404 def get_range_by_str(self, rangestr, raw=True, output=False):
392 """Get lines of history from a string of ranges, as used by magic
405 """Get lines of history from a string of ranges, as used by magic
393 commands %hist, %save, %macro, etc.
406 commands %hist, %save, %macro, etc.
394
407
395 Parameters
408 Parameters
396 ----------
409 ----------
397 rangestr : str
410 rangestr : str
398 A string specifying ranges, e.g. "5 ~2/1-4". See
411 A string specifying ranges, e.g. "5 ~2/1-4". See
399 :func:`magic_history` for full details.
412 :func:`magic_history` for full details.
400 raw, output : bool
413 raw, output : bool
401 As :meth:`get_range`
414 As :meth:`get_range`
402
415
403 Returns
416 Returns
404 -------
417 -------
405 Tuples as :meth:`get_range`
418 Tuples as :meth:`get_range`
406 """
419 """
407 for sess, s, e in extract_hist_ranges(rangestr):
420 for sess, s, e in extract_hist_ranges(rangestr):
408 for line in self.get_range(sess, s, e, raw=raw, output=output):
421 for line in self.get_range(sess, s, e, raw=raw, output=output):
409 yield line
422 yield line
410
423
411
424
412 class HistoryManager(HistoryAccessor):
425 class HistoryManager(HistoryAccessor):
413 """A class to organize all history-related functionality in one place.
426 """A class to organize all history-related functionality in one place.
414 """
427 """
415 # Public interface
428 # Public interface
416
429
417 # An instance of the IPython shell we are attached to
430 # An instance of the IPython shell we are attached to
418 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
431 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
419 # Lists to hold processed and raw history. These start with a blank entry
432 # Lists to hold processed and raw history. These start with a blank entry
420 # so that we can index them starting from 1
433 # so that we can index them starting from 1
421 input_hist_parsed = List([""])
434 input_hist_parsed = List([""])
422 input_hist_raw = List([""])
435 input_hist_raw = List([""])
423 # A list of directories visited during session
436 # A list of directories visited during session
424 dir_hist = List()
437 dir_hist = List()
425 def _dir_hist_default(self):
438 def _dir_hist_default(self):
426 try:
439 try:
427 return [py3compat.getcwd()]
440 return [py3compat.getcwd()]
428 except OSError:
441 except OSError:
429 return []
442 return []
430
443
431 # A dict of output history, keyed with ints from the shell's
444 # A dict of output history, keyed with ints from the shell's
432 # execution count.
445 # execution count.
433 output_hist = Dict()
446 output_hist = Dict()
434 # The text/plain repr of outputs.
447 # The text/plain repr of outputs.
435 output_hist_reprs = Dict()
448 output_hist_reprs = Dict()
436
449
437 # The number of the current session in the history database
450 # The number of the current session in the history database
438 session_number = Integer()
451 session_number = Integer()
439
452
440 db_log_output = Bool(False, config=True,
453 db_log_output = Bool(False, config=True,
441 help="Should the history database include output? (default: no)"
454 help="Should the history database include output? (default: no)"
442 )
455 )
443 db_cache_size = Integer(0, config=True,
456 db_cache_size = Integer(0, config=True,
444 help="Write to database every x commands (higher values save disk access & power).\n"
457 help="Write to database every x commands (higher values save disk access & power).\n"
445 "Values of 1 or less effectively disable caching."
458 "Values of 1 or less effectively disable caching."
446 )
459 )
447 # The input and output caches
460 # The input and output caches
448 db_input_cache = List()
461 db_input_cache = List()
449 db_output_cache = List()
462 db_output_cache = List()
450
463
451 # History saving in separate thread
464 # History saving in separate thread
452 save_thread = Instance('IPython.core.history.HistorySavingThread')
465 save_thread = Instance('IPython.core.history.HistorySavingThread')
453 try: # Event is a function returning an instance of _Event...
466 try: # Event is a function returning an instance of _Event...
454 save_flag = Instance(threading._Event)
467 save_flag = Instance(threading._Event)
455 except AttributeError: # ...until Python 3.3, when it's a class.
468 except AttributeError: # ...until Python 3.3, when it's a class.
456 save_flag = Instance(threading.Event)
469 save_flag = Instance(threading.Event)
457
470
458 # Private interface
471 # Private interface
459 # Variables used to store the three last inputs from the user. On each new
472 # Variables used to store the three last inputs from the user. On each new
460 # history update, we populate the user's namespace with these, shifted as
473 # history update, we populate the user's namespace with these, shifted as
461 # necessary.
474 # necessary.
462 _i00 = Unicode(u'')
475 _i00 = Unicode(u'')
463 _i = Unicode(u'')
476 _i = Unicode(u'')
464 _ii = Unicode(u'')
477 _ii = Unicode(u'')
465 _iii = Unicode(u'')
478 _iii = Unicode(u'')
466
479
467 # A regex matching all forms of the exit command, so that we don't store
480 # A regex matching all forms of the exit command, so that we don't store
468 # them in the history (it's annoying to rewind the first entry and land on
481 # them in the history (it's annoying to rewind the first entry and land on
469 # an exit call).
482 # an exit call).
470 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
483 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
471
484
472 def __init__(self, shell=None, config=None, **traits):
485 def __init__(self, shell=None, config=None, **traits):
473 """Create a new history manager associated with a shell instance.
486 """Create a new history manager associated with a shell instance.
474 """
487 """
475 # We need a pointer back to the shell for various tasks.
488 # We need a pointer back to the shell for various tasks.
476 super(HistoryManager, self).__init__(shell=shell, config=config,
489 super(HistoryManager, self).__init__(shell=shell, config=config,
477 **traits)
490 **traits)
478 self.save_flag = threading.Event()
491 self.save_flag = threading.Event()
479 self.db_input_cache_lock = threading.Lock()
492 self.db_input_cache_lock = threading.Lock()
480 self.db_output_cache_lock = threading.Lock()
493 self.db_output_cache_lock = threading.Lock()
481 if self.enabled and self.hist_file != ':memory:':
494 if self.enabled and self.hist_file != ':memory:':
482 self.save_thread = HistorySavingThread(self)
495 self.save_thread = HistorySavingThread(self)
483 self.save_thread.start()
496 self.save_thread.start()
484
497
485 self.new_session()
498 self.new_session()
486
499
487 def _get_hist_file_name(self, profile=None):
500 def _get_hist_file_name(self, profile=None):
488 """Get default history file name based on the Shell's profile.
501 """Get default history file name based on the Shell's profile.
489
502
490 The profile parameter is ignored, but must exist for compatibility with
503 The profile parameter is ignored, but must exist for compatibility with
491 the parent class."""
504 the parent class."""
492 profile_dir = self.shell.profile_dir.location
505 profile_dir = self.shell.profile_dir.location
493 return os.path.join(profile_dir, 'history.sqlite')
506 return os.path.join(profile_dir, 'history.sqlite')
494
507
495 @needs_sqlite
508 @needs_sqlite
496 def new_session(self, conn=None):
509 def new_session(self, conn=None):
497 """Get a new session number."""
510 """Get a new session number."""
498 if conn is None:
511 if conn is None:
499 conn = self.db
512 conn = self.db
500
513
501 with conn:
514 with conn:
502 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
515 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
503 NULL, "") """, (datetime.datetime.now(),))
516 NULL, "") """, (datetime.datetime.now(),))
504 self.session_number = cur.lastrowid
517 self.session_number = cur.lastrowid
505
518
506 def end_session(self):
519 def end_session(self):
507 """Close the database session, filling in the end time and line count."""
520 """Close the database session, filling in the end time and line count."""
508 self.writeout_cache()
521 self.writeout_cache()
509 with self.db:
522 with self.db:
510 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
523 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
511 session==?""", (datetime.datetime.now(),
524 session==?""", (datetime.datetime.now(),
512 len(self.input_hist_parsed)-1, self.session_number))
525 len(self.input_hist_parsed)-1, self.session_number))
513 self.session_number = 0
526 self.session_number = 0
514
527
515 def name_session(self, name):
528 def name_session(self, name):
516 """Give the current session a name in the history database."""
529 """Give the current session a name in the history database."""
517 with self.db:
530 with self.db:
518 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
531 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
519 (name, self.session_number))
532 (name, self.session_number))
520
533
521 def reset(self, new_session=True):
534 def reset(self, new_session=True):
522 """Clear the session history, releasing all object references, and
535 """Clear the session history, releasing all object references, and
523 optionally open a new session."""
536 optionally open a new session."""
524 self.output_hist.clear()
537 self.output_hist.clear()
525 # The directory history can't be completely empty
538 # The directory history can't be completely empty
526 self.dir_hist[:] = [py3compat.getcwd()]
539 self.dir_hist[:] = [py3compat.getcwd()]
527
540
528 if new_session:
541 if new_session:
529 if self.session_number:
542 if self.session_number:
530 self.end_session()
543 self.end_session()
531 self.input_hist_parsed[:] = [""]
544 self.input_hist_parsed[:] = [""]
532 self.input_hist_raw[:] = [""]
545 self.input_hist_raw[:] = [""]
533 self.new_session()
546 self.new_session()
534
547
535 # ------------------------------
548 # ------------------------------
536 # Methods for retrieving history
549 # Methods for retrieving history
537 # ------------------------------
550 # ------------------------------
551 def get_session_info(self, session=0):
552 """Get info about a session.
553
554 Parameters
555 ----------
556
557 session : int
558 Session number to retrieve. The current session is 0, and negative
559 numbers count back from current session, so -1 is the previous session.
560
561 Returns
562 -------
563
564 session_id : int
565 Session ID number
566 start : datetime
567 Timestamp for the start of the session.
568 end : datetime
569 Timestamp for the end of the session, or None if IPython crashed.
570 num_cmds : int
571 Number of commands run, or None if IPython crashed.
572 remark : unicode
573 A manually set description.
574 """
575 if session <= 0:
576 session += self.session_number
577
578 return super(HistoryManager, self).get_session_info(session=session)
579
538 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
580 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
539 """Get input and output history from the current session. Called by
581 """Get input and output history from the current session. Called by
540 get_range, and takes similar parameters."""
582 get_range, and takes similar parameters."""
541 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
583 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
542
584
543 n = len(input_hist)
585 n = len(input_hist)
544 if start < 0:
586 if start < 0:
545 start += n
587 start += n
546 if not stop or (stop > n):
588 if not stop or (stop > n):
547 stop = n
589 stop = n
548 elif stop < 0:
590 elif stop < 0:
549 stop += n
591 stop += n
550
592
551 for i in range(start, stop):
593 for i in range(start, stop):
552 if output:
594 if output:
553 line = (input_hist[i], self.output_hist_reprs.get(i))
595 line = (input_hist[i], self.output_hist_reprs.get(i))
554 else:
596 else:
555 line = input_hist[i]
597 line = input_hist[i]
556 yield (0, i, line)
598 yield (0, i, line)
557
599
558 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
600 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
559 """Retrieve input by session.
601 """Retrieve input by session.
560
602
561 Parameters
603 Parameters
562 ----------
604 ----------
563 session : int
605 session : int
564 Session number to retrieve. The current session is 0, and negative
606 Session number to retrieve. The current session is 0, and negative
565 numbers count back from current session, so -1 is previous session.
607 numbers count back from current session, so -1 is previous session.
566 start : int
608 start : int
567 First line to retrieve.
609 First line to retrieve.
568 stop : int
610 stop : int
569 End of line range (excluded from output itself). If None, retrieve
611 End of line range (excluded from output itself). If None, retrieve
570 to the end of the session.
612 to the end of the session.
571 raw : bool
613 raw : bool
572 If True, return untranslated input
614 If True, return untranslated input
573 output : bool
615 output : bool
574 If True, attempt to include output. This will be 'real' Python
616 If True, attempt to include output. This will be 'real' Python
575 objects for the current session, or text reprs from previous
617 objects for the current session, or text reprs from previous
576 sessions if db_log_output was enabled at the time. Where no output
618 sessions if db_log_output was enabled at the time. Where no output
577 is found, None is used.
619 is found, None is used.
578
620
579 Returns
621 Returns
580 -------
622 -------
581 An iterator over the desired lines. Each line is a 3-tuple, either
623 entries
582 (session, line, input) if output is False, or
624 An iterator over the desired lines. Each line is a 3-tuple, either
583 (session, line, (input, output)) if output is True.
625 (session, line, input) if output is False, or
626 (session, line, (input, output)) if output is True.
584 """
627 """
585 if session <= 0:
628 if session <= 0:
586 session += self.session_number
629 session += self.session_number
587 if session==self.session_number: # Current session
630 if session==self.session_number: # Current session
588 return self._get_range_session(start, stop, raw, output)
631 return self._get_range_session(start, stop, raw, output)
589 return super(HistoryManager, self).get_range(session, start, stop, raw,
632 return super(HistoryManager, self).get_range(session, start, stop, raw,
590 output)
633 output)
591
634
592 ## ----------------------------
635 ## ----------------------------
593 ## Methods for storing history:
636 ## Methods for storing history:
594 ## ----------------------------
637 ## ----------------------------
595 def store_inputs(self, line_num, source, source_raw=None):
638 def store_inputs(self, line_num, source, source_raw=None):
596 """Store source and raw input in history and create input cache
639 """Store source and raw input in history and create input cache
597 variables _i*.
640 variables ``_i*``.
598
641
599 Parameters
642 Parameters
600 ----------
643 ----------
601 line_num : int
644 line_num : int
602 The prompt number of this input.
645 The prompt number of this input.
603
646
604 source : str
647 source : str
605 Python input.
648 Python input.
606
649
607 source_raw : str, optional
650 source_raw : str, optional
608 If given, this is the raw input without any IPython transformations
651 If given, this is the raw input without any IPython transformations
609 applied to it. If not given, ``source`` is used.
652 applied to it. If not given, ``source`` is used.
610 """
653 """
611 if source_raw is None:
654 if source_raw is None:
612 source_raw = source
655 source_raw = source
613 source = source.rstrip('\n')
656 source = source.rstrip('\n')
614 source_raw = source_raw.rstrip('\n')
657 source_raw = source_raw.rstrip('\n')
615
658
616 # do not store exit/quit commands
659 # do not store exit/quit commands
617 if self._exit_re.match(source_raw.strip()):
660 if self._exit_re.match(source_raw.strip()):
618 return
661 return
619
662
620 self.input_hist_parsed.append(source)
663 self.input_hist_parsed.append(source)
621 self.input_hist_raw.append(source_raw)
664 self.input_hist_raw.append(source_raw)
622
665
623 with self.db_input_cache_lock:
666 with self.db_input_cache_lock:
624 self.db_input_cache.append((line_num, source, source_raw))
667 self.db_input_cache.append((line_num, source, source_raw))
625 # Trigger to flush cache and write to DB.
668 # Trigger to flush cache and write to DB.
626 if len(self.db_input_cache) >= self.db_cache_size:
669 if len(self.db_input_cache) >= self.db_cache_size:
627 self.save_flag.set()
670 self.save_flag.set()
628
671
629 # update the auto _i variables
672 # update the auto _i variables
630 self._iii = self._ii
673 self._iii = self._ii
631 self._ii = self._i
674 self._ii = self._i
632 self._i = self._i00
675 self._i = self._i00
633 self._i00 = source_raw
676 self._i00 = source_raw
634
677
635 # hackish access to user namespace to create _i1,_i2... dynamically
678 # hackish access to user namespace to create _i1,_i2... dynamically
636 new_i = '_i%s' % line_num
679 new_i = '_i%s' % line_num
637 to_main = {'_i': self._i,
680 to_main = {'_i': self._i,
638 '_ii': self._ii,
681 '_ii': self._ii,
639 '_iii': self._iii,
682 '_iii': self._iii,
640 new_i : self._i00 }
683 new_i : self._i00 }
641
684
642 if self.shell is not None:
685 if self.shell is not None:
643 self.shell.push(to_main, interactive=False)
686 self.shell.push(to_main, interactive=False)
644
687
645 def store_output(self, line_num):
688 def store_output(self, line_num):
646 """If database output logging is enabled, this saves all the
689 """If database output logging is enabled, this saves all the
647 outputs from the indicated prompt number to the database. It's
690 outputs from the indicated prompt number to the database. It's
648 called by run_cell after code has been executed.
691 called by run_cell after code has been executed.
649
692
650 Parameters
693 Parameters
651 ----------
694 ----------
652 line_num : int
695 line_num : int
653 The line number from which to save outputs
696 The line number from which to save outputs
654 """
697 """
655 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
698 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
656 return
699 return
657 output = self.output_hist_reprs[line_num]
700 output = self.output_hist_reprs[line_num]
658
701
659 with self.db_output_cache_lock:
702 with self.db_output_cache_lock:
660 self.db_output_cache.append((line_num, output))
703 self.db_output_cache.append((line_num, output))
661 if self.db_cache_size <= 1:
704 if self.db_cache_size <= 1:
662 self.save_flag.set()
705 self.save_flag.set()
663
706
664 def _writeout_input_cache(self, conn):
707 def _writeout_input_cache(self, conn):
665 with conn:
708 with conn:
666 for line in self.db_input_cache:
709 for line in self.db_input_cache:
667 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
710 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
668 (self.session_number,)+line)
711 (self.session_number,)+line)
669
712
670 def _writeout_output_cache(self, conn):
713 def _writeout_output_cache(self, conn):
671 with conn:
714 with conn:
672 for line in self.db_output_cache:
715 for line in self.db_output_cache:
673 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
716 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
674 (self.session_number,)+line)
717 (self.session_number,)+line)
675
718
676 @needs_sqlite
719 @needs_sqlite
677 def writeout_cache(self, conn=None):
720 def writeout_cache(self, conn=None):
678 """Write any entries in the cache to the database."""
721 """Write any entries in the cache to the database."""
679 if conn is None:
722 if conn is None:
680 conn = self.db
723 conn = self.db
681
724
682 with self.db_input_cache_lock:
725 with self.db_input_cache_lock:
683 try:
726 try:
684 self._writeout_input_cache(conn)
727 self._writeout_input_cache(conn)
685 except sqlite3.IntegrityError:
728 except sqlite3.IntegrityError:
686 self.new_session(conn)
729 self.new_session(conn)
687 print("ERROR! Session/line number was not unique in",
730 print("ERROR! Session/line number was not unique in",
688 "database. History logging moved to new session",
731 "database. History logging moved to new session",
689 self.session_number)
732 self.session_number)
690 try:
733 try:
691 # Try writing to the new session. If this fails, don't
734 # Try writing to the new session. If this fails, don't
692 # recurse
735 # recurse
693 self._writeout_input_cache(conn)
736 self._writeout_input_cache(conn)
694 except sqlite3.IntegrityError:
737 except sqlite3.IntegrityError:
695 pass
738 pass
696 finally:
739 finally:
697 self.db_input_cache = []
740 self.db_input_cache = []
698
741
699 with self.db_output_cache_lock:
742 with self.db_output_cache_lock:
700 try:
743 try:
701 self._writeout_output_cache(conn)
744 self._writeout_output_cache(conn)
702 except sqlite3.IntegrityError:
745 except sqlite3.IntegrityError:
703 print("!! Session/line number for output was not unique",
746 print("!! Session/line number for output was not unique",
704 "in database. Output will not be stored.")
747 "in database. Output will not be stored.")
705 finally:
748 finally:
706 self.db_output_cache = []
749 self.db_output_cache = []
707
750
708
751
709 class HistorySavingThread(threading.Thread):
752 class HistorySavingThread(threading.Thread):
710 """This thread takes care of writing history to the database, so that
753 """This thread takes care of writing history to the database, so that
711 the UI isn't held up while that happens.
754 the UI isn't held up while that happens.
712
755
713 It waits for the HistoryManager's save_flag to be set, then writes out
756 It waits for the HistoryManager's save_flag to be set, then writes out
714 the history cache. The main thread is responsible for setting the flag when
757 the history cache. The main thread is responsible for setting the flag when
715 the cache size reaches a defined threshold."""
758 the cache size reaches a defined threshold."""
716 daemon = True
759 daemon = True
717 stop_now = False
760 stop_now = False
718 enabled = True
761 enabled = True
719 def __init__(self, history_manager):
762 def __init__(self, history_manager):
720 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
763 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
721 self.history_manager = history_manager
764 self.history_manager = history_manager
722 self.enabled = history_manager.enabled
765 self.enabled = history_manager.enabled
723 atexit.register(self.stop)
766 atexit.register(self.stop)
724
767
725 @needs_sqlite
768 @needs_sqlite
726 def run(self):
769 def run(self):
727 # We need a separate db connection per thread:
770 # We need a separate db connection per thread:
728 try:
771 try:
729 self.db = sqlite3.connect(self.history_manager.hist_file,
772 self.db = sqlite3.connect(self.history_manager.hist_file,
730 **self.history_manager.connection_options
773 **self.history_manager.connection_options
731 )
774 )
732 while True:
775 while True:
733 self.history_manager.save_flag.wait()
776 self.history_manager.save_flag.wait()
734 if self.stop_now:
777 if self.stop_now:
735 return
778 return
736 self.history_manager.save_flag.clear()
779 self.history_manager.save_flag.clear()
737 self.history_manager.writeout_cache(self.db)
780 self.history_manager.writeout_cache(self.db)
738 except Exception as e:
781 except Exception as e:
739 print(("The history saving thread hit an unexpected error (%s)."
782 print(("The history saving thread hit an unexpected error (%s)."
740 "History will not be written to the database.") % repr(e))
783 "History will not be written to the database.") % repr(e))
741
784
742 def stop(self):
785 def stop(self):
743 """This can be called from the main thread to safely stop this thread.
786 """This can be called from the main thread to safely stop this thread.
744
787
745 Note that it does not attempt to write out remaining history before
788 Note that it does not attempt to write out remaining history before
746 exiting. That should be done by calling the HistoryManager's
789 exiting. That should be done by calling the HistoryManager's
747 end_session method."""
790 end_session method."""
748 self.stop_now = True
791 self.stop_now = True
749 self.history_manager.save_flag.set()
792 self.history_manager.save_flag.set()
750 self.join()
793 self.join()
751
794
752
795
753 # To match, e.g. ~5/8-~2/3
796 # To match, e.g. ~5/8-~2/3
754 range_re = re.compile(r"""
797 range_re = re.compile(r"""
755 ((?P<startsess>~?\d+)/)?
798 ((?P<startsess>~?\d+)/)?
756 (?P<start>\d+)?
799 (?P<start>\d+)?
757 ((?P<sep>[\-:])
800 ((?P<sep>[\-:])
758 ((?P<endsess>~?\d+)/)?
801 ((?P<endsess>~?\d+)/)?
759 (?P<end>\d+))?
802 (?P<end>\d+))?
760 $""", re.VERBOSE)
803 $""", re.VERBOSE)
761
804
762
805
763 def extract_hist_ranges(ranges_str):
806 def extract_hist_ranges(ranges_str):
764 """Turn a string of history ranges into 3-tuples of (session, start, stop).
807 """Turn a string of history ranges into 3-tuples of (session, start, stop).
765
808
766 Examples
809 Examples
767 --------
810 --------
768 list(extract_input_ranges("~8/5-~7/4 2"))
811 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
769 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
812 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
770 """
813 """
771 for range_str in ranges_str.split():
814 for range_str in ranges_str.split():
772 rmatch = range_re.match(range_str)
815 rmatch = range_re.match(range_str)
773 if not rmatch:
816 if not rmatch:
774 continue
817 continue
775 start = rmatch.group("start")
818 start = rmatch.group("start")
776 if start:
819 if start:
777 start = int(start)
820 start = int(start)
778 end = rmatch.group("end")
821 end = rmatch.group("end")
779 # If no end specified, get (a, a + 1)
822 # If no end specified, get (a, a + 1)
780 end = int(end) if end else start + 1
823 end = int(end) if end else start + 1
781 else: # start not specified
824 else: # start not specified
782 if not rmatch.group('startsess'): # no startsess
825 if not rmatch.group('startsess'): # no startsess
783 continue
826 continue
784 start = 1
827 start = 1
785 end = None # provide the entire session hist
828 end = None # provide the entire session hist
786
829
787 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
830 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
788 end += 1
831 end += 1
789 startsess = rmatch.group("startsess") or "0"
832 startsess = rmatch.group("startsess") or "0"
790 endsess = rmatch.group("endsess") or startsess
833 endsess = rmatch.group("endsess") or startsess
791 startsess = int(startsess.replace("~","-"))
834 startsess = int(startsess.replace("~","-"))
792 endsess = int(endsess.replace("~","-"))
835 endsess = int(endsess.replace("~","-"))
793 assert endsess >= startsess, "start session must be earlier than end session"
836 assert endsess >= startsess, "start session must be earlier than end session"
794
837
795 if endsess == startsess:
838 if endsess == startsess:
796 yield (startsess, start, end)
839 yield (startsess, start, end)
797 continue
840 continue
798 # Multiple sessions in one range:
841 # Multiple sessions in one range:
799 yield (startsess, start, None)
842 yield (startsess, start, None)
800 for sess in range(startsess+1, endsess):
843 for sess in range(startsess+1, endsess):
801 yield (sess, 1, None)
844 yield (sess, 1, None)
802 yield (endsess, 1, end)
845 yield (endsess, 1, end)
803
846
804
847
805 def _format_lineno(session, line):
848 def _format_lineno(session, line):
806 """Helper function to format line numbers properly."""
849 """Helper function to format line numbers properly."""
807 if session == 0:
850 if session == 0:
808 return str(line)
851 return str(line)
809 return "%s#%s" % (session, line)
852 return "%s#%s" % (session, line)
810
853
811
854
@@ -1,280 +1,281 b''
1 """Magic functions for running cells in various scripts."""
1 """Magic functions for running cells in various scripts."""
2 from __future__ import print_function
2 from __future__ import print_function
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import errno
16 import errno
17 import os
17 import os
18 import sys
18 import sys
19 import signal
19 import signal
20 import time
20 import time
21 from subprocess import Popen, PIPE
21 from subprocess import Popen, PIPE
22 import atexit
22 import atexit
23
23
24 # Our own packages
24 # Our own packages
25 from IPython.config.configurable import Configurable
25 from IPython.config.configurable import Configurable
26 from IPython.core import magic_arguments
26 from IPython.core import magic_arguments
27 from IPython.core.magic import (
27 from IPython.core.magic import (
28 Magics, magics_class, line_magic, cell_magic
28 Magics, magics_class, line_magic, cell_magic
29 )
29 )
30 from IPython.lib.backgroundjobs import BackgroundJobManager
30 from IPython.lib.backgroundjobs import BackgroundJobManager
31 from IPython.utils import py3compat
31 from IPython.utils import py3compat
32 from IPython.utils.process import arg_split
32 from IPython.utils.process import arg_split
33 from IPython.utils.traitlets import List, Dict
33 from IPython.utils.traitlets import List, Dict
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Magic implementation classes
36 # Magic implementation classes
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 def script_args(f):
39 def script_args(f):
40 """single decorator for adding script args"""
40 """single decorator for adding script args"""
41 args = [
41 args = [
42 magic_arguments.argument(
42 magic_arguments.argument(
43 '--out', type=str,
43 '--out', type=str,
44 help="""The variable in which to store stdout from the script.
44 help="""The variable in which to store stdout from the script.
45 If the script is backgrounded, this will be the stdout *pipe*,
45 If the script is backgrounded, this will be the stdout *pipe*,
46 instead of the stderr text itself.
46 instead of the stderr text itself.
47 """
47 """
48 ),
48 ),
49 magic_arguments.argument(
49 magic_arguments.argument(
50 '--err', type=str,
50 '--err', type=str,
51 help="""The variable in which to store stderr from the script.
51 help="""The variable in which to store stderr from the script.
52 If the script is backgrounded, this will be the stderr *pipe*,
52 If the script is backgrounded, this will be the stderr *pipe*,
53 instead of the stderr text itself.
53 instead of the stderr text itself.
54 """
54 """
55 ),
55 ),
56 magic_arguments.argument(
56 magic_arguments.argument(
57 '--bg', action="store_true",
57 '--bg', action="store_true",
58 help="""Whether to run the script in the background.
58 help="""Whether to run the script in the background.
59 If given, the only way to see the output of the command is
59 If given, the only way to see the output of the command is
60 with --out/err.
60 with --out/err.
61 """
61 """
62 ),
62 ),
63 magic_arguments.argument(
63 magic_arguments.argument(
64 '--proc', type=str,
64 '--proc', type=str,
65 help="""The variable in which to store Popen instance.
65 help="""The variable in which to store Popen instance.
66 This is used only when --bg option is given.
66 This is used only when --bg option is given.
67 """
67 """
68 ),
68 ),
69 ]
69 ]
70 for arg in args:
70 for arg in args:
71 f = arg(f)
71 f = arg(f)
72 return f
72 return f
73
73
74 @magics_class
74 @magics_class
75 class ScriptMagics(Magics):
75 class ScriptMagics(Magics):
76 """Magics for talking to scripts
76 """Magics for talking to scripts
77
77
78 This defines a base `%%script` cell magic for running a cell
78 This defines a base `%%script` cell magic for running a cell
79 with a program in a subprocess, and registers a few top-level
79 with a program in a subprocess, and registers a few top-level
80 magics that call %%script with common interpreters.
80 magics that call %%script with common interpreters.
81 """
81 """
82 script_magics = List(config=True,
82 script_magics = List(config=True,
83 help="""Extra script cell magics to define
83 help="""Extra script cell magics to define
84
84
85 This generates simple wrappers of `%%script foo` as `%%foo`.
85 This generates simple wrappers of `%%script foo` as `%%foo`.
86
86
87 If you want to add script magics that aren't on your path,
87 If you want to add script magics that aren't on your path,
88 specify them in script_paths
88 specify them in script_paths
89 """,
89 """,
90 )
90 )
91 def _script_magics_default(self):
91 def _script_magics_default(self):
92 """default to a common list of programs"""
92 """default to a common list of programs"""
93
93
94 defaults = [
94 defaults = [
95 'sh',
95 'sh',
96 'bash',
96 'bash',
97 'perl',
97 'perl',
98 'ruby',
98 'ruby',
99 'python',
99 'python',
100 'python2',
100 'python3',
101 'python3',
101 'pypy',
102 'pypy',
102 ]
103 ]
103 if os.name == 'nt':
104 if os.name == 'nt':
104 defaults.extend([
105 defaults.extend([
105 'cmd',
106 'cmd',
106 'powershell',
107 'powershell',
107 ])
108 ])
108
109
109 return defaults
110 return defaults
110
111
111 script_paths = Dict(config=True,
112 script_paths = Dict(config=True,
112 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
113 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
113
114
114 Only necessary for items in script_magics where the default path will not
115 Only necessary for items in script_magics where the default path will not
115 find the right interpreter.
116 find the right interpreter.
116 """
117 """
117 )
118 )
118
119
119 def __init__(self, shell=None):
120 def __init__(self, shell=None):
120 super(ScriptMagics, self).__init__(shell=shell)
121 super(ScriptMagics, self).__init__(shell=shell)
121 self._generate_script_magics()
122 self._generate_script_magics()
122 self.job_manager = BackgroundJobManager()
123 self.job_manager = BackgroundJobManager()
123 self.bg_processes = []
124 self.bg_processes = []
124 atexit.register(self.kill_bg_processes)
125 atexit.register(self.kill_bg_processes)
125
126
126 def __del__(self):
127 def __del__(self):
127 self.kill_bg_processes()
128 self.kill_bg_processes()
128
129
129 def _generate_script_magics(self):
130 def _generate_script_magics(self):
130 cell_magics = self.magics['cell']
131 cell_magics = self.magics['cell']
131 for name in self.script_magics:
132 for name in self.script_magics:
132 cell_magics[name] = self._make_script_magic(name)
133 cell_magics[name] = self._make_script_magic(name)
133
134
134 def _make_script_magic(self, name):
135 def _make_script_magic(self, name):
135 """make a named magic, that calls %%script with a particular program"""
136 """make a named magic, that calls %%script with a particular program"""
136 # expand to explicit path if necessary:
137 # expand to explicit path if necessary:
137 script = self.script_paths.get(name, name)
138 script = self.script_paths.get(name, name)
138
139
139 @magic_arguments.magic_arguments()
140 @magic_arguments.magic_arguments()
140 @script_args
141 @script_args
141 def named_script_magic(line, cell):
142 def named_script_magic(line, cell):
142 # if line, add it as cl-flags
143 # if line, add it as cl-flags
143 if line:
144 if line:
144 line = "%s %s" % (script, line)
145 line = "%s %s" % (script, line)
145 else:
146 else:
146 line = script
147 line = script
147 return self.shebang(line, cell)
148 return self.shebang(line, cell)
148
149
149 # write a basic docstring:
150 # write a basic docstring:
150 named_script_magic.__doc__ = \
151 named_script_magic.__doc__ = \
151 """%%{name} script magic
152 """%%{name} script magic
152
153
153 Run cells with {script} in a subprocess.
154 Run cells with {script} in a subprocess.
154
155
155 This is a shortcut for `%%script {script}`
156 This is a shortcut for `%%script {script}`
156 """.format(**locals())
157 """.format(**locals())
157
158
158 return named_script_magic
159 return named_script_magic
159
160
160 @magic_arguments.magic_arguments()
161 @magic_arguments.magic_arguments()
161 @script_args
162 @script_args
162 @cell_magic("script")
163 @cell_magic("script")
163 def shebang(self, line, cell):
164 def shebang(self, line, cell):
164 """Run a cell via a shell command
165 """Run a cell via a shell command
165
166
166 The `%%script` line is like the #! line of script,
167 The `%%script` line is like the #! line of script,
167 specifying a program (bash, perl, ruby, etc.) with which to run.
168 specifying a program (bash, perl, ruby, etc.) with which to run.
168
169
169 The rest of the cell is run by that program.
170 The rest of the cell is run by that program.
170
171
171 Examples
172 Examples
172 --------
173 --------
173 ::
174 ::
174
175
175 In [1]: %%script bash
176 In [1]: %%script bash
176 ...: for i in 1 2 3; do
177 ...: for i in 1 2 3; do
177 ...: echo $i
178 ...: echo $i
178 ...: done
179 ...: done
179 1
180 1
180 2
181 2
181 3
182 3
182 """
183 """
183 argv = arg_split(line, posix = not sys.platform.startswith('win'))
184 argv = arg_split(line, posix = not sys.platform.startswith('win'))
184 args, cmd = self.shebang.parser.parse_known_args(argv)
185 args, cmd = self.shebang.parser.parse_known_args(argv)
185
186
186 try:
187 try:
187 p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
188 p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
188 except OSError as e:
189 except OSError as e:
189 if e.errno == errno.ENOENT:
190 if e.errno == errno.ENOENT:
190 print("Couldn't find program: %r" % cmd[0])
191 print("Couldn't find program: %r" % cmd[0])
191 return
192 return
192 else:
193 else:
193 raise
194 raise
194
195
195 cell = cell.encode('utf8', 'replace')
196 cell = cell.encode('utf8', 'replace')
196 if args.bg:
197 if args.bg:
197 self.bg_processes.append(p)
198 self.bg_processes.append(p)
198 self._gc_bg_processes()
199 self._gc_bg_processes()
199 if args.out:
200 if args.out:
200 self.shell.user_ns[args.out] = p.stdout
201 self.shell.user_ns[args.out] = p.stdout
201 if args.err:
202 if args.err:
202 self.shell.user_ns[args.err] = p.stderr
203 self.shell.user_ns[args.err] = p.stderr
203 self.job_manager.new(self._run_script, p, cell, daemon=True)
204 self.job_manager.new(self._run_script, p, cell, daemon=True)
204 if args.proc:
205 if args.proc:
205 self.shell.user_ns[args.proc] = p
206 self.shell.user_ns[args.proc] = p
206 return
207 return
207
208
208 try:
209 try:
209 out, err = p.communicate(cell)
210 out, err = p.communicate(cell)
210 except KeyboardInterrupt:
211 except KeyboardInterrupt:
211 try:
212 try:
212 p.send_signal(signal.SIGINT)
213 p.send_signal(signal.SIGINT)
213 time.sleep(0.1)
214 time.sleep(0.1)
214 if p.poll() is not None:
215 if p.poll() is not None:
215 print("Process is interrupted.")
216 print("Process is interrupted.")
216 return
217 return
217 p.terminate()
218 p.terminate()
218 time.sleep(0.1)
219 time.sleep(0.1)
219 if p.poll() is not None:
220 if p.poll() is not None:
220 print("Process is terminated.")
221 print("Process is terminated.")
221 return
222 return
222 p.kill()
223 p.kill()
223 print("Process is killed.")
224 print("Process is killed.")
224 except OSError:
225 except OSError:
225 pass
226 pass
226 except Exception as e:
227 except Exception as e:
227 print("Error while terminating subprocess (pid=%i): %s" \
228 print("Error while terminating subprocess (pid=%i): %s" \
228 % (p.pid, e))
229 % (p.pid, e))
229 return
230 return
230 out = py3compat.bytes_to_str(out)
231 out = py3compat.bytes_to_str(out)
231 err = py3compat.bytes_to_str(err)
232 err = py3compat.bytes_to_str(err)
232 if args.out:
233 if args.out:
233 self.shell.user_ns[args.out] = out
234 self.shell.user_ns[args.out] = out
234 else:
235 else:
235 sys.stdout.write(out)
236 sys.stdout.write(out)
236 sys.stdout.flush()
237 sys.stdout.flush()
237 if args.err:
238 if args.err:
238 self.shell.user_ns[args.err] = err
239 self.shell.user_ns[args.err] = err
239 else:
240 else:
240 sys.stderr.write(err)
241 sys.stderr.write(err)
241 sys.stderr.flush()
242 sys.stderr.flush()
242
243
243 def _run_script(self, p, cell):
244 def _run_script(self, p, cell):
244 """callback for running the script in the background"""
245 """callback for running the script in the background"""
245 p.stdin.write(cell)
246 p.stdin.write(cell)
246 p.stdin.close()
247 p.stdin.close()
247 p.wait()
248 p.wait()
248
249
249 @line_magic("killbgscripts")
250 @line_magic("killbgscripts")
250 def killbgscripts(self, _nouse_=''):
251 def killbgscripts(self, _nouse_=''):
251 """Kill all BG processes started by %%script and its family."""
252 """Kill all BG processes started by %%script and its family."""
252 self.kill_bg_processes()
253 self.kill_bg_processes()
253 print("All background processes were killed.")
254 print("All background processes were killed.")
254
255
255 def kill_bg_processes(self):
256 def kill_bg_processes(self):
256 """Kill all BG processes which are still running."""
257 """Kill all BG processes which are still running."""
257 for p in self.bg_processes:
258 for p in self.bg_processes:
258 if p.poll() is None:
259 if p.poll() is None:
259 try:
260 try:
260 p.send_signal(signal.SIGINT)
261 p.send_signal(signal.SIGINT)
261 except:
262 except:
262 pass
263 pass
263 time.sleep(0.1)
264 time.sleep(0.1)
264 for p in self.bg_processes:
265 for p in self.bg_processes:
265 if p.poll() is None:
266 if p.poll() is None:
266 try:
267 try:
267 p.terminate()
268 p.terminate()
268 except:
269 except:
269 pass
270 pass
270 time.sleep(0.1)
271 time.sleep(0.1)
271 for p in self.bg_processes:
272 for p in self.bg_processes:
272 if p.poll() is None:
273 if p.poll() is None:
273 try:
274 try:
274 p.kill()
275 p.kill()
275 except:
276 except:
276 pass
277 pass
277 self._gc_bg_processes()
278 self._gc_bg_processes()
278
279
279 def _gc_bg_processes(self):
280 def _gc_bg_processes(self):
280 self.bg_processes = [p for p in self.bg_processes if p.poll() is None]
281 self.bg_processes = [p for p in self.bg_processes if p.poll() is None]
@@ -1,376 +1,382 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2009 The IPython Development Team
13 # Copyright (C) 2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import sys
23 import sys
24 from io import BytesIO
24 from io import BytesIO
25
25
26 from IPython.core.display import _pngxy
26 from IPython.core.display import _pngxy
27 from IPython.utils.decorators import flag_calls
27 from IPython.utils.decorators import flag_calls
28 from IPython.utils import py3compat
28 from IPython.utils import py3compat
29
29
30 # If user specifies a GUI, that dictates the backend, otherwise we read the
30 # If user specifies a GUI, that dictates the backend, otherwise we read the
31 # user's mpl default from the mpl rc structure
31 # user's mpl default from the mpl rc structure
32 backends = {'tk': 'TkAgg',
32 backends = {'tk': 'TkAgg',
33 'gtk': 'GTKAgg',
33 'gtk': 'GTKAgg',
34 'gtk3': 'GTK3Agg',
34 'gtk3': 'GTK3Agg',
35 'wx': 'WXAgg',
35 'wx': 'WXAgg',
36 'qt': 'Qt4Agg', # qt3 not supported
36 'qt': 'Qt4Agg', # qt3 not supported
37 'qt4': 'Qt4Agg',
37 'qt4': 'Qt4Agg',
38 'osx': 'MacOSX',
38 'osx': 'MacOSX',
39 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
39 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
40
40
41 # We also need a reverse backends2guis mapping that will properly choose which
41 # We also need a reverse backends2guis mapping that will properly choose which
42 # GUI support to activate based on the desired matplotlib backend. For the
42 # GUI support to activate based on the desired matplotlib backend. For the
43 # most part it's just a reverse of the above dict, but we also need to add a
43 # most part it's just a reverse of the above dict, but we also need to add a
44 # few others that map to the same GUI manually:
44 # few others that map to the same GUI manually:
45 backend2gui = dict(zip(backends.values(), backends.keys()))
45 backend2gui = dict(zip(backends.values(), backends.keys()))
46 # Our tests expect backend2gui to just return 'qt'
46 # Our tests expect backend2gui to just return 'qt'
47 backend2gui['Qt4Agg'] = 'qt'
47 backend2gui['Qt4Agg'] = 'qt'
48 # In the reverse mapping, there are a few extra valid matplotlib backends that
48 # In the reverse mapping, there are a few extra valid matplotlib backends that
49 # map to the same GUI support
49 # map to the same GUI support
50 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
50 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
51 backend2gui['GTK3Cairo'] = 'gtk3'
51 backend2gui['GTK3Cairo'] = 'gtk3'
52 backend2gui['WX'] = 'wx'
52 backend2gui['WX'] = 'wx'
53 backend2gui['CocoaAgg'] = 'osx'
53 backend2gui['CocoaAgg'] = 'osx'
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Matplotlib utilities
56 # Matplotlib utilities
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59
59
60 def getfigs(*fig_nums):
60 def getfigs(*fig_nums):
61 """Get a list of matplotlib figures by figure numbers.
61 """Get a list of matplotlib figures by figure numbers.
62
62
63 If no arguments are given, all available figures are returned. If the
63 If no arguments are given, all available figures are returned. If the
64 argument list contains references to invalid figures, a warning is printed
64 argument list contains references to invalid figures, a warning is printed
65 but the function continues pasting further figures.
65 but the function continues pasting further figures.
66
66
67 Parameters
67 Parameters
68 ----------
68 ----------
69 figs : tuple
69 figs : tuple
70 A tuple of ints giving the figure numbers of the figures to return.
70 A tuple of ints giving the figure numbers of the figures to return.
71 """
71 """
72 from matplotlib._pylab_helpers import Gcf
72 from matplotlib._pylab_helpers import Gcf
73 if not fig_nums:
73 if not fig_nums:
74 fig_managers = Gcf.get_all_fig_managers()
74 fig_managers = Gcf.get_all_fig_managers()
75 return [fm.canvas.figure for fm in fig_managers]
75 return [fm.canvas.figure for fm in fig_managers]
76 else:
76 else:
77 figs = []
77 figs = []
78 for num in fig_nums:
78 for num in fig_nums:
79 f = Gcf.figs.get(num)
79 f = Gcf.figs.get(num)
80 if f is None:
80 if f is None:
81 print('Warning: figure %s not available.' % num)
81 print('Warning: figure %s not available.' % num)
82 else:
82 else:
83 figs.append(f.canvas.figure)
83 figs.append(f.canvas.figure)
84 return figs
84 return figs
85
85
86
86
87 def figsize(sizex, sizey):
87 def figsize(sizex, sizey):
88 """Set the default figure size to be [sizex, sizey].
88 """Set the default figure size to be [sizex, sizey].
89
89
90 This is just an easy to remember, convenience wrapper that sets::
90 This is just an easy to remember, convenience wrapper that sets::
91
91
92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
93 """
93 """
94 import matplotlib
94 import matplotlib
95 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
95 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
96
96
97
97
98 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
98 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
99 """Print a figure to an image, and return the resulting bytes
99 """Print a figure to an image, and return the resulting file data
100
101 Returned data will be bytes unless ``fmt='svg'``,
102 in which case it will be unicode.
100
103
101 Any keyword args are passed to fig.canvas.print_figure,
104 Any keyword args are passed to fig.canvas.print_figure,
102 such as ``quality`` or ``bbox_inches``.
105 such as ``quality`` or ``bbox_inches``.
103 """
106 """
104 from matplotlib import rcParams
107 from matplotlib import rcParams
105 # When there's an empty figure, we shouldn't return anything, otherwise we
108 # When there's an empty figure, we shouldn't return anything, otherwise we
106 # get big blank areas in the qt console.
109 # get big blank areas in the qt console.
107 if not fig.axes and not fig.lines:
110 if not fig.axes and not fig.lines:
108 return
111 return
109
112
110 dpi = rcParams['savefig.dpi']
113 dpi = rcParams['savefig.dpi']
111 if fmt == 'retina':
114 if fmt == 'retina':
112 dpi = dpi * 2
115 dpi = dpi * 2
113 fmt = 'png'
116 fmt = 'png'
114
117
115 # build keyword args
118 # build keyword args
116 kw = dict(
119 kw = dict(
117 format=fmt,
120 format=fmt,
118 fc=fig.get_facecolor(),
121 fc=fig.get_facecolor(),
119 ec=fig.get_edgecolor(),
122 ec=fig.get_edgecolor(),
120 dpi=dpi,
123 dpi=dpi,
121 bbox_inches=bbox_inches,
124 bbox_inches=bbox_inches,
122 )
125 )
123 # **kwargs get higher priority
126 # **kwargs get higher priority
124 kw.update(kwargs)
127 kw.update(kwargs)
125
128
126 bytes_io = BytesIO()
129 bytes_io = BytesIO()
127 fig.canvas.print_figure(bytes_io, **kw)
130 fig.canvas.print_figure(bytes_io, **kw)
128 return bytes_io.getvalue()
131 data = bytes_io.getvalue()
132 if fmt == 'svg':
133 data = data.decode('utf-8')
134 return data
129
135
130 def retina_figure(fig, **kwargs):
136 def retina_figure(fig, **kwargs):
131 """format a figure as a pixel-doubled (retina) PNG"""
137 """format a figure as a pixel-doubled (retina) PNG"""
132 pngdata = print_figure(fig, fmt='retina', **kwargs)
138 pngdata = print_figure(fig, fmt='retina', **kwargs)
133 w, h = _pngxy(pngdata)
139 w, h = _pngxy(pngdata)
134 metadata = dict(width=w//2, height=h//2)
140 metadata = dict(width=w//2, height=h//2)
135 return pngdata, metadata
141 return pngdata, metadata
136
142
137 # We need a little factory function here to create the closure where
143 # We need a little factory function here to create the closure where
138 # safe_execfile can live.
144 # safe_execfile can live.
139 def mpl_runner(safe_execfile):
145 def mpl_runner(safe_execfile):
140 """Factory to return a matplotlib-enabled runner for %run.
146 """Factory to return a matplotlib-enabled runner for %run.
141
147
142 Parameters
148 Parameters
143 ----------
149 ----------
144 safe_execfile : function
150 safe_execfile : function
145 This must be a function with the same interface as the
151 This must be a function with the same interface as the
146 :meth:`safe_execfile` method of IPython.
152 :meth:`safe_execfile` method of IPython.
147
153
148 Returns
154 Returns
149 -------
155 -------
150 A function suitable for use as the ``runner`` argument of the %run magic
156 A function suitable for use as the ``runner`` argument of the %run magic
151 function.
157 function.
152 """
158 """
153
159
154 def mpl_execfile(fname,*where,**kw):
160 def mpl_execfile(fname,*where,**kw):
155 """matplotlib-aware wrapper around safe_execfile.
161 """matplotlib-aware wrapper around safe_execfile.
156
162
157 Its interface is identical to that of the :func:`execfile` builtin.
163 Its interface is identical to that of the :func:`execfile` builtin.
158
164
159 This is ultimately a call to execfile(), but wrapped in safeties to
165 This is ultimately a call to execfile(), but wrapped in safeties to
160 properly handle interactive rendering."""
166 properly handle interactive rendering."""
161
167
162 import matplotlib
168 import matplotlib
163 import matplotlib.pylab as pylab
169 import matplotlib.pylab as pylab
164
170
165 #print '*** Matplotlib runner ***' # dbg
171 #print '*** Matplotlib runner ***' # dbg
166 # turn off rendering until end of script
172 # turn off rendering until end of script
167 is_interactive = matplotlib.rcParams['interactive']
173 is_interactive = matplotlib.rcParams['interactive']
168 matplotlib.interactive(False)
174 matplotlib.interactive(False)
169 safe_execfile(fname,*where,**kw)
175 safe_execfile(fname,*where,**kw)
170 matplotlib.interactive(is_interactive)
176 matplotlib.interactive(is_interactive)
171 # make rendering call now, if the user tried to do it
177 # make rendering call now, if the user tried to do it
172 if pylab.draw_if_interactive.called:
178 if pylab.draw_if_interactive.called:
173 pylab.draw()
179 pylab.draw()
174 pylab.draw_if_interactive.called = False
180 pylab.draw_if_interactive.called = False
175
181
176 return mpl_execfile
182 return mpl_execfile
177
183
178
184
179 def select_figure_formats(shell, formats, **kwargs):
185 def select_figure_formats(shell, formats, **kwargs):
180 """Select figure formats for the inline backend.
186 """Select figure formats for the inline backend.
181
187
182 Parameters
188 Parameters
183 ==========
189 ==========
184 shell : InteractiveShell
190 shell : InteractiveShell
185 The main IPython instance.
191 The main IPython instance.
186 formats : str or set
192 formats : str or set
187 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
193 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
188 **kwargs : any
194 **kwargs : any
189 Extra keyword arguments to be passed to fig.canvas.print_figure.
195 Extra keyword arguments to be passed to fig.canvas.print_figure.
190 """
196 """
191 from matplotlib.figure import Figure
197 from matplotlib.figure import Figure
192 from IPython.kernel.zmq.pylab import backend_inline
198 from IPython.kernel.zmq.pylab import backend_inline
193
199
194 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
200 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
195 png_formatter = shell.display_formatter.formatters['image/png']
201 png_formatter = shell.display_formatter.formatters['image/png']
196 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
202 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
197 pdf_formatter = shell.display_formatter.formatters['application/pdf']
203 pdf_formatter = shell.display_formatter.formatters['application/pdf']
198
204
199 if isinstance(formats, py3compat.string_types):
205 if isinstance(formats, py3compat.string_types):
200 formats = {formats}
206 formats = {formats}
201 # cast in case of list / tuple
207 # cast in case of list / tuple
202 formats = set(formats)
208 formats = set(formats)
203
209
204 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
210 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
205
211
206 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
212 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
207 bad = formats.difference(supported)
213 bad = formats.difference(supported)
208 if bad:
214 if bad:
209 bs = "%s" % ','.join([repr(f) for f in bad])
215 bs = "%s" % ','.join([repr(f) for f in bad])
210 gs = "%s" % ','.join([repr(f) for f in supported])
216 gs = "%s" % ','.join([repr(f) for f in supported])
211 raise ValueError("supported formats are: %s not %s" % (gs, bs))
217 raise ValueError("supported formats are: %s not %s" % (gs, bs))
212
218
213 if 'png' in formats:
219 if 'png' in formats:
214 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
220 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
215 if 'retina' in formats or 'png2x' in formats:
221 if 'retina' in formats or 'png2x' in formats:
216 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
222 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
217 if 'jpg' in formats or 'jpeg' in formats:
223 if 'jpg' in formats or 'jpeg' in formats:
218 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
224 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
219 if 'svg' in formats:
225 if 'svg' in formats:
220 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
226 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
221 if 'pdf' in formats:
227 if 'pdf' in formats:
222 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
228 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
223
229
224 #-----------------------------------------------------------------------------
230 #-----------------------------------------------------------------------------
225 # Code for initializing matplotlib and importing pylab
231 # Code for initializing matplotlib and importing pylab
226 #-----------------------------------------------------------------------------
232 #-----------------------------------------------------------------------------
227
233
228
234
229 def find_gui_and_backend(gui=None, gui_select=None):
235 def find_gui_and_backend(gui=None, gui_select=None):
230 """Given a gui string return the gui and mpl backend.
236 """Given a gui string return the gui and mpl backend.
231
237
232 Parameters
238 Parameters
233 ----------
239 ----------
234 gui : str
240 gui : str
235 Can be one of ('tk','gtk','wx','qt','qt4','inline').
241 Can be one of ('tk','gtk','wx','qt','qt4','inline').
236 gui_select : str
242 gui_select : str
237 Can be one of ('tk','gtk','wx','qt','qt4','inline').
243 Can be one of ('tk','gtk','wx','qt','qt4','inline').
238 This is any gui already selected by the shell.
244 This is any gui already selected by the shell.
239
245
240 Returns
246 Returns
241 -------
247 -------
242 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
248 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
243 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
249 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
244 """
250 """
245
251
246 import matplotlib
252 import matplotlib
247
253
248 if gui and gui != 'auto':
254 if gui and gui != 'auto':
249 # select backend based on requested gui
255 # select backend based on requested gui
250 backend = backends[gui]
256 backend = backends[gui]
251 else:
257 else:
252 # We need to read the backend from the original data structure, *not*
258 # We need to read the backend from the original data structure, *not*
253 # from mpl.rcParams, since a prior invocation of %matplotlib may have
259 # from mpl.rcParams, since a prior invocation of %matplotlib may have
254 # overwritten that.
260 # overwritten that.
255 # WARNING: this assumes matplotlib 1.1 or newer!!
261 # WARNING: this assumes matplotlib 1.1 or newer!!
256 backend = matplotlib.rcParamsOrig['backend']
262 backend = matplotlib.rcParamsOrig['backend']
257 # In this case, we need to find what the appropriate gui selection call
263 # In this case, we need to find what the appropriate gui selection call
258 # should be for IPython, so we can activate inputhook accordingly
264 # should be for IPython, so we can activate inputhook accordingly
259 gui = backend2gui.get(backend, None)
265 gui = backend2gui.get(backend, None)
260
266
261 # If we have already had a gui active, we need it and inline are the
267 # If we have already had a gui active, we need it and inline are the
262 # ones allowed.
268 # ones allowed.
263 if gui_select and gui != gui_select:
269 if gui_select and gui != gui_select:
264 gui = gui_select
270 gui = gui_select
265 backend = backends[gui]
271 backend = backends[gui]
266
272
267 return gui, backend
273 return gui, backend
268
274
269
275
270 def activate_matplotlib(backend):
276 def activate_matplotlib(backend):
271 """Activate the given backend and set interactive to True."""
277 """Activate the given backend and set interactive to True."""
272
278
273 import matplotlib
279 import matplotlib
274 matplotlib.interactive(True)
280 matplotlib.interactive(True)
275
281
276 # Matplotlib had a bug where even switch_backend could not force
282 # Matplotlib had a bug where even switch_backend could not force
277 # the rcParam to update. This needs to be set *before* the module
283 # the rcParam to update. This needs to be set *before* the module
278 # magic of switch_backend().
284 # magic of switch_backend().
279 matplotlib.rcParams['backend'] = backend
285 matplotlib.rcParams['backend'] = backend
280
286
281 import matplotlib.pyplot
287 import matplotlib.pyplot
282 matplotlib.pyplot.switch_backend(backend)
288 matplotlib.pyplot.switch_backend(backend)
283
289
284 # This must be imported last in the matplotlib series, after
290 # This must be imported last in the matplotlib series, after
285 # backend/interactivity choices have been made
291 # backend/interactivity choices have been made
286 import matplotlib.pylab as pylab
292 import matplotlib.pylab as pylab
287
293
288 pylab.show._needmain = False
294 pylab.show._needmain = False
289 # We need to detect at runtime whether show() is called by the user.
295 # We need to detect at runtime whether show() is called by the user.
290 # For this, we wrap it into a decorator which adds a 'called' flag.
296 # For this, we wrap it into a decorator which adds a 'called' flag.
291 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
297 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
292
298
293
299
294 def import_pylab(user_ns, import_all=True):
300 def import_pylab(user_ns, import_all=True):
295 """Populate the namespace with pylab-related values.
301 """Populate the namespace with pylab-related values.
296
302
297 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
303 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
298
304
299 Also imports a few names from IPython (figsize, display, getfigs)
305 Also imports a few names from IPython (figsize, display, getfigs)
300
306
301 """
307 """
302
308
303 # Import numpy as np/pyplot as plt are conventions we're trying to
309 # Import numpy as np/pyplot as plt are conventions we're trying to
304 # somewhat standardize on. Making them available to users by default
310 # somewhat standardize on. Making them available to users by default
305 # will greatly help this.
311 # will greatly help this.
306 s = ("import numpy\n"
312 s = ("import numpy\n"
307 "import matplotlib\n"
313 "import matplotlib\n"
308 "from matplotlib import pylab, mlab, pyplot\n"
314 "from matplotlib import pylab, mlab, pyplot\n"
309 "np = numpy\n"
315 "np = numpy\n"
310 "plt = pyplot\n"
316 "plt = pyplot\n"
311 )
317 )
312 exec(s, user_ns)
318 exec(s, user_ns)
313
319
314 if import_all:
320 if import_all:
315 s = ("from matplotlib.pylab import *\n"
321 s = ("from matplotlib.pylab import *\n"
316 "from numpy import *\n")
322 "from numpy import *\n")
317 exec(s, user_ns)
323 exec(s, user_ns)
318
324
319 # IPython symbols to add
325 # IPython symbols to add
320 user_ns['figsize'] = figsize
326 user_ns['figsize'] = figsize
321 from IPython.core.display import display
327 from IPython.core.display import display
322 # Add display and getfigs to the user's namespace
328 # Add display and getfigs to the user's namespace
323 user_ns['display'] = display
329 user_ns['display'] = display
324 user_ns['getfigs'] = getfigs
330 user_ns['getfigs'] = getfigs
325
331
326
332
327 def configure_inline_support(shell, backend):
333 def configure_inline_support(shell, backend):
328 """Configure an IPython shell object for matplotlib use.
334 """Configure an IPython shell object for matplotlib use.
329
335
330 Parameters
336 Parameters
331 ----------
337 ----------
332 shell : InteractiveShell instance
338 shell : InteractiveShell instance
333
339
334 backend : matplotlib backend
340 backend : matplotlib backend
335 """
341 """
336 # If using our svg payload backend, register the post-execution
342 # If using our svg payload backend, register the post-execution
337 # function that will pick up the results for display. This can only be
343 # function that will pick up the results for display. This can only be
338 # done with access to the real shell object.
344 # done with access to the real shell object.
339
345
340 # Note: if we can't load the inline backend, then there's no point
346 # Note: if we can't load the inline backend, then there's no point
341 # continuing (such as in terminal-only shells in environments without
347 # continuing (such as in terminal-only shells in environments without
342 # zeromq available).
348 # zeromq available).
343 try:
349 try:
344 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
350 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
345 except ImportError:
351 except ImportError:
346 return
352 return
347 from matplotlib import pyplot
353 from matplotlib import pyplot
348
354
349 cfg = InlineBackend.instance(parent=shell)
355 cfg = InlineBackend.instance(parent=shell)
350 cfg.shell = shell
356 cfg.shell = shell
351 if cfg not in shell.configurables:
357 if cfg not in shell.configurables:
352 shell.configurables.append(cfg)
358 shell.configurables.append(cfg)
353
359
354 if backend == backends['inline']:
360 if backend == backends['inline']:
355 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
361 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
356 shell.events.register('post_execute', flush_figures)
362 shell.events.register('post_execute', flush_figures)
357
363
358 # Save rcParams that will be overwrittern
364 # Save rcParams that will be overwrittern
359 shell._saved_rcParams = dict()
365 shell._saved_rcParams = dict()
360 for k in cfg.rc:
366 for k in cfg.rc:
361 shell._saved_rcParams[k] = pyplot.rcParams[k]
367 shell._saved_rcParams[k] = pyplot.rcParams[k]
362 # load inline_rc
368 # load inline_rc
363 pyplot.rcParams.update(cfg.rc)
369 pyplot.rcParams.update(cfg.rc)
364 else:
370 else:
365 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
371 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
366 try:
372 try:
367 shell.events.unregister('post_execute', flush_figures)
373 shell.events.unregister('post_execute', flush_figures)
368 except ValueError:
374 except ValueError:
369 pass
375 pass
370 if hasattr(shell, '_saved_rcParams'):
376 if hasattr(shell, '_saved_rcParams'):
371 pyplot.rcParams.update(shell._saved_rcParams)
377 pyplot.rcParams.update(shell._saved_rcParams)
372 del shell._saved_rcParams
378 del shell._saved_rcParams
373
379
374 # Setup the default figure format
380 # Setup the default figure format
375 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
381 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
376
382
@@ -1,148 +1,149 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Release data for the IPython project."""
2 """Release data for the IPython project."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2008, IPython Development Team.
5 # Copyright (c) 2008, IPython Development Team.
6 # Copyright (c) 2001, Fernando Perez <fernando.perez@colorado.edu>
6 # Copyright (c) 2001, Fernando Perez <fernando.perez@colorado.edu>
7 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
7 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
8 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
8 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
9 #
9 #
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11 #
11 #
12 # The full license is in the file COPYING.txt, distributed with this software.
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Name of the package for release purposes. This is the name which labels
15 # Name of the package for release purposes. This is the name which labels
16 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
16 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
17 name = 'ipython'
17 name = 'ipython'
18
18
19 # IPython version information. An empty _version_extra corresponds to a full
19 # IPython version information. An empty _version_extra corresponds to a full
20 # release. 'dev' as a _version_extra string means this is a development
20 # release. 'dev' as a _version_extra string means this is a development
21 # version
21 # version
22 _version_major = 2
22 _version_major = 2
23 _version_minor = 0
23 _version_minor = 0
24 _version_patch = 0
24 _version_patch = 0
25 _version_extra = 'dev'
25 _version_extra = 'dev'
26 # _version_extra = 'rc1'
26 # _version_extra = 'rc1'
27 # _version_extra = '' # Uncomment this for full releases
27 # _version_extra = '' # Uncomment this for full releases
28
28
29 codename = 'Work in Progress'
29 # release.codename is deprecated in 2.0, will be removed in 3.0
30 codename = ''
30
31
31 # Construct full version string from these.
32 # Construct full version string from these.
32 _ver = [_version_major, _version_minor, _version_patch]
33 _ver = [_version_major, _version_minor, _version_patch]
33
34
34 __version__ = '.'.join(map(str, _ver))
35 __version__ = '.'.join(map(str, _ver))
35 if _version_extra:
36 if _version_extra:
36 __version__ = __version__ + '-' + _version_extra
37 __version__ = __version__ + '-' + _version_extra
37
38
38 version = __version__ # backwards compatibility name
39 version = __version__ # backwards compatibility name
39 version_info = (_version_major, _version_minor, _version_patch, _version_extra)
40 version_info = (_version_major, _version_minor, _version_patch, _version_extra)
40
41
41 # Change this when incrementing the kernel protocol version
42 # Change this when incrementing the kernel protocol version
42 kernel_protocol_version_info = (4, 1)
43 kernel_protocol_version_info = (4, 1)
43
44
44 description = "IPython: Productive Interactive Computing"
45 description = "IPython: Productive Interactive Computing"
45
46
46 long_description = \
47 long_description = \
47 """
48 """
48 IPython provides a rich toolkit to help you make the most out of using Python
49 IPython provides a rich toolkit to help you make the most out of using Python
49 interactively. Its main components are:
50 interactively. Its main components are:
50
51
51 * Powerful interactive Python shells (terminal- and Qt-based).
52 * Powerful interactive Python shells (terminal- and Qt-based).
52 * A web-based interactive notebook environment with all shell features plus
53 * A web-based interactive notebook environment with all shell features plus
53 support for embedded figures, animations and rich media.
54 support for embedded figures, animations and rich media.
54 * Support for interactive data visualization and use of GUI toolkits.
55 * Support for interactive data visualization and use of GUI toolkits.
55 * Flexible, embeddable interpreters to load into your own projects.
56 * Flexible, embeddable interpreters to load into your own projects.
56 * A high-performance library for high level and interactive parallel computing
57 * A high-performance library for high level and interactive parallel computing
57 that works in multicore systems, clusters, supercomputing and cloud scenarios.
58 that works in multicore systems, clusters, supercomputing and cloud scenarios.
58
59
59 The enhanced interactive Python shells have the following main features:
60 The enhanced interactive Python shells have the following main features:
60
61
61 * Comprehensive object introspection.
62 * Comprehensive object introspection.
62
63
63 * Input history, persistent across sessions.
64 * Input history, persistent across sessions.
64
65
65 * Caching of output results during a session with automatically generated
66 * Caching of output results during a session with automatically generated
66 references.
67 references.
67
68
68 * Extensible tab completion, with support by default for completion of python
69 * Extensible tab completion, with support by default for completion of python
69 variables and keywords, filenames and function keywords.
70 variables and keywords, filenames and function keywords.
70
71
71 * Extensible system of 'magic' commands for controlling the environment and
72 * Extensible system of 'magic' commands for controlling the environment and
72 performing many tasks related either to IPython or the operating system.
73 performing many tasks related either to IPython or the operating system.
73
74
74 * A rich configuration system with easy switching between different setups
75 * A rich configuration system with easy switching between different setups
75 (simpler than changing $PYTHONSTARTUP environment variables every time).
76 (simpler than changing $PYTHONSTARTUP environment variables every time).
76
77
77 * Session logging and reloading.
78 * Session logging and reloading.
78
79
79 * Extensible syntax processing for special purpose situations.
80 * Extensible syntax processing for special purpose situations.
80
81
81 * Access to the system shell with user-extensible alias system.
82 * Access to the system shell with user-extensible alias system.
82
83
83 * Easily embeddable in other Python programs and GUIs.
84 * Easily embeddable in other Python programs and GUIs.
84
85
85 * Integrated access to the pdb debugger and the Python profiler.
86 * Integrated access to the pdb debugger and the Python profiler.
86
87
87 The parallel computing architecture has the following main features:
88 The parallel computing architecture has the following main features:
88
89
89 * Quickly parallelize Python code from an interactive Python/IPython session.
90 * Quickly parallelize Python code from an interactive Python/IPython session.
90
91
91 * A flexible and dynamic process model that be deployed on anything from
92 * A flexible and dynamic process model that be deployed on anything from
92 multicore workstations to supercomputers.
93 multicore workstations to supercomputers.
93
94
94 * An architecture that supports many different styles of parallelism, from
95 * An architecture that supports many different styles of parallelism, from
95 message passing to task farming.
96 message passing to task farming.
96
97
97 * Both blocking and fully asynchronous interfaces.
98 * Both blocking and fully asynchronous interfaces.
98
99
99 * High level APIs that enable many things to be parallelized in a few lines
100 * High level APIs that enable many things to be parallelized in a few lines
100 of code.
101 of code.
101
102
102 * Share live parallel jobs with other users securely.
103 * Share live parallel jobs with other users securely.
103
104
104 * Dynamically load balanced task farming system.
105 * Dynamically load balanced task farming system.
105
106
106 * Robust error handling in parallel code.
107 * Robust error handling in parallel code.
107
108
108 The latest development version is always available from IPython's `GitHub
109 The latest development version is always available from IPython's `GitHub
109 site <http://github.com/ipython>`_.
110 site <http://github.com/ipython>`_.
110 """
111 """
111
112
112 license = 'BSD'
113 license = 'BSD'
113
114
114 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
115 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
115 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
116 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
116 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
117 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
117 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
118 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
118 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
119 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
119 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com'),
120 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com'),
120 'Thomas' : ('Thomas A. Kluyver', 'takowl@gmail.com'),
121 'Thomas' : ('Thomas A. Kluyver', 'takowl@gmail.com'),
121 'Jorgen' : ('Jorgen Stenarson', 'jorgen.stenarson@bostream.nu'),
122 'Jorgen' : ('Jorgen Stenarson', 'jorgen.stenarson@bostream.nu'),
122 'Matthias' : ('Matthias Bussonnier', 'bussonniermatthias@gmail.com'),
123 'Matthias' : ('Matthias Bussonnier', 'bussonniermatthias@gmail.com'),
123 }
124 }
124
125
125 author = 'The IPython Development Team'
126 author = 'The IPython Development Team'
126
127
127 author_email = 'ipython-dev@scipy.org'
128 author_email = 'ipython-dev@scipy.org'
128
129
129 url = 'http://ipython.org'
130 url = 'http://ipython.org'
130
131
131 download_url = 'https://github.com/ipython/ipython/downloads'
132 download_url = 'https://github.com/ipython/ipython/downloads'
132
133
133 platforms = ['Linux','Mac OSX','Windows XP/Vista/7/8']
134 platforms = ['Linux','Mac OSX','Windows XP/Vista/7/8']
134
135
135 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed',
136 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed',
136 'Web-based computing', 'Qt console', 'Embedding']
137 'Web-based computing', 'Qt console', 'Embedding']
137
138
138 classifiers = [
139 classifiers = [
139 'Intended Audience :: Developers',
140 'Intended Audience :: Developers',
140 'Intended Audience :: Science/Research',
141 'Intended Audience :: Science/Research',
141 'License :: OSI Approved :: BSD License',
142 'License :: OSI Approved :: BSD License',
142 'Programming Language :: Python',
143 'Programming Language :: Python',
143 'Programming Language :: Python :: 2',
144 'Programming Language :: Python :: 2',
144 'Programming Language :: Python :: 2.7',
145 'Programming Language :: Python :: 2.7',
145 'Programming Language :: Python :: 3',
146 'Programming Language :: Python :: 3',
146 'Topic :: System :: Distributed Computing',
147 'Topic :: System :: Distributed Computing',
147 'Topic :: System :: Shells'
148 'Topic :: System :: Shells'
148 ]
149 ]
@@ -1,241 +1,241 b''
1 """Tests for pylab tools module.
1 """Tests for pylab tools module.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2011, the IPython Development Team.
4 # Copyright (c) 2011, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 from io import UnsupportedOperation, BytesIO
16 from io import UnsupportedOperation, BytesIO
17
17
18 import matplotlib
18 import matplotlib
19 matplotlib.use('Agg')
19 matplotlib.use('Agg')
20 from matplotlib.figure import Figure
20 from matplotlib.figure import Figure
21
21
22 from nose import SkipTest
22 from nose import SkipTest
23 import nose.tools as nt
23 import nose.tools as nt
24
24
25 from matplotlib import pyplot as plt
25 from matplotlib import pyplot as plt
26 import numpy as np
26 import numpy as np
27
27
28 # Our own imports
28 # Our own imports
29 from IPython.core.getipython import get_ipython
29 from IPython.core.getipython import get_ipython
30 from IPython.core.interactiveshell import InteractiveShell
30 from IPython.core.interactiveshell import InteractiveShell
31 from IPython.core.display import _PNG, _JPEG
31 from IPython.core.display import _PNG, _JPEG
32 from .. import pylabtools as pt
32 from .. import pylabtools as pt
33
33
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Globals and constants
37 # Globals and constants
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Local utilities
41 # Local utilities
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # Classes and functions
45 # Classes and functions
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 def test_figure_to_svg():
48 def test_figure_to_svg():
49 # simple empty-figure test
49 # simple empty-figure test
50 fig = plt.figure()
50 fig = plt.figure()
51 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
51 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
52
52
53 plt.close('all')
53 plt.close('all')
54
54
55 # simple check for at least svg-looking output
55 # simple check for at least svg-looking output
56 fig = plt.figure()
56 fig = plt.figure()
57 ax = fig.add_subplot(1,1,1)
57 ax = fig.add_subplot(1,1,1)
58 ax.plot([1,2,3])
58 ax.plot([1,2,3])
59 plt.draw()
59 plt.draw()
60 svg = pt.print_figure(fig, 'svg')[:100].lower()
60 svg = pt.print_figure(fig, 'svg')[:100].lower()
61 nt.assert_in(b'doctype svg', svg)
61 nt.assert_in(u'doctype svg', svg)
62
62
63 def _check_pil_jpeg_bytes():
63 def _check_pil_jpeg_bytes():
64 """Skip if PIL can't write JPEGs to BytesIO objects"""
64 """Skip if PIL can't write JPEGs to BytesIO objects"""
65 # PIL's JPEG plugin can't write to BytesIO objects
65 # PIL's JPEG plugin can't write to BytesIO objects
66 # Pillow fixes this
66 # Pillow fixes this
67 from PIL import Image
67 from PIL import Image
68 buf = BytesIO()
68 buf = BytesIO()
69 img = Image.new("RGB", (4,4))
69 img = Image.new("RGB", (4,4))
70 try:
70 try:
71 img.save(buf, 'jpeg')
71 img.save(buf, 'jpeg')
72 except Exception as e:
72 except Exception as e:
73 ename = e.__class__.__name__
73 ename = e.__class__.__name__
74 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
74 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
75
75
76 @dec.skip_without("PIL.Image")
76 @dec.skip_without("PIL.Image")
77 def test_figure_to_jpeg():
77 def test_figure_to_jpeg():
78 _check_pil_jpeg_bytes()
78 _check_pil_jpeg_bytes()
79 # simple check for at least jpeg-looking output
79 # simple check for at least jpeg-looking output
80 fig = plt.figure()
80 fig = plt.figure()
81 ax = fig.add_subplot(1,1,1)
81 ax = fig.add_subplot(1,1,1)
82 ax.plot([1,2,3])
82 ax.plot([1,2,3])
83 plt.draw()
83 plt.draw()
84 jpeg = pt.print_figure(fig, 'jpeg', quality=50)[:100].lower()
84 jpeg = pt.print_figure(fig, 'jpeg', quality=50)[:100].lower()
85 assert jpeg.startswith(_JPEG)
85 assert jpeg.startswith(_JPEG)
86
86
87 def test_retina_figure():
87 def test_retina_figure():
88 fig = plt.figure()
88 fig = plt.figure()
89 ax = fig.add_subplot(1,1,1)
89 ax = fig.add_subplot(1,1,1)
90 ax.plot([1,2,3])
90 ax.plot([1,2,3])
91 plt.draw()
91 plt.draw()
92 png, md = pt.retina_figure(fig)
92 png, md = pt.retina_figure(fig)
93 assert png.startswith(_PNG)
93 assert png.startswith(_PNG)
94 nt.assert_in('width', md)
94 nt.assert_in('width', md)
95 nt.assert_in('height', md)
95 nt.assert_in('height', md)
96
96
97 _fmt_mime_map = {
97 _fmt_mime_map = {
98 'png': 'image/png',
98 'png': 'image/png',
99 'jpeg': 'image/jpeg',
99 'jpeg': 'image/jpeg',
100 'pdf': 'application/pdf',
100 'pdf': 'application/pdf',
101 'retina': 'image/png',
101 'retina': 'image/png',
102 'svg': 'image/svg+xml',
102 'svg': 'image/svg+xml',
103 }
103 }
104
104
105 def test_select_figure_formats_str():
105 def test_select_figure_formats_str():
106 ip = get_ipython()
106 ip = get_ipython()
107 for fmt, active_mime in _fmt_mime_map.items():
107 for fmt, active_mime in _fmt_mime_map.items():
108 pt.select_figure_formats(ip, fmt)
108 pt.select_figure_formats(ip, fmt)
109 for mime, f in ip.display_formatter.formatters.items():
109 for mime, f in ip.display_formatter.formatters.items():
110 if mime == active_mime:
110 if mime == active_mime:
111 nt.assert_in(Figure, f)
111 nt.assert_in(Figure, f)
112 else:
112 else:
113 nt.assert_not_in(Figure, f)
113 nt.assert_not_in(Figure, f)
114
114
115 def test_select_figure_formats_kwargs():
115 def test_select_figure_formats_kwargs():
116 ip = get_ipython()
116 ip = get_ipython()
117 kwargs = dict(quality=10, bbox_inches='tight')
117 kwargs = dict(quality=10, bbox_inches='tight')
118 pt.select_figure_formats(ip, 'png', **kwargs)
118 pt.select_figure_formats(ip, 'png', **kwargs)
119 formatter = ip.display_formatter.formatters['image/png']
119 formatter = ip.display_formatter.formatters['image/png']
120 f = formatter.lookup_by_type(Figure)
120 f = formatter.lookup_by_type(Figure)
121 cell = f.__closure__[0].cell_contents
121 cell = f.__closure__[0].cell_contents
122 nt.assert_equal(cell, kwargs)
122 nt.assert_equal(cell, kwargs)
123
123
124 # check that the formatter doesn't raise
124 # check that the formatter doesn't raise
125 fig = plt.figure()
125 fig = plt.figure()
126 ax = fig.add_subplot(1,1,1)
126 ax = fig.add_subplot(1,1,1)
127 ax.plot([1,2,3])
127 ax.plot([1,2,3])
128 plt.draw()
128 plt.draw()
129 formatter.enabled = True
129 formatter.enabled = True
130 png = formatter(fig)
130 png = formatter(fig)
131 assert png.startswith(_PNG)
131 assert png.startswith(_PNG)
132
132
133 def test_select_figure_formats_set():
133 def test_select_figure_formats_set():
134 ip = get_ipython()
134 ip = get_ipython()
135 for fmts in [
135 for fmts in [
136 {'png', 'svg'},
136 {'png', 'svg'},
137 ['png'],
137 ['png'],
138 ('jpeg', 'pdf', 'retina'),
138 ('jpeg', 'pdf', 'retina'),
139 {'svg'},
139 {'svg'},
140 ]:
140 ]:
141 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
141 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
142 pt.select_figure_formats(ip, fmts)
142 pt.select_figure_formats(ip, fmts)
143 for mime, f in ip.display_formatter.formatters.items():
143 for mime, f in ip.display_formatter.formatters.items():
144 if mime in active_mimes:
144 if mime in active_mimes:
145 nt.assert_in(Figure, f)
145 nt.assert_in(Figure, f)
146 else:
146 else:
147 nt.assert_not_in(Figure, f)
147 nt.assert_not_in(Figure, f)
148
148
149 def test_select_figure_formats_bad():
149 def test_select_figure_formats_bad():
150 ip = get_ipython()
150 ip = get_ipython()
151 with nt.assert_raises(ValueError):
151 with nt.assert_raises(ValueError):
152 pt.select_figure_formats(ip, 'foo')
152 pt.select_figure_formats(ip, 'foo')
153 with nt.assert_raises(ValueError):
153 with nt.assert_raises(ValueError):
154 pt.select_figure_formats(ip, {'png', 'foo'})
154 pt.select_figure_formats(ip, {'png', 'foo'})
155 with nt.assert_raises(ValueError):
155 with nt.assert_raises(ValueError):
156 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
156 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
157
157
158 def test_import_pylab():
158 def test_import_pylab():
159 ns = {}
159 ns = {}
160 pt.import_pylab(ns, import_all=False)
160 pt.import_pylab(ns, import_all=False)
161 nt.assert_true('plt' in ns)
161 nt.assert_true('plt' in ns)
162 nt.assert_equal(ns['np'], np)
162 nt.assert_equal(ns['np'], np)
163
163
164 class TestPylabSwitch(object):
164 class TestPylabSwitch(object):
165 class Shell(InteractiveShell):
165 class Shell(InteractiveShell):
166 def enable_gui(self, gui):
166 def enable_gui(self, gui):
167 pass
167 pass
168
168
169 def setup(self):
169 def setup(self):
170 import matplotlib
170 import matplotlib
171 def act_mpl(backend):
171 def act_mpl(backend):
172 matplotlib.rcParams['backend'] = backend
172 matplotlib.rcParams['backend'] = backend
173
173
174 # Save rcParams since they get modified
174 # Save rcParams since they get modified
175 self._saved_rcParams = matplotlib.rcParams
175 self._saved_rcParams = matplotlib.rcParams
176 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
176 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
177 matplotlib.rcParams = dict(backend='Qt4Agg')
177 matplotlib.rcParams = dict(backend='Qt4Agg')
178 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
178 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
179
179
180 # Mock out functions
180 # Mock out functions
181 self._save_am = pt.activate_matplotlib
181 self._save_am = pt.activate_matplotlib
182 pt.activate_matplotlib = act_mpl
182 pt.activate_matplotlib = act_mpl
183 self._save_ip = pt.import_pylab
183 self._save_ip = pt.import_pylab
184 pt.import_pylab = lambda *a,**kw:None
184 pt.import_pylab = lambda *a,**kw:None
185 self._save_cis = pt.configure_inline_support
185 self._save_cis = pt.configure_inline_support
186 pt.configure_inline_support = lambda *a,**kw:None
186 pt.configure_inline_support = lambda *a,**kw:None
187
187
188 def teardown(self):
188 def teardown(self):
189 pt.activate_matplotlib = self._save_am
189 pt.activate_matplotlib = self._save_am
190 pt.import_pylab = self._save_ip
190 pt.import_pylab = self._save_ip
191 pt.configure_inline_support = self._save_cis
191 pt.configure_inline_support = self._save_cis
192 import matplotlib
192 import matplotlib
193 matplotlib.rcParams = self._saved_rcParams
193 matplotlib.rcParams = self._saved_rcParams
194 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
194 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
195
195
196 def test_qt(self):
196 def test_qt(self):
197 s = self.Shell()
197 s = self.Shell()
198 gui, backend = s.enable_matplotlib(None)
198 gui, backend = s.enable_matplotlib(None)
199 nt.assert_equal(gui, 'qt')
199 nt.assert_equal(gui, 'qt')
200 nt.assert_equal(s.pylab_gui_select, 'qt')
200 nt.assert_equal(s.pylab_gui_select, 'qt')
201
201
202 gui, backend = s.enable_matplotlib('inline')
202 gui, backend = s.enable_matplotlib('inline')
203 nt.assert_equal(gui, 'inline')
203 nt.assert_equal(gui, 'inline')
204 nt.assert_equal(s.pylab_gui_select, 'qt')
204 nt.assert_equal(s.pylab_gui_select, 'qt')
205
205
206 gui, backend = s.enable_matplotlib('qt')
206 gui, backend = s.enable_matplotlib('qt')
207 nt.assert_equal(gui, 'qt')
207 nt.assert_equal(gui, 'qt')
208 nt.assert_equal(s.pylab_gui_select, 'qt')
208 nt.assert_equal(s.pylab_gui_select, 'qt')
209
209
210 gui, backend = s.enable_matplotlib('inline')
210 gui, backend = s.enable_matplotlib('inline')
211 nt.assert_equal(gui, 'inline')
211 nt.assert_equal(gui, 'inline')
212 nt.assert_equal(s.pylab_gui_select, 'qt')
212 nt.assert_equal(s.pylab_gui_select, 'qt')
213
213
214 gui, backend = s.enable_matplotlib()
214 gui, backend = s.enable_matplotlib()
215 nt.assert_equal(gui, 'qt')
215 nt.assert_equal(gui, 'qt')
216 nt.assert_equal(s.pylab_gui_select, 'qt')
216 nt.assert_equal(s.pylab_gui_select, 'qt')
217
217
218 def test_inline(self):
218 def test_inline(self):
219 s = self.Shell()
219 s = self.Shell()
220 gui, backend = s.enable_matplotlib('inline')
220 gui, backend = s.enable_matplotlib('inline')
221 nt.assert_equal(gui, 'inline')
221 nt.assert_equal(gui, 'inline')
222 nt.assert_equal(s.pylab_gui_select, None)
222 nt.assert_equal(s.pylab_gui_select, None)
223
223
224 gui, backend = s.enable_matplotlib('inline')
224 gui, backend = s.enable_matplotlib('inline')
225 nt.assert_equal(gui, 'inline')
225 nt.assert_equal(gui, 'inline')
226 nt.assert_equal(s.pylab_gui_select, None)
226 nt.assert_equal(s.pylab_gui_select, None)
227
227
228 gui, backend = s.enable_matplotlib('qt')
228 gui, backend = s.enable_matplotlib('qt')
229 nt.assert_equal(gui, 'qt')
229 nt.assert_equal(gui, 'qt')
230 nt.assert_equal(s.pylab_gui_select, 'qt')
230 nt.assert_equal(s.pylab_gui_select, 'qt')
231
231
232 def test_qt_gtk(self):
232 def test_qt_gtk(self):
233 s = self.Shell()
233 s = self.Shell()
234 gui, backend = s.enable_matplotlib('qt')
234 gui, backend = s.enable_matplotlib('qt')
235 nt.assert_equal(gui, 'qt')
235 nt.assert_equal(gui, 'qt')
236 nt.assert_equal(s.pylab_gui_select, 'qt')
236 nt.assert_equal(s.pylab_gui_select, 'qt')
237
237
238 gui, backend = s.enable_matplotlib('gtk')
238 gui, backend = s.enable_matplotlib('gtk')
239 nt.assert_equal(gui, 'qt')
239 nt.assert_equal(gui, 'qt')
240 nt.assert_equal(s.pylab_gui_select, 'qt')
240 nt.assert_equal(s.pylab_gui_select, 'qt')
241
241
@@ -1,851 +1,854 b''
1 # coding: utf-8
1 # coding: utf-8
2 """A tornado based IPython notebook server.
2 """A tornado based IPython notebook server.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 from __future__ import print_function
8 from __future__ import print_function
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2013 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 # stdlib
20 # stdlib
21 import errno
21 import errno
22 import io
22 import io
23 import json
23 import json
24 import logging
24 import logging
25 import os
25 import os
26 import random
26 import random
27 import select
27 import select
28 import signal
28 import signal
29 import socket
29 import socket
30 import sys
30 import sys
31 import threading
31 import threading
32 import time
32 import time
33 import webbrowser
33 import webbrowser
34
34
35
35
36 # Third party
36 # Third party
37 # check for pyzmq 2.1.11
37 # check for pyzmq 2.1.11
38 from IPython.utils.zmqrelated import check_for_zmq
38 from IPython.utils.zmqrelated import check_for_zmq
39 check_for_zmq('2.1.11', 'IPython.html')
39 check_for_zmq('2.1.11', 'IPython.html')
40
40
41 from jinja2 import Environment, FileSystemLoader
41 from jinja2 import Environment, FileSystemLoader
42
42
43 # Install the pyzmq ioloop. This has to be done before anything else from
43 # Install the pyzmq ioloop. This has to be done before anything else from
44 # tornado is imported.
44 # tornado is imported.
45 from zmq.eventloop import ioloop
45 from zmq.eventloop import ioloop
46 ioloop.install()
46 ioloop.install()
47
47
48 # check for tornado 3.1.0
48 # check for tornado 3.1.0
49 msg = "The IPython Notebook requires tornado >= 3.1.0"
49 msg = "The IPython Notebook requires tornado >= 3.1.0"
50 try:
50 try:
51 import tornado
51 import tornado
52 except ImportError:
52 except ImportError:
53 raise ImportError(msg)
53 raise ImportError(msg)
54 try:
54 try:
55 version_info = tornado.version_info
55 version_info = tornado.version_info
56 except AttributeError:
56 except AttributeError:
57 raise ImportError(msg + ", but you have < 1.1.0")
57 raise ImportError(msg + ", but you have < 1.1.0")
58 if version_info < (3,1,0):
58 if version_info < (3,1,0):
59 raise ImportError(msg + ", but you have %s" % tornado.version)
59 raise ImportError(msg + ", but you have %s" % tornado.version)
60
60
61 from tornado import httpserver
61 from tornado import httpserver
62 from tornado import web
62 from tornado import web
63
63
64 # Our own libraries
64 # Our own libraries
65 from IPython.html import DEFAULT_STATIC_FILES_PATH
65 from IPython.html import DEFAULT_STATIC_FILES_PATH
66 from .base.handlers import Template404
66 from .base.handlers import Template404
67 from .log import log_request
67 from .log import log_request
68 from .services.kernels.kernelmanager import MappingKernelManager
68 from .services.kernels.kernelmanager import MappingKernelManager
69 from .services.notebooks.nbmanager import NotebookManager
69 from .services.notebooks.nbmanager import NotebookManager
70 from .services.notebooks.filenbmanager import FileNotebookManager
70 from .services.notebooks.filenbmanager import FileNotebookManager
71 from .services.clusters.clustermanager import ClusterManager
71 from .services.clusters.clustermanager import ClusterManager
72 from .services.sessions.sessionmanager import SessionManager
72 from .services.sessions.sessionmanager import SessionManager
73
73
74 from .base.handlers import AuthenticatedFileHandler, FileFindHandler
74 from .base.handlers import AuthenticatedFileHandler, FileFindHandler
75
75
76 from IPython.config import Config
76 from IPython.config.application import catch_config_error, boolean_flag
77 from IPython.config.application import catch_config_error, boolean_flag
77 from IPython.core.application import BaseIPythonApplication
78 from IPython.core.application import BaseIPythonApplication
78 from IPython.core.profiledir import ProfileDir
79 from IPython.core.profiledir import ProfileDir
79 from IPython.consoleapp import IPythonConsoleApp
80 from IPython.consoleapp import IPythonConsoleApp
80 from IPython.kernel import swallow_argv
81 from IPython.kernel import swallow_argv
81 from IPython.kernel.zmq.session import default_secure
82 from IPython.kernel.zmq.session import default_secure
82 from IPython.kernel.zmq.kernelapp import (
83 from IPython.kernel.zmq.kernelapp import (
83 kernel_flags,
84 kernel_flags,
84 kernel_aliases,
85 kernel_aliases,
85 )
86 )
86 from IPython.nbformat.sign import NotebookNotary
87 from IPython.nbformat.sign import NotebookNotary
87 from IPython.utils.importstring import import_item
88 from IPython.utils.importstring import import_item
88 from IPython.utils.localinterfaces import localhost
89 from IPython.utils.localinterfaces import localhost
89 from IPython.utils import submodule
90 from IPython.utils import submodule
90 from IPython.utils.traitlets import (
91 from IPython.utils.traitlets import (
91 Dict, Unicode, Integer, List, Bool, Bytes,
92 Dict, Unicode, Integer, List, Bool, Bytes,
92 DottedObjectName, TraitError,
93 DottedObjectName, TraitError,
93 )
94 )
94 from IPython.utils import py3compat
95 from IPython.utils import py3compat
95 from IPython.utils.path import filefind, get_ipython_dir
96 from IPython.utils.path import filefind, get_ipython_dir
96
97
97 from .utils import url_path_join
98 from .utils import url_path_join
98
99
99 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
100 # Module globals
101 # Module globals
101 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
102
103
103 _examples = """
104 _examples = """
104 ipython notebook # start the notebook
105 ipython notebook # start the notebook
105 ipython notebook --profile=sympy # use the sympy profile
106 ipython notebook --profile=sympy # use the sympy profile
106 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
107 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
107 """
108 """
108
109
109 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
110 # Helper functions
111 # Helper functions
111 #-----------------------------------------------------------------------------
112 #-----------------------------------------------------------------------------
112
113
113 def random_ports(port, n):
114 def random_ports(port, n):
114 """Generate a list of n random ports near the given port.
115 """Generate a list of n random ports near the given port.
115
116
116 The first 5 ports will be sequential, and the remaining n-5 will be
117 The first 5 ports will be sequential, and the remaining n-5 will be
117 randomly selected in the range [port-2*n, port+2*n].
118 randomly selected in the range [port-2*n, port+2*n].
118 """
119 """
119 for i in range(min(5, n)):
120 for i in range(min(5, n)):
120 yield port + i
121 yield port + i
121 for i in range(n-5):
122 for i in range(n-5):
122 yield max(1, port + random.randint(-2*n, 2*n))
123 yield max(1, port + random.randint(-2*n, 2*n))
123
124
124 def load_handlers(name):
125 def load_handlers(name):
125 """Load the (URL pattern, handler) tuples for each component."""
126 """Load the (URL pattern, handler) tuples for each component."""
126 name = 'IPython.html.' + name
127 name = 'IPython.html.' + name
127 mod = __import__(name, fromlist=['default_handlers'])
128 mod = __import__(name, fromlist=['default_handlers'])
128 return mod.default_handlers
129 return mod.default_handlers
129
130
130 #-----------------------------------------------------------------------------
131 #-----------------------------------------------------------------------------
131 # The Tornado web application
132 # The Tornado web application
132 #-----------------------------------------------------------------------------
133 #-----------------------------------------------------------------------------
133
134
134 class NotebookWebApplication(web.Application):
135 class NotebookWebApplication(web.Application):
135
136
136 def __init__(self, ipython_app, kernel_manager, notebook_manager,
137 def __init__(self, ipython_app, kernel_manager, notebook_manager,
137 cluster_manager, session_manager, log, base_url,
138 cluster_manager, session_manager, log, base_url,
138 settings_overrides, jinja_env_options):
139 settings_overrides, jinja_env_options):
139
140
140 settings = self.init_settings(
141 settings = self.init_settings(
141 ipython_app, kernel_manager, notebook_manager, cluster_manager,
142 ipython_app, kernel_manager, notebook_manager, cluster_manager,
142 session_manager, log, base_url, settings_overrides, jinja_env_options)
143 session_manager, log, base_url, settings_overrides, jinja_env_options)
143 handlers = self.init_handlers(settings)
144 handlers = self.init_handlers(settings)
144
145
145 super(NotebookWebApplication, self).__init__(handlers, **settings)
146 super(NotebookWebApplication, self).__init__(handlers, **settings)
146
147
147 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
148 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
148 cluster_manager, session_manager, log, base_url,
149 cluster_manager, session_manager, log, base_url,
149 settings_overrides, jinja_env_options=None):
150 settings_overrides, jinja_env_options=None):
150 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
151 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
151 # base_url will always be unicode, which will in turn
152 # base_url will always be unicode, which will in turn
152 # make the patterns unicode, and ultimately result in unicode
153 # make the patterns unicode, and ultimately result in unicode
153 # keys in kwargs to handler._execute(**kwargs) in tornado.
154 # keys in kwargs to handler._execute(**kwargs) in tornado.
154 # This enforces that base_url be ascii in that situation.
155 # This enforces that base_url be ascii in that situation.
155 #
156 #
156 # Note that the URLs these patterns check against are escaped,
157 # Note that the URLs these patterns check against are escaped,
157 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
158 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
158 base_url = py3compat.unicode_to_str(base_url, 'ascii')
159 base_url = py3compat.unicode_to_str(base_url, 'ascii')
159 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
160 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
160 jenv_opt = jinja_env_options if jinja_env_options else {}
161 jenv_opt = jinja_env_options if jinja_env_options else {}
161 env = Environment(loader=FileSystemLoader(template_path),**jenv_opt )
162 env = Environment(loader=FileSystemLoader(template_path),**jenv_opt )
162 settings = dict(
163 settings = dict(
163 # basics
164 # basics
164 log_function=log_request,
165 log_function=log_request,
165 base_url=base_url,
166 base_url=base_url,
166 template_path=template_path,
167 template_path=template_path,
167 static_path=ipython_app.static_file_path,
168 static_path=ipython_app.static_file_path,
168 static_handler_class = FileFindHandler,
169 static_handler_class = FileFindHandler,
169 static_url_prefix = url_path_join(base_url,'/static/'),
170 static_url_prefix = url_path_join(base_url,'/static/'),
170
171
171 # authentication
172 # authentication
172 cookie_secret=ipython_app.cookie_secret,
173 cookie_secret=ipython_app.cookie_secret,
173 login_url=url_path_join(base_url,'/login'),
174 login_url=url_path_join(base_url,'/login'),
174 password=ipython_app.password,
175 password=ipython_app.password,
175
176
176 # managers
177 # managers
177 kernel_manager=kernel_manager,
178 kernel_manager=kernel_manager,
178 notebook_manager=notebook_manager,
179 notebook_manager=notebook_manager,
179 cluster_manager=cluster_manager,
180 cluster_manager=cluster_manager,
180 session_manager=session_manager,
181 session_manager=session_manager,
181
182
182 # IPython stuff
183 # IPython stuff
183 nbextensions_path = ipython_app.nbextensions_path,
184 nbextensions_path = ipython_app.nbextensions_path,
184 mathjax_url=ipython_app.mathjax_url,
185 mathjax_url=ipython_app.mathjax_url,
185 config=ipython_app.config,
186 config=ipython_app.config,
186 jinja2_env=env,
187 jinja2_env=env,
187 )
188 )
188
189
189 # allow custom overrides for the tornado web app.
190 # allow custom overrides for the tornado web app.
190 settings.update(settings_overrides)
191 settings.update(settings_overrides)
191 return settings
192 return settings
192
193
193 def init_handlers(self, settings):
194 def init_handlers(self, settings):
194 # Load the (URL pattern, handler) tuples for each component.
195 # Load the (URL pattern, handler) tuples for each component.
195 handlers = []
196 handlers = []
196 handlers.extend(load_handlers('base.handlers'))
197 handlers.extend(load_handlers('base.handlers'))
197 handlers.extend(load_handlers('tree.handlers'))
198 handlers.extend(load_handlers('tree.handlers'))
198 handlers.extend(load_handlers('auth.login'))
199 handlers.extend(load_handlers('auth.login'))
199 handlers.extend(load_handlers('auth.logout'))
200 handlers.extend(load_handlers('auth.logout'))
200 handlers.extend(load_handlers('notebook.handlers'))
201 handlers.extend(load_handlers('notebook.handlers'))
201 handlers.extend(load_handlers('nbconvert.handlers'))
202 handlers.extend(load_handlers('nbconvert.handlers'))
202 handlers.extend(load_handlers('services.kernels.handlers'))
203 handlers.extend(load_handlers('services.kernels.handlers'))
203 handlers.extend(load_handlers('services.notebooks.handlers'))
204 handlers.extend(load_handlers('services.notebooks.handlers'))
204 handlers.extend(load_handlers('services.clusters.handlers'))
205 handlers.extend(load_handlers('services.clusters.handlers'))
205 handlers.extend(load_handlers('services.sessions.handlers'))
206 handlers.extend(load_handlers('services.sessions.handlers'))
206 handlers.extend(load_handlers('services.nbconvert.handlers'))
207 handlers.extend(load_handlers('services.nbconvert.handlers'))
207 # FIXME: /files/ should be handled by the Contents service when it exists
208 # FIXME: /files/ should be handled by the Contents service when it exists
208 nbm = settings['notebook_manager']
209 nbm = settings['notebook_manager']
209 if hasattr(nbm, 'notebook_dir'):
210 if hasattr(nbm, 'notebook_dir'):
210 handlers.extend([
211 handlers.extend([
211 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : nbm.notebook_dir}),
212 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : nbm.notebook_dir}),
212 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
213 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
213 ])
214 ])
214 # prepend base_url onto the patterns that we match
215 # prepend base_url onto the patterns that we match
215 new_handlers = []
216 new_handlers = []
216 for handler in handlers:
217 for handler in handlers:
217 pattern = url_path_join(settings['base_url'], handler[0])
218 pattern = url_path_join(settings['base_url'], handler[0])
218 new_handler = tuple([pattern] + list(handler[1:]))
219 new_handler = tuple([pattern] + list(handler[1:]))
219 new_handlers.append(new_handler)
220 new_handlers.append(new_handler)
220 # add 404 on the end, which will catch everything that falls through
221 # add 404 on the end, which will catch everything that falls through
221 new_handlers.append((r'(.*)', Template404))
222 new_handlers.append((r'(.*)', Template404))
222 return new_handlers
223 return new_handlers
223
224
224
225
225 class NbserverListApp(BaseIPythonApplication):
226 class NbserverListApp(BaseIPythonApplication):
226
227
227 description="List currently running notebook servers in this profile."
228 description="List currently running notebook servers in this profile."
228
229
229 flags = dict(
230 flags = dict(
230 json=({'NbserverListApp': {'json': True}},
231 json=({'NbserverListApp': {'json': True}},
231 "Produce machine-readable JSON output."),
232 "Produce machine-readable JSON output."),
232 )
233 )
233
234
234 json = Bool(False, config=True,
235 json = Bool(False, config=True,
235 help="If True, each line of output will be a JSON object with the "
236 help="If True, each line of output will be a JSON object with the "
236 "details from the server info file.")
237 "details from the server info file.")
237
238
238 def start(self):
239 def start(self):
239 if not self.json:
240 if not self.json:
240 print("Currently running servers:")
241 print("Currently running servers:")
241 for serverinfo in list_running_servers(self.profile):
242 for serverinfo in list_running_servers(self.profile):
242 if self.json:
243 if self.json:
243 print(json.dumps(serverinfo))
244 print(json.dumps(serverinfo))
244 else:
245 else:
245 print(serverinfo['url'], "::", serverinfo['notebook_dir'])
246 print(serverinfo['url'], "::", serverinfo['notebook_dir'])
246
247
247 #-----------------------------------------------------------------------------
248 #-----------------------------------------------------------------------------
248 # Aliases and Flags
249 # Aliases and Flags
249 #-----------------------------------------------------------------------------
250 #-----------------------------------------------------------------------------
250
251
251 flags = dict(kernel_flags)
252 flags = dict(kernel_flags)
252 flags['no-browser']=(
253 flags['no-browser']=(
253 {'NotebookApp' : {'open_browser' : False}},
254 {'NotebookApp' : {'open_browser' : False}},
254 "Don't open the notebook in a browser after startup."
255 "Don't open the notebook in a browser after startup."
255 )
256 )
256 flags['no-mathjax']=(
257 flags['no-mathjax']=(
257 {'NotebookApp' : {'enable_mathjax' : False}},
258 {'NotebookApp' : {'enable_mathjax' : False}},
258 """Disable MathJax
259 """Disable MathJax
259
260
260 MathJax is the javascript library IPython uses to render math/LaTeX. It is
261 MathJax is the javascript library IPython uses to render math/LaTeX. It is
261 very large, so you may want to disable it if you have a slow internet
262 very large, so you may want to disable it if you have a slow internet
262 connection, or for offline use of the notebook.
263 connection, or for offline use of the notebook.
263
264
264 When disabled, equations etc. will appear as their untransformed TeX source.
265 When disabled, equations etc. will appear as their untransformed TeX source.
265 """
266 """
266 )
267 )
267
268
268 # Add notebook manager flags
269 # Add notebook manager flags
269 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
270 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
270 'Auto-save a .py script everytime the .ipynb notebook is saved',
271 'Auto-save a .py script everytime the .ipynb notebook is saved',
271 'Do not auto-save .py scripts for every notebook'))
272 'Do not auto-save .py scripts for every notebook'))
272
273
273 # the flags that are specific to the frontend
274 # the flags that are specific to the frontend
274 # these must be scrubbed before being passed to the kernel,
275 # these must be scrubbed before being passed to the kernel,
275 # or it will raise an error on unrecognized flags
276 # or it will raise an error on unrecognized flags
276 notebook_flags = ['no-browser', 'no-mathjax', 'script', 'no-script']
277 notebook_flags = ['no-browser', 'no-mathjax', 'script', 'no-script']
277
278
278 aliases = dict(kernel_aliases)
279 aliases = dict(kernel_aliases)
279
280
280 aliases.update({
281 aliases.update({
281 'ip': 'NotebookApp.ip',
282 'ip': 'NotebookApp.ip',
282 'port': 'NotebookApp.port',
283 'port': 'NotebookApp.port',
283 'port-retries': 'NotebookApp.port_retries',
284 'port-retries': 'NotebookApp.port_retries',
284 'transport': 'KernelManager.transport',
285 'transport': 'KernelManager.transport',
285 'keyfile': 'NotebookApp.keyfile',
286 'keyfile': 'NotebookApp.keyfile',
286 'certfile': 'NotebookApp.certfile',
287 'certfile': 'NotebookApp.certfile',
287 'notebook-dir': 'NotebookApp.notebook_dir',
288 'notebook-dir': 'NotebookApp.notebook_dir',
288 'browser': 'NotebookApp.browser',
289 'browser': 'NotebookApp.browser',
289 })
290 })
290
291
291 # remove ipkernel flags that are singletons, and don't make sense in
292 # remove ipkernel flags that are singletons, and don't make sense in
292 # multi-kernel evironment:
293 # multi-kernel evironment:
293 aliases.pop('f', None)
294 aliases.pop('f', None)
294
295
295 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
296 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
296 u'notebook-dir', u'profile', u'profile-dir']
297 u'notebook-dir', u'profile', u'profile-dir']
297
298
298 #-----------------------------------------------------------------------------
299 #-----------------------------------------------------------------------------
299 # NotebookApp
300 # NotebookApp
300 #-----------------------------------------------------------------------------
301 #-----------------------------------------------------------------------------
301
302
302 class NotebookApp(BaseIPythonApplication):
303 class NotebookApp(BaseIPythonApplication):
303
304
304 name = 'ipython-notebook'
305 name = 'ipython-notebook'
305
306
306 description = """
307 description = """
307 The IPython HTML Notebook.
308 The IPython HTML Notebook.
308
309
309 This launches a Tornado based HTML Notebook Server that serves up an
310 This launches a Tornado based HTML Notebook Server that serves up an
310 HTML5/Javascript Notebook client.
311 HTML5/Javascript Notebook client.
311 """
312 """
312 examples = _examples
313 examples = _examples
313
314
314 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
315 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
315 FileNotebookManager, NotebookNotary]
316 FileNotebookManager, NotebookNotary]
316 flags = Dict(flags)
317 flags = Dict(flags)
317 aliases = Dict(aliases)
318 aliases = Dict(aliases)
318
319
319 subcommands = dict(
320 subcommands = dict(
320 list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
321 list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
321 )
322 )
322
323
323 kernel_argv = List(Unicode)
324 kernel_argv = List(Unicode)
324
325
325 def _log_level_default(self):
326 def _log_level_default(self):
326 return logging.INFO
327 return logging.INFO
327
328
328 def _log_format_default(self):
329 def _log_format_default(self):
329 """override default log format to include time"""
330 """override default log format to include time"""
330 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
331 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
331
332
332 # create requested profiles by default, if they don't exist:
333 # create requested profiles by default, if they don't exist:
333 auto_create = Bool(True)
334 auto_create = Bool(True)
334
335
335 # file to be opened in the notebook server
336 # file to be opened in the notebook server
336 file_to_run = Unicode('', config=True)
337 file_to_run = Unicode('', config=True)
337 def _file_to_run_changed(self, name, old, new):
338 def _file_to_run_changed(self, name, old, new):
338 path, base = os.path.split(new)
339 path, base = os.path.split(new)
339 if path:
340 if path:
340 self.file_to_run = base
341 self.file_to_run = base
341 self.notebook_dir = path
342 self.notebook_dir = path
342
343
343 # Network related information.
344 # Network related information.
344
345
345 ip = Unicode(config=True,
346 ip = Unicode(config=True,
346 help="The IP address the notebook server will listen on."
347 help="The IP address the notebook server will listen on."
347 )
348 )
348 def _ip_default(self):
349 def _ip_default(self):
349 return localhost()
350 return localhost()
350
351
351 def _ip_changed(self, name, old, new):
352 def _ip_changed(self, name, old, new):
352 if new == u'*': self.ip = u''
353 if new == u'*': self.ip = u''
353
354
354 port = Integer(8888, config=True,
355 port = Integer(8888, config=True,
355 help="The port the notebook server will listen on."
356 help="The port the notebook server will listen on."
356 )
357 )
357 port_retries = Integer(50, config=True,
358 port_retries = Integer(50, config=True,
358 help="The number of additional ports to try if the specified port is not available."
359 help="The number of additional ports to try if the specified port is not available."
359 )
360 )
360
361
361 certfile = Unicode(u'', config=True,
362 certfile = Unicode(u'', config=True,
362 help="""The full path to an SSL/TLS certificate file."""
363 help="""The full path to an SSL/TLS certificate file."""
363 )
364 )
364
365
365 keyfile = Unicode(u'', config=True,
366 keyfile = Unicode(u'', config=True,
366 help="""The full path to a private key file for usage with SSL/TLS."""
367 help="""The full path to a private key file for usage with SSL/TLS."""
367 )
368 )
368
369
369 cookie_secret = Bytes(b'', config=True,
370 cookie_secret = Bytes(b'', config=True,
370 help="""The random bytes used to secure cookies.
371 help="""The random bytes used to secure cookies.
371 By default this is a new random number every time you start the Notebook.
372 By default this is a new random number every time you start the Notebook.
372 Set it to a value in a config file to enable logins to persist across server sessions.
373 Set it to a value in a config file to enable logins to persist across server sessions.
373
374
374 Note: Cookie secrets should be kept private, do not share config files with
375 Note: Cookie secrets should be kept private, do not share config files with
375 cookie_secret stored in plaintext (you can read the value from a file).
376 cookie_secret stored in plaintext (you can read the value from a file).
376 """
377 """
377 )
378 )
378 def _cookie_secret_default(self):
379 def _cookie_secret_default(self):
379 return os.urandom(1024)
380 return os.urandom(1024)
380
381
381 password = Unicode(u'', config=True,
382 password = Unicode(u'', config=True,
382 help="""Hashed password to use for web authentication.
383 help="""Hashed password to use for web authentication.
383
384
384 To generate, type in a python/IPython shell:
385 To generate, type in a python/IPython shell:
385
386
386 from IPython.lib import passwd; passwd()
387 from IPython.lib import passwd; passwd()
387
388
388 The string should be of the form type:salt:hashed-password.
389 The string should be of the form type:salt:hashed-password.
389 """
390 """
390 )
391 )
391
392
392 open_browser = Bool(True, config=True,
393 open_browser = Bool(True, config=True,
393 help="""Whether to open in a browser after starting.
394 help="""Whether to open in a browser after starting.
394 The specific browser used is platform dependent and
395 The specific browser used is platform dependent and
395 determined by the python standard library `webbrowser`
396 determined by the python standard library `webbrowser`
396 module, unless it is overridden using the --browser
397 module, unless it is overridden using the --browser
397 (NotebookApp.browser) configuration option.
398 (NotebookApp.browser) configuration option.
398 """)
399 """)
399
400
400 browser = Unicode(u'', config=True,
401 browser = Unicode(u'', config=True,
401 help="""Specify what command to use to invoke a web
402 help="""Specify what command to use to invoke a web
402 browser when opening the notebook. If not specified, the
403 browser when opening the notebook. If not specified, the
403 default browser will be determined by the `webbrowser`
404 default browser will be determined by the `webbrowser`
404 standard library module, which allows setting of the
405 standard library module, which allows setting of the
405 BROWSER environment variable to override it.
406 BROWSER environment variable to override it.
406 """)
407 """)
407
408
408 webapp_settings = Dict(config=True,
409 webapp_settings = Dict(config=True,
409 help="Supply overrides for the tornado.web.Application that the "
410 help="Supply overrides for the tornado.web.Application that the "
410 "IPython notebook uses.")
411 "IPython notebook uses.")
411
412
412 jinja_environment_options = Dict(config=True,
413 jinja_environment_options = Dict(config=True,
413 help="Supply extra arguments that will be passed to Jinja environment.")
414 help="Supply extra arguments that will be passed to Jinja environment.")
414
415
415
416
416 enable_mathjax = Bool(True, config=True,
417 enable_mathjax = Bool(True, config=True,
417 help="""Whether to enable MathJax for typesetting math/TeX
418 help="""Whether to enable MathJax for typesetting math/TeX
418
419
419 MathJax is the javascript library IPython uses to render math/LaTeX. It is
420 MathJax is the javascript library IPython uses to render math/LaTeX. It is
420 very large, so you may want to disable it if you have a slow internet
421 very large, so you may want to disable it if you have a slow internet
421 connection, or for offline use of the notebook.
422 connection, or for offline use of the notebook.
422
423
423 When disabled, equations etc. will appear as their untransformed TeX source.
424 When disabled, equations etc. will appear as their untransformed TeX source.
424 """
425 """
425 )
426 )
426 def _enable_mathjax_changed(self, name, old, new):
427 def _enable_mathjax_changed(self, name, old, new):
427 """set mathjax url to empty if mathjax is disabled"""
428 """set mathjax url to empty if mathjax is disabled"""
428 if not new:
429 if not new:
429 self.mathjax_url = u''
430 self.mathjax_url = u''
430
431
431 base_url = Unicode('/', config=True,
432 base_url = Unicode('/', config=True,
432 help='''The base URL for the notebook server.
433 help='''The base URL for the notebook server.
433
434
434 Leading and trailing slashes can be omitted,
435 Leading and trailing slashes can be omitted,
435 and will automatically be added.
436 and will automatically be added.
436 ''')
437 ''')
437 def _base_url_changed(self, name, old, new):
438 def _base_url_changed(self, name, old, new):
438 if not new.startswith('/'):
439 if not new.startswith('/'):
439 self.base_url = '/'+new
440 self.base_url = '/'+new
440 elif not new.endswith('/'):
441 elif not new.endswith('/'):
441 self.base_url = new+'/'
442 self.base_url = new+'/'
442
443
443 base_project_url = Unicode('/', config=True, help="""DEPRECATED use base_url""")
444 base_project_url = Unicode('/', config=True, help="""DEPRECATED use base_url""")
444 def _base_project_url_changed(self, name, old, new):
445 def _base_project_url_changed(self, name, old, new):
445 self.log.warn("base_project_url is deprecated, use base_url")
446 self.log.warn("base_project_url is deprecated, use base_url")
446 self.base_url = new
447 self.base_url = new
447
448
448 extra_static_paths = List(Unicode, config=True,
449 extra_static_paths = List(Unicode, config=True,
449 help="""Extra paths to search for serving static files.
450 help="""Extra paths to search for serving static files.
450
451
451 This allows adding javascript/css to be available from the notebook server machine,
452 This allows adding javascript/css to be available from the notebook server machine,
452 or overriding individual files in the IPython"""
453 or overriding individual files in the IPython"""
453 )
454 )
454 def _extra_static_paths_default(self):
455 def _extra_static_paths_default(self):
455 return [os.path.join(self.profile_dir.location, 'static')]
456 return [os.path.join(self.profile_dir.location, 'static')]
456
457
457 @property
458 @property
458 def static_file_path(self):
459 def static_file_path(self):
459 """return extra paths + the default location"""
460 """return extra paths + the default location"""
460 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
461 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
461
462
462 nbextensions_path = List(Unicode, config=True,
463 nbextensions_path = List(Unicode, config=True,
463 help="""paths for Javascript extensions. By default, this is just IPYTHONDIR/nbextensions"""
464 help="""paths for Javascript extensions. By default, this is just IPYTHONDIR/nbextensions"""
464 )
465 )
465 def _nbextensions_path_default(self):
466 def _nbextensions_path_default(self):
466 return [os.path.join(get_ipython_dir(), 'nbextensions')]
467 return [os.path.join(get_ipython_dir(), 'nbextensions')]
467
468
468 mathjax_url = Unicode("", config=True,
469 mathjax_url = Unicode("", config=True,
469 help="""The url for MathJax.js."""
470 help="""The url for MathJax.js."""
470 )
471 )
471 def _mathjax_url_default(self):
472 def _mathjax_url_default(self):
472 if not self.enable_mathjax:
473 if not self.enable_mathjax:
473 return u''
474 return u''
474 static_url_prefix = self.webapp_settings.get("static_url_prefix",
475 static_url_prefix = self.webapp_settings.get("static_url_prefix",
475 url_path_join(self.base_url, "static")
476 url_path_join(self.base_url, "static")
476 )
477 )
477
478
478 # try local mathjax, either in nbextensions/mathjax or static/mathjax
479 # try local mathjax, either in nbextensions/mathjax or static/mathjax
479 for (url_prefix, search_path) in [
480 for (url_prefix, search_path) in [
480 (url_path_join(self.base_url, "nbextensions"), self.nbextensions_path),
481 (url_path_join(self.base_url, "nbextensions"), self.nbextensions_path),
481 (static_url_prefix, self.static_file_path),
482 (static_url_prefix, self.static_file_path),
482 ]:
483 ]:
483 self.log.debug("searching for local mathjax in %s", search_path)
484 self.log.debug("searching for local mathjax in %s", search_path)
484 try:
485 try:
485 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
486 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
486 except IOError:
487 except IOError:
487 continue
488 continue
488 else:
489 else:
489 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
490 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
490 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
491 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
491 return url
492 return url
492
493
493 # no local mathjax, serve from CDN
494 # no local mathjax, serve from CDN
494 if self.certfile:
495 if self.certfile:
495 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
496 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
496 host = u"https://c328740.ssl.cf1.rackcdn.com"
497 host = u"https://c328740.ssl.cf1.rackcdn.com"
497 else:
498 else:
498 host = u"http://cdn.mathjax.org"
499 host = u"http://cdn.mathjax.org"
499
500
500 url = host + u"/mathjax/latest/MathJax.js"
501 url = host + u"/mathjax/latest/MathJax.js"
501 self.log.info("Using MathJax from CDN: %s", url)
502 self.log.info("Using MathJax from CDN: %s", url)
502 return url
503 return url
503
504
504 def _mathjax_url_changed(self, name, old, new):
505 def _mathjax_url_changed(self, name, old, new):
505 if new and not self.enable_mathjax:
506 if new and not self.enable_mathjax:
506 # enable_mathjax=False overrides mathjax_url
507 # enable_mathjax=False overrides mathjax_url
507 self.mathjax_url = u''
508 self.mathjax_url = u''
508 else:
509 else:
509 self.log.info("Using MathJax: %s", new)
510 self.log.info("Using MathJax: %s", new)
510
511
511 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
512 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
512 config=True,
513 config=True,
513 help='The notebook manager class to use.')
514 help='The notebook manager class to use.')
514
515
515 trust_xheaders = Bool(False, config=True,
516 trust_xheaders = Bool(False, config=True,
516 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
517 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
517 "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")
518 "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")
518 )
519 )
519
520
520 info_file = Unicode()
521 info_file = Unicode()
521
522
522 def _info_file_default(self):
523 def _info_file_default(self):
523 info_file = "nbserver-%s.json"%os.getpid()
524 info_file = "nbserver-%s.json"%os.getpid()
524 return os.path.join(self.profile_dir.security_dir, info_file)
525 return os.path.join(self.profile_dir.security_dir, info_file)
525
526
526 notebook_dir = Unicode(py3compat.getcwd(), config=True,
527 notebook_dir = Unicode(py3compat.getcwd(), config=True,
527 help="The directory to use for notebooks and kernels."
528 help="The directory to use for notebooks and kernels."
528 )
529 )
529
530
530 def _notebook_dir_changed(self, name, old, new):
531 def _notebook_dir_changed(self, name, old, new):
531 """Do a bit of validation of the notebook dir."""
532 """Do a bit of validation of the notebook dir."""
532 if not os.path.isabs(new):
533 if not os.path.isabs(new):
533 # If we receive a non-absolute path, make it absolute.
534 # If we receive a non-absolute path, make it absolute.
534 self.notebook_dir = os.path.abspath(new)
535 self.notebook_dir = os.path.abspath(new)
535 return
536 return
536 if not os.path.isdir(new):
537 if not os.path.isdir(new):
537 raise TraitError("No such notebook dir: %r" % new)
538 raise TraitError("No such notebook dir: %r" % new)
538
539
539 # setting App.notebook_dir implies setting notebook and kernel dirs as well
540 # setting App.notebook_dir implies setting notebook and kernel dirs as well
540 self.config.FileNotebookManager.notebook_dir = new
541 self.config.FileNotebookManager.notebook_dir = new
541 self.config.MappingKernelManager.root_dir = new
542 self.config.MappingKernelManager.root_dir = new
542
543
543
544
544 def parse_command_line(self, argv=None):
545 def parse_command_line(self, argv=None):
545 super(NotebookApp, self).parse_command_line(argv)
546 super(NotebookApp, self).parse_command_line(argv)
546
547
547 if self.extra_args:
548 if self.extra_args:
548 arg0 = self.extra_args[0]
549 arg0 = self.extra_args[0]
549 f = os.path.abspath(arg0)
550 f = os.path.abspath(arg0)
550 self.argv.remove(arg0)
551 self.argv.remove(arg0)
551 if not os.path.exists(f):
552 if not os.path.exists(f):
552 self.log.critical("No such file or directory: %s", f)
553 self.log.critical("No such file or directory: %s", f)
553 self.exit(1)
554 self.exit(1)
554
555
555 # Use config here, to ensure that it takes higher priority than
556 # Use config here, to ensure that it takes higher priority than
556 # anything that comes from the profile.
557 # anything that comes from the profile.
558 c = Config()
557 if os.path.isdir(f):
559 if os.path.isdir(f):
558 self.config.NotebookApp.notebook_dir = f
560 c.NotebookApp.notebook_dir = f
559 elif os.path.isfile(f):
561 elif os.path.isfile(f):
560 self.config.NotebookApp.file_to_run = f
562 c.NotebookApp.file_to_run = f
563 self.update_config(c)
561
564
562 def init_kernel_argv(self):
565 def init_kernel_argv(self):
563 """construct the kernel arguments"""
566 """construct the kernel arguments"""
564 # Scrub frontend-specific flags
567 # Scrub frontend-specific flags
565 self.kernel_argv = swallow_argv(self.argv, notebook_aliases, notebook_flags)
568 self.kernel_argv = swallow_argv(self.argv, notebook_aliases, notebook_flags)
566 if any(arg.startswith(u'--pylab') for arg in self.kernel_argv):
569 if any(arg.startswith(u'--pylab') for arg in self.kernel_argv):
567 self.log.warn('\n '.join([
570 self.log.warn('\n '.join([
568 "Starting all kernels in pylab mode is not recommended,",
571 "Starting all kernels in pylab mode is not recommended,",
569 "and will be disabled in a future release.",
572 "and will be disabled in a future release.",
570 "Please use the %matplotlib magic to enable matplotlib instead.",
573 "Please use the %matplotlib magic to enable matplotlib instead.",
571 "pylab implies many imports, which can have confusing side effects",
574 "pylab implies many imports, which can have confusing side effects",
572 "and harm the reproducibility of your notebooks.",
575 "and harm the reproducibility of your notebooks.",
573 ]))
576 ]))
574 # Kernel should inherit default config file from frontend
577 # Kernel should inherit default config file from frontend
575 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
578 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
576 # Kernel should get *absolute* path to profile directory
579 # Kernel should get *absolute* path to profile directory
577 self.kernel_argv.extend(["--profile-dir", self.profile_dir.location])
580 self.kernel_argv.extend(["--profile-dir", self.profile_dir.location])
578
581
579 def init_configurables(self):
582 def init_configurables(self):
580 # force Session default to be secure
583 # force Session default to be secure
581 default_secure(self.config)
584 default_secure(self.config)
582 self.kernel_manager = MappingKernelManager(
585 self.kernel_manager = MappingKernelManager(
583 parent=self, log=self.log, kernel_argv=self.kernel_argv,
586 parent=self, log=self.log, kernel_argv=self.kernel_argv,
584 connection_dir = self.profile_dir.security_dir,
587 connection_dir = self.profile_dir.security_dir,
585 )
588 )
586 kls = import_item(self.notebook_manager_class)
589 kls = import_item(self.notebook_manager_class)
587 self.notebook_manager = kls(parent=self, log=self.log)
590 self.notebook_manager = kls(parent=self, log=self.log)
588 self.session_manager = SessionManager(parent=self, log=self.log)
591 self.session_manager = SessionManager(parent=self, log=self.log)
589 self.cluster_manager = ClusterManager(parent=self, log=self.log)
592 self.cluster_manager = ClusterManager(parent=self, log=self.log)
590 self.cluster_manager.update_profiles()
593 self.cluster_manager.update_profiles()
591
594
592 def init_logging(self):
595 def init_logging(self):
593 # This prevents double log messages because tornado use a root logger that
596 # This prevents double log messages because tornado use a root logger that
594 # self.log is a child of. The logging module dipatches log messages to a log
597 # self.log is a child of. The logging module dipatches log messages to a log
595 # and all of its ancenstors until propagate is set to False.
598 # and all of its ancenstors until propagate is set to False.
596 self.log.propagate = False
599 self.log.propagate = False
597
600
598 # hook up tornado 3's loggers to our app handlers
601 # hook up tornado 3's loggers to our app handlers
599 for name in ('access', 'application', 'general'):
602 for name in ('access', 'application', 'general'):
600 logger = logging.getLogger('tornado.%s' % name)
603 logger = logging.getLogger('tornado.%s' % name)
601 logger.parent = self.log
604 logger.parent = self.log
602 logger.setLevel(self.log.level)
605 logger.setLevel(self.log.level)
603
606
604 def init_webapp(self):
607 def init_webapp(self):
605 """initialize tornado webapp and httpserver"""
608 """initialize tornado webapp and httpserver"""
606 self.web_app = NotebookWebApplication(
609 self.web_app = NotebookWebApplication(
607 self, self.kernel_manager, self.notebook_manager,
610 self, self.kernel_manager, self.notebook_manager,
608 self.cluster_manager, self.session_manager,
611 self.cluster_manager, self.session_manager,
609 self.log, self.base_url, self.webapp_settings,
612 self.log, self.base_url, self.webapp_settings,
610 self.jinja_environment_options
613 self.jinja_environment_options
611 )
614 )
612 if self.certfile:
615 if self.certfile:
613 ssl_options = dict(certfile=self.certfile)
616 ssl_options = dict(certfile=self.certfile)
614 if self.keyfile:
617 if self.keyfile:
615 ssl_options['keyfile'] = self.keyfile
618 ssl_options['keyfile'] = self.keyfile
616 else:
619 else:
617 ssl_options = None
620 ssl_options = None
618 self.web_app.password = self.password
621 self.web_app.password = self.password
619 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
622 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
620 xheaders=self.trust_xheaders)
623 xheaders=self.trust_xheaders)
621 if not self.ip:
624 if not self.ip:
622 warning = "WARNING: The notebook server is listening on all IP addresses"
625 warning = "WARNING: The notebook server is listening on all IP addresses"
623 if ssl_options is None:
626 if ssl_options is None:
624 self.log.critical(warning + " and not using encryption. This "
627 self.log.critical(warning + " and not using encryption. This "
625 "is not recommended.")
628 "is not recommended.")
626 if not self.password:
629 if not self.password:
627 self.log.critical(warning + " and not using authentication. "
630 self.log.critical(warning + " and not using authentication. "
628 "This is highly insecure and not recommended.")
631 "This is highly insecure and not recommended.")
629 success = None
632 success = None
630 for port in random_ports(self.port, self.port_retries+1):
633 for port in random_ports(self.port, self.port_retries+1):
631 try:
634 try:
632 self.http_server.listen(port, self.ip)
635 self.http_server.listen(port, self.ip)
633 except socket.error as e:
636 except socket.error as e:
634 if e.errno == errno.EADDRINUSE:
637 if e.errno == errno.EADDRINUSE:
635 self.log.info('The port %i is already in use, trying another random port.' % port)
638 self.log.info('The port %i is already in use, trying another random port.' % port)
636 continue
639 continue
637 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
640 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
638 self.log.warn("Permission to listen on port %i denied" % port)
641 self.log.warn("Permission to listen on port %i denied" % port)
639 continue
642 continue
640 else:
643 else:
641 raise
644 raise
642 else:
645 else:
643 self.port = port
646 self.port = port
644 success = True
647 success = True
645 break
648 break
646 if not success:
649 if not success:
647 self.log.critical('ERROR: the notebook server could not be started because '
650 self.log.critical('ERROR: the notebook server could not be started because '
648 'no available port could be found.')
651 'no available port could be found.')
649 self.exit(1)
652 self.exit(1)
650
653
651 @property
654 @property
652 def display_url(self):
655 def display_url(self):
653 ip = self.ip if self.ip else '[all ip addresses on your system]'
656 ip = self.ip if self.ip else '[all ip addresses on your system]'
654 return self._url(ip)
657 return self._url(ip)
655
658
656 @property
659 @property
657 def connection_url(self):
660 def connection_url(self):
658 ip = self.ip if self.ip else localhost()
661 ip = self.ip if self.ip else localhost()
659 return self._url(ip)
662 return self._url(ip)
660
663
661 def _url(self, ip):
664 def _url(self, ip):
662 proto = 'https' if self.certfile else 'http'
665 proto = 'https' if self.certfile else 'http'
663 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_url)
666 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_url)
664
667
665 def init_signal(self):
668 def init_signal(self):
666 if not sys.platform.startswith('win'):
669 if not sys.platform.startswith('win'):
667 signal.signal(signal.SIGINT, self._handle_sigint)
670 signal.signal(signal.SIGINT, self._handle_sigint)
668 signal.signal(signal.SIGTERM, self._signal_stop)
671 signal.signal(signal.SIGTERM, self._signal_stop)
669 if hasattr(signal, 'SIGUSR1'):
672 if hasattr(signal, 'SIGUSR1'):
670 # Windows doesn't support SIGUSR1
673 # Windows doesn't support SIGUSR1
671 signal.signal(signal.SIGUSR1, self._signal_info)
674 signal.signal(signal.SIGUSR1, self._signal_info)
672 if hasattr(signal, 'SIGINFO'):
675 if hasattr(signal, 'SIGINFO'):
673 # only on BSD-based systems
676 # only on BSD-based systems
674 signal.signal(signal.SIGINFO, self._signal_info)
677 signal.signal(signal.SIGINFO, self._signal_info)
675
678
676 def _handle_sigint(self, sig, frame):
679 def _handle_sigint(self, sig, frame):
677 """SIGINT handler spawns confirmation dialog"""
680 """SIGINT handler spawns confirmation dialog"""
678 # register more forceful signal handler for ^C^C case
681 # register more forceful signal handler for ^C^C case
679 signal.signal(signal.SIGINT, self._signal_stop)
682 signal.signal(signal.SIGINT, self._signal_stop)
680 # request confirmation dialog in bg thread, to avoid
683 # request confirmation dialog in bg thread, to avoid
681 # blocking the App
684 # blocking the App
682 thread = threading.Thread(target=self._confirm_exit)
685 thread = threading.Thread(target=self._confirm_exit)
683 thread.daemon = True
686 thread.daemon = True
684 thread.start()
687 thread.start()
685
688
686 def _restore_sigint_handler(self):
689 def _restore_sigint_handler(self):
687 """callback for restoring original SIGINT handler"""
690 """callback for restoring original SIGINT handler"""
688 signal.signal(signal.SIGINT, self._handle_sigint)
691 signal.signal(signal.SIGINT, self._handle_sigint)
689
692
690 def _confirm_exit(self):
693 def _confirm_exit(self):
691 """confirm shutdown on ^C
694 """confirm shutdown on ^C
692
695
693 A second ^C, or answering 'y' within 5s will cause shutdown,
696 A second ^C, or answering 'y' within 5s will cause shutdown,
694 otherwise original SIGINT handler will be restored.
697 otherwise original SIGINT handler will be restored.
695
698
696 This doesn't work on Windows.
699 This doesn't work on Windows.
697 """
700 """
698 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
701 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
699 time.sleep(0.1)
702 time.sleep(0.1)
700 info = self.log.info
703 info = self.log.info
701 info('interrupted')
704 info('interrupted')
702 print(self.notebook_info())
705 print(self.notebook_info())
703 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
706 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
704 sys.stdout.flush()
707 sys.stdout.flush()
705 r,w,x = select.select([sys.stdin], [], [], 5)
708 r,w,x = select.select([sys.stdin], [], [], 5)
706 if r:
709 if r:
707 line = sys.stdin.readline()
710 line = sys.stdin.readline()
708 if line.lower().startswith('y'):
711 if line.lower().startswith('y'):
709 self.log.critical("Shutdown confirmed")
712 self.log.critical("Shutdown confirmed")
710 ioloop.IOLoop.instance().stop()
713 ioloop.IOLoop.instance().stop()
711 return
714 return
712 else:
715 else:
713 print("No answer for 5s:", end=' ')
716 print("No answer for 5s:", end=' ')
714 print("resuming operation...")
717 print("resuming operation...")
715 # no answer, or answer is no:
718 # no answer, or answer is no:
716 # set it back to original SIGINT handler
719 # set it back to original SIGINT handler
717 # use IOLoop.add_callback because signal.signal must be called
720 # use IOLoop.add_callback because signal.signal must be called
718 # from main thread
721 # from main thread
719 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
722 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
720
723
721 def _signal_stop(self, sig, frame):
724 def _signal_stop(self, sig, frame):
722 self.log.critical("received signal %s, stopping", sig)
725 self.log.critical("received signal %s, stopping", sig)
723 ioloop.IOLoop.instance().stop()
726 ioloop.IOLoop.instance().stop()
724
727
725 def _signal_info(self, sig, frame):
728 def _signal_info(self, sig, frame):
726 print(self.notebook_info())
729 print(self.notebook_info())
727
730
728 def init_components(self):
731 def init_components(self):
729 """Check the components submodule, and warn if it's unclean"""
732 """Check the components submodule, and warn if it's unclean"""
730 status = submodule.check_submodule_status()
733 status = submodule.check_submodule_status()
731 if status == 'missing':
734 if status == 'missing':
732 self.log.warn("components submodule missing, running `git submodule update`")
735 self.log.warn("components submodule missing, running `git submodule update`")
733 submodule.update_submodules(submodule.ipython_parent())
736 submodule.update_submodules(submodule.ipython_parent())
734 elif status == 'unclean':
737 elif status == 'unclean':
735 self.log.warn("components submodule unclean, you may see 404s on static/components")
738 self.log.warn("components submodule unclean, you may see 404s on static/components")
736 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
739 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
737
740
738 @catch_config_error
741 @catch_config_error
739 def initialize(self, argv=None):
742 def initialize(self, argv=None):
740 super(NotebookApp, self).initialize(argv)
743 super(NotebookApp, self).initialize(argv)
741 self.init_logging()
744 self.init_logging()
742 self.init_kernel_argv()
745 self.init_kernel_argv()
743 self.init_configurables()
746 self.init_configurables()
744 self.init_components()
747 self.init_components()
745 self.init_webapp()
748 self.init_webapp()
746 self.init_signal()
749 self.init_signal()
747
750
748 def cleanup_kernels(self):
751 def cleanup_kernels(self):
749 """Shutdown all kernels.
752 """Shutdown all kernels.
750
753
751 The kernels will shutdown themselves when this process no longer exists,
754 The kernels will shutdown themselves when this process no longer exists,
752 but explicit shutdown allows the KernelManagers to cleanup the connection files.
755 but explicit shutdown allows the KernelManagers to cleanup the connection files.
753 """
756 """
754 self.log.info('Shutting down kernels')
757 self.log.info('Shutting down kernels')
755 self.kernel_manager.shutdown_all()
758 self.kernel_manager.shutdown_all()
756
759
757 def notebook_info(self):
760 def notebook_info(self):
758 "Return the current working directory and the server url information"
761 "Return the current working directory and the server url information"
759 info = self.notebook_manager.info_string() + "\n"
762 info = self.notebook_manager.info_string() + "\n"
760 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
763 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
761 return info + "The IPython Notebook is running at: %s" % self.display_url
764 return info + "The IPython Notebook is running at: %s" % self.display_url
762
765
763 def server_info(self):
766 def server_info(self):
764 """Return a JSONable dict of information about this server."""
767 """Return a JSONable dict of information about this server."""
765 return {'url': self.connection_url,
768 return {'url': self.connection_url,
766 'hostname': self.ip if self.ip else 'localhost',
769 'hostname': self.ip if self.ip else 'localhost',
767 'port': self.port,
770 'port': self.port,
768 'secure': bool(self.certfile),
771 'secure': bool(self.certfile),
769 'base_url': self.base_url,
772 'base_url': self.base_url,
770 'notebook_dir': os.path.abspath(self.notebook_dir),
773 'notebook_dir': os.path.abspath(self.notebook_dir),
771 }
774 }
772
775
773 def write_server_info_file(self):
776 def write_server_info_file(self):
774 """Write the result of server_info() to the JSON file info_file."""
777 """Write the result of server_info() to the JSON file info_file."""
775 with open(self.info_file, 'w') as f:
778 with open(self.info_file, 'w') as f:
776 json.dump(self.server_info(), f, indent=2)
779 json.dump(self.server_info(), f, indent=2)
777
780
778 def remove_server_info_file(self):
781 def remove_server_info_file(self):
779 """Remove the nbserver-<pid>.json file created for this server.
782 """Remove the nbserver-<pid>.json file created for this server.
780
783
781 Ignores the error raised when the file has already been removed.
784 Ignores the error raised when the file has already been removed.
782 """
785 """
783 try:
786 try:
784 os.unlink(self.info_file)
787 os.unlink(self.info_file)
785 except OSError as e:
788 except OSError as e:
786 if e.errno != errno.ENOENT:
789 if e.errno != errno.ENOENT:
787 raise
790 raise
788
791
789 def start(self):
792 def start(self):
790 """ Start the IPython Notebook server app, after initialization
793 """ Start the IPython Notebook server app, after initialization
791
794
792 This method takes no arguments so all configuration and initialization
795 This method takes no arguments so all configuration and initialization
793 must be done prior to calling this method."""
796 must be done prior to calling this method."""
794 if self.subapp is not None:
797 if self.subapp is not None:
795 return self.subapp.start()
798 return self.subapp.start()
796
799
797 info = self.log.info
800 info = self.log.info
798 for line in self.notebook_info().split("\n"):
801 for line in self.notebook_info().split("\n"):
799 info(line)
802 info(line)
800 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
803 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
801
804
802 self.write_server_info_file()
805 self.write_server_info_file()
803
806
804 if self.open_browser or self.file_to_run:
807 if self.open_browser or self.file_to_run:
805 try:
808 try:
806 browser = webbrowser.get(self.browser or None)
809 browser = webbrowser.get(self.browser or None)
807 except webbrowser.Error as e:
810 except webbrowser.Error as e:
808 self.log.warn('No web browser found: %s.' % e)
811 self.log.warn('No web browser found: %s.' % e)
809 browser = None
812 browser = None
810
813
811 if self.file_to_run:
814 if self.file_to_run:
812 fullpath = os.path.join(self.notebook_dir, self.file_to_run)
815 fullpath = os.path.join(self.notebook_dir, self.file_to_run)
813 if not os.path.exists(fullpath):
816 if not os.path.exists(fullpath):
814 self.log.critical("%s does not exist" % fullpath)
817 self.log.critical("%s does not exist" % fullpath)
815 self.exit(1)
818 self.exit(1)
816
819
817 uri = url_path_join('notebooks', self.file_to_run)
820 uri = url_path_join('notebooks', self.file_to_run)
818 else:
821 else:
819 uri = 'tree'
822 uri = 'tree'
820 if browser:
823 if browser:
821 b = lambda : browser.open(url_path_join(self.connection_url, uri),
824 b = lambda : browser.open(url_path_join(self.connection_url, uri),
822 new=2)
825 new=2)
823 threading.Thread(target=b).start()
826 threading.Thread(target=b).start()
824 try:
827 try:
825 ioloop.IOLoop.instance().start()
828 ioloop.IOLoop.instance().start()
826 except KeyboardInterrupt:
829 except KeyboardInterrupt:
827 info("Interrupted...")
830 info("Interrupted...")
828 finally:
831 finally:
829 self.cleanup_kernels()
832 self.cleanup_kernels()
830 self.remove_server_info_file()
833 self.remove_server_info_file()
831
834
832
835
833 def list_running_servers(profile='default'):
836 def list_running_servers(profile='default'):
834 """Iterate over the server info files of running notebook servers.
837 """Iterate over the server info files of running notebook servers.
835
838
836 Given a profile name, find nbserver-* files in the security directory of
839 Given a profile name, find nbserver-* files in the security directory of
837 that profile, and yield dicts of their information, each one pertaining to
840 that profile, and yield dicts of their information, each one pertaining to
838 a currently running notebook server instance.
841 a currently running notebook server instance.
839 """
842 """
840 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile)
843 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile)
841 for file in os.listdir(pd.security_dir):
844 for file in os.listdir(pd.security_dir):
842 if file.startswith('nbserver-'):
845 if file.startswith('nbserver-'):
843 with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f:
846 with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f:
844 yield json.load(f)
847 yield json.load(f)
845
848
846 #-----------------------------------------------------------------------------
849 #-----------------------------------------------------------------------------
847 # Main entry point
850 # Main entry point
848 #-----------------------------------------------------------------------------
851 #-----------------------------------------------------------------------------
849
852
850 launch_new_instance = NotebookApp.launch_instance
853 launch_new_instance = NotebookApp.launch_instance
851
854
@@ -1,269 +1,259 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Keyboard management
9 // Keyboard management
10 //============================================================================
10 //============================================================================
11
11
12 IPython.namespace('IPython.keyboard');
12 IPython.namespace('IPython.keyboard');
13
13
14 IPython.keyboard = (function (IPython) {
14 IPython.keyboard = (function (IPython) {
15 "use strict";
15 "use strict";
16
16
17 // Setup global keycodes and inverse keycodes.
17 // Setup global keycodes and inverse keycodes.
18
18
19 // See http://unixpapa.com/js/key.html for a complete description. The short of
19 // See http://unixpapa.com/js/key.html for a complete description. The short of
20 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
20 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
21 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
21 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
22 // but have minor differences.
22 // but have minor differences.
23
23
24 // These apply to Firefox, (Webkit and IE)
24 // These apply to Firefox, (Webkit and IE)
25 var _keycodes = {
25 var _keycodes = {
26 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
26 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
27 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
27 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
28 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
28 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
29 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
29 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
30 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
30 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
31 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
31 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
32 '\\ |': 220, '\' "': 222,
32 '\\ |': 220, '\' "': 222,
33 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
33 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
34 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
34 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
35 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
35 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
36 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
36 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
37 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
37 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
38 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
38 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
39 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
39 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
40 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
40 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
41 'insert': 45, 'delete': 46, 'numlock': 144,
41 'insert': 45, 'delete': 46, 'numlock': 144,
42 };
42 };
43
43
44 // These apply to Firefox and Opera
44 // These apply to Firefox and Opera
45 var _mozilla_keycodes = {
45 var _mozilla_keycodes = {
46 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
46 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
47 };
47 };
48
48
49 // This apply to Webkit and IE
49 // This apply to Webkit and IE
50 var _ie_keycodes = {
50 var _ie_keycodes = {
51 '; :': 186, '= +': 187, '- _': 189
51 '; :': 186, '= +': 187, '- _': 189
52 };
52 };
53
53
54 var browser = IPython.utils.browser[0];
54 var browser = IPython.utils.browser[0];
55 var platform = IPython.utils.platform;
55 var platform = IPython.utils.platform;
56
56
57 if (browser === 'Firefox' || browser === 'Opera' || browser === 'Netscape') {
57 if (browser === 'Firefox' || browser === 'Opera' || browser === 'Netscape') {
58 $.extend(_keycodes, _mozilla_keycodes);
58 $.extend(_keycodes, _mozilla_keycodes);
59 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
59 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
60 $.extend(_keycodes, _ie_keycodes);
60 $.extend(_keycodes, _ie_keycodes);
61 }
61 }
62
62
63 var keycodes = {};
63 var keycodes = {};
64 var inv_keycodes = {};
64 var inv_keycodes = {};
65 for (var name in _keycodes) {
65 for (var name in _keycodes) {
66 var names = name.split(' ');
66 var names = name.split(' ');
67 if (names.length === 1) {
67 if (names.length === 1) {
68 var n = names[0];
68 var n = names[0];
69 keycodes[n] = _keycodes[n];
69 keycodes[n] = _keycodes[n];
70 inv_keycodes[_keycodes[n]] = n;
70 inv_keycodes[_keycodes[n]] = n;
71 } else {
71 } else {
72 var primary = names[0];
72 var primary = names[0];
73 var secondary = names[1];
73 var secondary = names[1];
74 keycodes[primary] = _keycodes[name];
74 keycodes[primary] = _keycodes[name];
75 keycodes[secondary] = _keycodes[name];
75 keycodes[secondary] = _keycodes[name];
76 inv_keycodes[_keycodes[name]] = primary;
76 inv_keycodes[_keycodes[name]] = primary;
77 }
77 }
78 }
78 }
79
79
80 var normalize_key = function (key) {
80 var normalize_key = function (key) {
81 return inv_keycodes[keycodes[key]];
81 return inv_keycodes[keycodes[key]];
82 };
82 };
83
83
84 var normalize_shortcut = function (shortcut) {
84 var normalize_shortcut = function (shortcut) {
85 // Put a shortcut into normalized form:
85 // Put a shortcut into normalized form:
86 // 1. Make lowercase
86 // 1. Make lowercase
87 // 2. Replace cmd by meta
87 // 2. Replace cmd by meta
88 // 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
88 // 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
89 // 4. Normalize keys
89 // 4. Normalize keys
90 shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
90 shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
91 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
91 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
92 var values = shortcut.split("-");
92 var values = shortcut.split("-");
93 if (values.length === 1) {
93 if (values.length === 1) {
94 return normalize_key(values[0]);
94 return normalize_key(values[0]);
95 } else {
95 } else {
96 var modifiers = values.slice(0,-1);
96 var modifiers = values.slice(0,-1);
97 var key = normalize_key(values[values.length-1]);
97 var key = normalize_key(values[values.length-1]);
98 modifiers.sort();
98 modifiers.sort();
99 return modifiers.join('-') + '-' + key;
99 return modifiers.join('-') + '-' + key;
100 }
100 }
101 };
101 };
102
102
103 var shortcut_to_event = function (shortcut, type) {
103 var shortcut_to_event = function (shortcut, type) {
104 // Convert a shortcut (shift-r) to a jQuery Event object
104 // Convert a shortcut (shift-r) to a jQuery Event object
105 type = type || 'keydown';
105 type = type || 'keydown';
106 shortcut = normalize_shortcut(shortcut);
106 shortcut = normalize_shortcut(shortcut);
107 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
107 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
108 var values = shortcut.split("-");
108 var values = shortcut.split("-");
109 var modifiers = values.slice(0,-1);
109 var modifiers = values.slice(0,-1);
110 var key = values[values.length-1];
110 var key = values[values.length-1];
111 var opts = {which: keycodes[key]};
111 var opts = {which: keycodes[key]};
112 if (modifiers.indexOf('alt') !== -1) {opts.altKey = true;}
112 if (modifiers.indexOf('alt') !== -1) {opts.altKey = true;}
113 if (modifiers.indexOf('ctrl') !== -1) {opts.ctrlKey = true;}
113 if (modifiers.indexOf('ctrl') !== -1) {opts.ctrlKey = true;}
114 if (modifiers.indexOf('meta') !== -1) {opts.metaKey = true;}
114 if (modifiers.indexOf('meta') !== -1) {opts.metaKey = true;}
115 if (modifiers.indexOf('shift') !== -1) {opts.shiftKey = true;}
115 if (modifiers.indexOf('shift') !== -1) {opts.shiftKey = true;}
116 return $.Event(type, opts);
116 return $.Event(type, opts);
117 };
117 };
118
118
119 var event_to_shortcut = function (event) {
119 var event_to_shortcut = function (event) {
120 // Convert a jQuery Event object to a shortcut (shift-r)
120 // Convert a jQuery Event object to a shortcut (shift-r)
121 var shortcut = '';
121 var shortcut = '';
122 var key = inv_keycodes[event.which];
122 var key = inv_keycodes[event.which];
123 if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
123 if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
124 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl-';}
124 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl-';}
125 if (event.metaKey && key !== 'meta') {shortcut += 'meta-';}
125 if (event.metaKey && key !== 'meta') {shortcut += 'meta-';}
126 if (event.shiftKey && key !== 'shift') {shortcut += 'shift-';}
126 if (event.shiftKey && key !== 'shift') {shortcut += 'shift-';}
127 shortcut += key;
127 shortcut += key;
128 return shortcut;
128 return shortcut;
129 };
129 };
130
130
131 var trigger_keydown = function (shortcut, element) {
132 // Trigger shortcut keydown on an element
133 element = element || document;
134 element = $(element);
135 var event = shortcut_to_event(shortcut, 'keydown');
136 element.trigger(event);
137 };
138
139
140 // Shortcut manager class
131 // Shortcut manager class
141
132
142 var ShortcutManager = function (delay) {
133 var ShortcutManager = function (delay) {
143 this._shortcuts = {};
134 this._shortcuts = {};
144 this._counts = {};
135 this._counts = {};
145 this._timers = {};
136 this._timers = {};
146 this.delay = delay || 800; // delay in milliseconds
137 this.delay = delay || 800; // delay in milliseconds
147 };
138 };
148
139
149 ShortcutManager.prototype.help = function () {
140 ShortcutManager.prototype.help = function () {
150 var help = [];
141 var help = [];
151 for (var shortcut in this._shortcuts) {
142 for (var shortcut in this._shortcuts) {
152 var help_string = this._shortcuts[shortcut]['help'];
143 var help_string = this._shortcuts[shortcut]['help'];
153 var help_index = this._shortcuts[shortcut]['help_index'];
144 var help_index = this._shortcuts[shortcut]['help_index'];
154 if (help_string) {
145 if (help_string) {
155 if (platform === 'MacOS') {
146 if (platform === 'MacOS') {
156 shortcut = shortcut.replace('meta', 'cmd');
147 shortcut = shortcut.replace('meta', 'cmd');
157 }
148 }
158 help.push({
149 help.push({
159 shortcut: shortcut,
150 shortcut: shortcut,
160 help: help_string,
151 help: help_string,
161 help_index: help_index}
152 help_index: help_index}
162 );
153 );
163 }
154 }
164 }
155 }
165 help.sort(function (a, b) {
156 help.sort(function (a, b) {
166 if (a.help_index > b.help_index)
157 if (a.help_index > b.help_index)
167 return 1;
158 return 1;
168 if (a.help_index < b.help_index)
159 if (a.help_index < b.help_index)
169 return -1;
160 return -1;
170 return 0;
161 return 0;
171 });
162 });
172 return help;
163 return help;
173 };
164 };
174
165
175 ShortcutManager.prototype.clear_shortcuts = function () {
166 ShortcutManager.prototype.clear_shortcuts = function () {
176 this._shortcuts = {};
167 this._shortcuts = {};
177 };
168 };
178
169
179 ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
170 ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
180 if (typeof(data) === 'function') {
171 if (typeof(data) === 'function') {
181 data = {help: '', help_index: '', handler: data};
172 data = {help: '', help_index: '', handler: data};
182 }
173 }
183 data.help_index = data.help_index || '';
174 data.help_index = data.help_index || '';
184 data.help = data.help || '';
175 data.help = data.help || '';
185 data.count = data.count || 1;
176 data.count = data.count || 1;
186 if (data.help_index === '') {
177 if (data.help_index === '') {
187 data.help_index = 'zz';
178 data.help_index = 'zz';
188 }
179 }
189 shortcut = normalize_shortcut(shortcut);
180 shortcut = normalize_shortcut(shortcut);
190 this._counts[shortcut] = 0;
181 this._counts[shortcut] = 0;
191 this._shortcuts[shortcut] = data;
182 this._shortcuts[shortcut] = data;
192 if (!suppress_help_update) {
183 if (!suppress_help_update) {
193 // update the keyboard shortcuts notebook help
184 // update the keyboard shortcuts notebook help
194 $([IPython.events]).trigger('rebuild.QuickHelp');
185 $([IPython.events]).trigger('rebuild.QuickHelp');
195 }
186 }
196 };
187 };
197
188
198 ShortcutManager.prototype.add_shortcuts = function (data) {
189 ShortcutManager.prototype.add_shortcuts = function (data) {
199 for (var shortcut in data) {
190 for (var shortcut in data) {
200 this.add_shortcut(shortcut, data[shortcut], true);
191 this.add_shortcut(shortcut, data[shortcut], true);
201 }
192 }
202 // update the keyboard shortcuts notebook help
193 // update the keyboard shortcuts notebook help
203 $([IPython.events]).trigger('rebuild.QuickHelp');
194 $([IPython.events]).trigger('rebuild.QuickHelp');
204 };
195 };
205
196
206 ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
197 ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
207 shortcut = normalize_shortcut(shortcut);
198 shortcut = normalize_shortcut(shortcut);
208 delete this._counts[shortcut];
199 delete this._counts[shortcut];
209 delete this._shortcuts[shortcut];
200 delete this._shortcuts[shortcut];
210 if (!suppress_help_update) {
201 if (!suppress_help_update) {
211 // update the keyboard shortcuts notebook help
202 // update the keyboard shortcuts notebook help
212 $([IPython.events]).trigger('rebuild.QuickHelp');
203 $([IPython.events]).trigger('rebuild.QuickHelp');
213 }
204 }
214 };
205 };
215
206
216 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
207 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
217 var that = this;
208 var that = this;
218 var c = this._counts;
209 var c = this._counts;
219 var t = this._timers;
210 var t = this._timers;
220 var timer = null;
211 var timer = null;
221 if (c[shortcut] === data.count-1) {
212 if (c[shortcut] === data.count-1) {
222 c[shortcut] = 0;
213 c[shortcut] = 0;
223 var timer = t[shortcut];
214 var timer = t[shortcut];
224 if (timer) {clearTimeout(timer); delete t[shortcut];}
215 if (timer) {clearTimeout(timer); delete t[shortcut];}
225 return data.handler(event);
216 return data.handler(event);
226 } else {
217 } else {
227 c[shortcut] = c[shortcut] + 1;
218 c[shortcut] = c[shortcut] + 1;
228 timer = setTimeout(function () {
219 timer = setTimeout(function () {
229 c[shortcut] = 0;
220 c[shortcut] = 0;
230 }, that.delay);
221 }, that.delay);
231 t[shortcut] = timer;
222 t[shortcut] = timer;
232 }
223 }
233 return false;
224 return false;
234 };
225 };
235
226
236 ShortcutManager.prototype.call_handler = function (event) {
227 ShortcutManager.prototype.call_handler = function (event) {
237 var shortcut = event_to_shortcut(event);
228 var shortcut = event_to_shortcut(event);
238 var data = this._shortcuts[shortcut];
229 var data = this._shortcuts[shortcut];
239 if (data) {
230 if (data) {
240 var handler = data['handler'];
231 var handler = data['handler'];
241 if (handler) {
232 if (handler) {
242 if (data.count === 1) {
233 if (data.count === 1) {
243 return handler(event);
234 return handler(event);
244 } else if (data.count > 1) {
235 } else if (data.count > 1) {
245 return this.count_handler(shortcut, event, data);
236 return this.count_handler(shortcut, event, data);
246 }
237 }
247 }
238 }
248 }
239 }
249 return true;
240 return true;
250 };
241 };
251
242
252 ShortcutManager.prototype.handles = function (event) {
243 ShortcutManager.prototype.handles = function (event) {
253 var shortcut = event_to_shortcut(event);
244 var shortcut = event_to_shortcut(event);
254 var data = this._shortcuts[shortcut];
245 var data = this._shortcuts[shortcut];
255 return !( data === undefined )
246 return !( data === undefined || data.handler === undefined )
256 }
247 }
257
248
258 return {
249 return {
259 keycodes : keycodes,
250 keycodes : keycodes,
260 inv_keycodes : inv_keycodes,
251 inv_keycodes : inv_keycodes,
261 ShortcutManager : ShortcutManager,
252 ShortcutManager : ShortcutManager,
262 normalize_key : normalize_key,
253 normalize_key : normalize_key,
263 normalize_shortcut : normalize_shortcut,
254 normalize_shortcut : normalize_shortcut,
264 shortcut_to_event : shortcut_to_event,
255 shortcut_to_event : shortcut_to_event,
265 event_to_shortcut : event_to_shortcut,
256 event_to_shortcut : event_to_shortcut
266 trigger_keydown : trigger_keydown
267 };
257 };
268
258
269 }(IPython));
259 }(IPython));
@@ -1,2407 +1,2413 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Notebook
9 // Notebook
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 /**
17 /**
18 * A notebook contains and manages cells.
18 * A notebook contains and manages cells.
19 *
19 *
20 * @class Notebook
20 * @class Notebook
21 * @constructor
21 * @constructor
22 * @param {String} selector A jQuery selector for the notebook's DOM element
22 * @param {String} selector A jQuery selector for the notebook's DOM element
23 * @param {Object} [options] A config object
23 * @param {Object} [options] A config object
24 */
24 */
25 var Notebook = function (selector, options) {
25 var Notebook = function (selector, options) {
26 this.options = options = options || {};
26 this.options = options = options || {};
27 this.base_url = options.base_url;
27 this.base_url = options.base_url;
28 this.notebook_path = options.notebook_path;
28 this.notebook_path = options.notebook_path;
29 this.notebook_name = options.notebook_name;
29 this.notebook_name = options.notebook_name;
30 this.element = $(selector);
30 this.element = $(selector);
31 this.element.scroll();
31 this.element.scroll();
32 this.element.data("notebook", this);
32 this.element.data("notebook", this);
33 this.next_prompt_number = 1;
33 this.next_prompt_number = 1;
34 this.session = null;
34 this.session = null;
35 this.kernel = null;
35 this.kernel = null;
36 this.clipboard = null;
36 this.clipboard = null;
37 this.undelete_backup = null;
37 this.undelete_backup = null;
38 this.undelete_index = null;
38 this.undelete_index = null;
39 this.undelete_below = false;
39 this.undelete_below = false;
40 this.paste_enabled = false;
40 this.paste_enabled = false;
41 // It is important to start out in command mode to match the intial mode
41 // It is important to start out in command mode to match the intial mode
42 // of the KeyboardManager.
42 // of the KeyboardManager.
43 this.mode = 'command';
43 this.mode = 'command';
44 this.set_dirty(false);
44 this.set_dirty(false);
45 this.metadata = {};
45 this.metadata = {};
46 this._checkpoint_after_save = false;
46 this._checkpoint_after_save = false;
47 this.last_checkpoint = null;
47 this.last_checkpoint = null;
48 this.checkpoints = [];
48 this.checkpoints = [];
49 this.autosave_interval = 0;
49 this.autosave_interval = 0;
50 this.autosave_timer = null;
50 this.autosave_timer = null;
51 // autosave *at most* every two minutes
51 // autosave *at most* every two minutes
52 this.minimum_autosave_interval = 120000;
52 this.minimum_autosave_interval = 120000;
53 // single worksheet for now
53 // single worksheet for now
54 this.worksheet_metadata = {};
54 this.worksheet_metadata = {};
55 this.notebook_name_blacklist_re = /[\/\\:]/;
55 this.notebook_name_blacklist_re = /[\/\\:]/;
56 this.nbformat = 3; // Increment this when changing the nbformat
56 this.nbformat = 3; // Increment this when changing the nbformat
57 this.nbformat_minor = 0; // Increment this when changing the nbformat
57 this.nbformat_minor = 0; // Increment this when changing the nbformat
58 this.style();
58 this.style();
59 this.create_elements();
59 this.create_elements();
60 this.bind_events();
60 this.bind_events();
61 this.save_notebook = function() { // don't allow save until notebook_loaded
62 this.save_notebook_error(null, null, "Load failed, save is disabled");
63 };
61 };
64 };
62
65
63 /**
66 /**
64 * Tweak the notebook's CSS style.
67 * Tweak the notebook's CSS style.
65 *
68 *
66 * @method style
69 * @method style
67 */
70 */
68 Notebook.prototype.style = function () {
71 Notebook.prototype.style = function () {
69 $('div#notebook').addClass('border-box-sizing');
72 $('div#notebook').addClass('border-box-sizing');
70 };
73 };
71
74
72 /**
75 /**
73 * Create an HTML and CSS representation of the notebook.
76 * Create an HTML and CSS representation of the notebook.
74 *
77 *
75 * @method create_elements
78 * @method create_elements
76 */
79 */
77 Notebook.prototype.create_elements = function () {
80 Notebook.prototype.create_elements = function () {
78 var that = this;
81 var that = this;
79 this.element.attr('tabindex','-1');
82 this.element.attr('tabindex','-1');
80 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
83 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
81 // We add this end_space div to the end of the notebook div to:
84 // We add this end_space div to the end of the notebook div to:
82 // i) provide a margin between the last cell and the end of the notebook
85 // i) provide a margin between the last cell and the end of the notebook
83 // ii) to prevent the div from scrolling up when the last cell is being
86 // ii) to prevent the div from scrolling up when the last cell is being
84 // edited, but is too low on the page, which browsers will do automatically.
87 // edited, but is too low on the page, which browsers will do automatically.
85 var end_space = $('<div/>').addClass('end_space');
88 var end_space = $('<div/>').addClass('end_space');
86 end_space.dblclick(function (e) {
89 end_space.dblclick(function (e) {
87 var ncells = that.ncells();
90 var ncells = that.ncells();
88 that.insert_cell_below('code',ncells-1);
91 that.insert_cell_below('code',ncells-1);
89 });
92 });
90 this.element.append(this.container);
93 this.element.append(this.container);
91 this.container.append(end_space);
94 this.container.append(end_space);
92 };
95 };
93
96
94 /**
97 /**
95 * Bind JavaScript events: key presses and custom IPython events.
98 * Bind JavaScript events: key presses and custom IPython events.
96 *
99 *
97 * @method bind_events
100 * @method bind_events
98 */
101 */
99 Notebook.prototype.bind_events = function () {
102 Notebook.prototype.bind_events = function () {
100 var that = this;
103 var that = this;
101
104
102 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
105 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
103 var index = that.find_cell_index(data.cell);
106 var index = that.find_cell_index(data.cell);
104 var new_cell = that.insert_cell_below('code',index);
107 var new_cell = that.insert_cell_below('code',index);
105 new_cell.set_text(data.text);
108 new_cell.set_text(data.text);
106 that.dirty = true;
109 that.dirty = true;
107 });
110 });
108
111
109 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
112 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
110 that.dirty = data.value;
113 that.dirty = data.value;
111 });
114 });
112
115
113 $([IPython.events]).on('trust_changed.Notebook', function (event, data) {
116 $([IPython.events]).on('trust_changed.Notebook', function (event, data) {
114 that.trusted = data.value;
117 that.trusted = data.value;
115 });
118 });
116
119
117 $([IPython.events]).on('select.Cell', function (event, data) {
120 $([IPython.events]).on('select.Cell', function (event, data) {
118 var index = that.find_cell_index(data.cell);
121 var index = that.find_cell_index(data.cell);
119 that.select(index);
122 that.select(index);
120 });
123 });
121
124
122 $([IPython.events]).on('edit_mode.Cell', function (event, data) {
125 $([IPython.events]).on('edit_mode.Cell', function (event, data) {
123 that.handle_edit_mode(data.cell);
126 that.handle_edit_mode(data.cell);
124 });
127 });
125
128
126 $([IPython.events]).on('command_mode.Cell', function (event, data) {
129 $([IPython.events]).on('command_mode.Cell', function (event, data) {
127 that.handle_command_mode(data.cell);
130 that.handle_command_mode(data.cell);
128 });
131 });
129
132
130 $([IPython.events]).on('status_autorestarting.Kernel', function () {
133 $([IPython.events]).on('status_autorestarting.Kernel', function () {
131 IPython.dialog.modal({
134 IPython.dialog.modal({
132 title: "Kernel Restarting",
135 title: "Kernel Restarting",
133 body: "The kernel appears to have died. It will restart automatically.",
136 body: "The kernel appears to have died. It will restart automatically.",
134 buttons: {
137 buttons: {
135 OK : {
138 OK : {
136 class : "btn-primary"
139 class : "btn-primary"
137 }
140 }
138 }
141 }
139 });
142 });
140 });
143 });
141
144
142 var collapse_time = function (time) {
145 var collapse_time = function (time) {
143 var app_height = $('#ipython-main-app').height(); // content height
146 var app_height = $('#ipython-main-app').height(); // content height
144 var splitter_height = $('div#pager_splitter').outerHeight(true);
147 var splitter_height = $('div#pager_splitter').outerHeight(true);
145 var new_height = app_height - splitter_height;
148 var new_height = app_height - splitter_height;
146 that.element.animate({height : new_height + 'px'}, time);
149 that.element.animate({height : new_height + 'px'}, time);
147 };
150 };
148
151
149 this.element.bind('collapse_pager', function (event, extrap) {
152 this.element.bind('collapse_pager', function (event, extrap) {
150 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
153 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
151 collapse_time(time);
154 collapse_time(time);
152 });
155 });
153
156
154 var expand_time = function (time) {
157 var expand_time = function (time) {
155 var app_height = $('#ipython-main-app').height(); // content height
158 var app_height = $('#ipython-main-app').height(); // content height
156 var splitter_height = $('div#pager_splitter').outerHeight(true);
159 var splitter_height = $('div#pager_splitter').outerHeight(true);
157 var pager_height = $('div#pager').outerHeight(true);
160 var pager_height = $('div#pager').outerHeight(true);
158 var new_height = app_height - pager_height - splitter_height;
161 var new_height = app_height - pager_height - splitter_height;
159 that.element.animate({height : new_height + 'px'}, time);
162 that.element.animate({height : new_height + 'px'}, time);
160 };
163 };
161
164
162 this.element.bind('expand_pager', function (event, extrap) {
165 this.element.bind('expand_pager', function (event, extrap) {
163 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
166 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
164 expand_time(time);
167 expand_time(time);
165 });
168 });
166
169
167 // Firefox 22 broke $(window).on("beforeunload")
170 // Firefox 22 broke $(window).on("beforeunload")
168 // I'm not sure why or how.
171 // I'm not sure why or how.
169 window.onbeforeunload = function (e) {
172 window.onbeforeunload = function (e) {
170 // TODO: Make killing the kernel configurable.
173 // TODO: Make killing the kernel configurable.
171 var kill_kernel = false;
174 var kill_kernel = false;
172 if (kill_kernel) {
175 if (kill_kernel) {
173 that.session.kill_kernel();
176 that.session.kill_kernel();
174 }
177 }
175 // if we are autosaving, trigger an autosave on nav-away.
178 // if we are autosaving, trigger an autosave on nav-away.
176 // still warn, because if we don't the autosave may fail.
179 // still warn, because if we don't the autosave may fail.
177 if (that.dirty) {
180 if (that.dirty) {
178 if ( that.autosave_interval ) {
181 if ( that.autosave_interval ) {
179 // schedule autosave in a timeout
182 // schedule autosave in a timeout
180 // this gives you a chance to forcefully discard changes
183 // this gives you a chance to forcefully discard changes
181 // by reloading the page if you *really* want to.
184 // by reloading the page if you *really* want to.
182 // the timer doesn't start until you *dismiss* the dialog.
185 // the timer doesn't start until you *dismiss* the dialog.
183 setTimeout(function () {
186 setTimeout(function () {
184 if (that.dirty) {
187 if (that.dirty) {
185 that.save_notebook();
188 that.save_notebook();
186 }
189 }
187 }, 1000);
190 }, 1000);
188 return "Autosave in progress, latest changes may be lost.";
191 return "Autosave in progress, latest changes may be lost.";
189 } else {
192 } else {
190 return "Unsaved changes will be lost.";
193 return "Unsaved changes will be lost.";
191 }
194 }
192 }
195 }
193 // Null is the *only* return value that will make the browser not
196 // Null is the *only* return value that will make the browser not
194 // pop up the "don't leave" dialog.
197 // pop up the "don't leave" dialog.
195 return null;
198 return null;
196 };
199 };
197 };
200 };
198
201
199 /**
202 /**
200 * Set the dirty flag, and trigger the set_dirty.Notebook event
203 * Set the dirty flag, and trigger the set_dirty.Notebook event
201 *
204 *
202 * @method set_dirty
205 * @method set_dirty
203 */
206 */
204 Notebook.prototype.set_dirty = function (value) {
207 Notebook.prototype.set_dirty = function (value) {
205 if (value === undefined) {
208 if (value === undefined) {
206 value = true;
209 value = true;
207 }
210 }
208 if (this.dirty == value) {
211 if (this.dirty == value) {
209 return;
212 return;
210 }
213 }
211 $([IPython.events]).trigger('set_dirty.Notebook', {value: value});
214 $([IPython.events]).trigger('set_dirty.Notebook', {value: value});
212 };
215 };
213
216
214 /**
217 /**
215 * Scroll the top of the page to a given cell.
218 * Scroll the top of the page to a given cell.
216 *
219 *
217 * @method scroll_to_cell
220 * @method scroll_to_cell
218 * @param {Number} cell_number An index of the cell to view
221 * @param {Number} cell_number An index of the cell to view
219 * @param {Number} time Animation time in milliseconds
222 * @param {Number} time Animation time in milliseconds
220 * @return {Number} Pixel offset from the top of the container
223 * @return {Number} Pixel offset from the top of the container
221 */
224 */
222 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
225 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
223 var cells = this.get_cells();
226 var cells = this.get_cells();
224 time = time || 0;
227 time = time || 0;
225 cell_number = Math.min(cells.length-1,cell_number);
228 cell_number = Math.min(cells.length-1,cell_number);
226 cell_number = Math.max(0 ,cell_number);
229 cell_number = Math.max(0 ,cell_number);
227 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
230 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
228 this.element.animate({scrollTop:scroll_value}, time);
231 this.element.animate({scrollTop:scroll_value}, time);
229 return scroll_value;
232 return scroll_value;
230 };
233 };
231
234
232 /**
235 /**
233 * Scroll to the bottom of the page.
236 * Scroll to the bottom of the page.
234 *
237 *
235 * @method scroll_to_bottom
238 * @method scroll_to_bottom
236 */
239 */
237 Notebook.prototype.scroll_to_bottom = function () {
240 Notebook.prototype.scroll_to_bottom = function () {
238 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
241 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
239 };
242 };
240
243
241 /**
244 /**
242 * Scroll to the top of the page.
245 * Scroll to the top of the page.
243 *
246 *
244 * @method scroll_to_top
247 * @method scroll_to_top
245 */
248 */
246 Notebook.prototype.scroll_to_top = function () {
249 Notebook.prototype.scroll_to_top = function () {
247 this.element.animate({scrollTop:0}, 0);
250 this.element.animate({scrollTop:0}, 0);
248 };
251 };
249
252
250 // Edit Notebook metadata
253 // Edit Notebook metadata
251
254
252 Notebook.prototype.edit_metadata = function () {
255 Notebook.prototype.edit_metadata = function () {
253 var that = this;
256 var that = this;
254 IPython.dialog.edit_metadata(this.metadata, function (md) {
257 IPython.dialog.edit_metadata(this.metadata, function (md) {
255 that.metadata = md;
258 that.metadata = md;
256 }, 'Notebook');
259 }, 'Notebook');
257 };
260 };
258
261
259 // Cell indexing, retrieval, etc.
262 // Cell indexing, retrieval, etc.
260
263
261 /**
264 /**
262 * Get all cell elements in the notebook.
265 * Get all cell elements in the notebook.
263 *
266 *
264 * @method get_cell_elements
267 * @method get_cell_elements
265 * @return {jQuery} A selector of all cell elements
268 * @return {jQuery} A selector of all cell elements
266 */
269 */
267 Notebook.prototype.get_cell_elements = function () {
270 Notebook.prototype.get_cell_elements = function () {
268 return this.container.children("div.cell");
271 return this.container.children("div.cell");
269 };
272 };
270
273
271 /**
274 /**
272 * Get a particular cell element.
275 * Get a particular cell element.
273 *
276 *
274 * @method get_cell_element
277 * @method get_cell_element
275 * @param {Number} index An index of a cell to select
278 * @param {Number} index An index of a cell to select
276 * @return {jQuery} A selector of the given cell.
279 * @return {jQuery} A selector of the given cell.
277 */
280 */
278 Notebook.prototype.get_cell_element = function (index) {
281 Notebook.prototype.get_cell_element = function (index) {
279 var result = null;
282 var result = null;
280 var e = this.get_cell_elements().eq(index);
283 var e = this.get_cell_elements().eq(index);
281 if (e.length !== 0) {
284 if (e.length !== 0) {
282 result = e;
285 result = e;
283 }
286 }
284 return result;
287 return result;
285 };
288 };
286
289
287 /**
290 /**
288 * Try to get a particular cell by msg_id.
291 * Try to get a particular cell by msg_id.
289 *
292 *
290 * @method get_msg_cell
293 * @method get_msg_cell
291 * @param {String} msg_id A message UUID
294 * @param {String} msg_id A message UUID
292 * @return {Cell} Cell or null if no cell was found.
295 * @return {Cell} Cell or null if no cell was found.
293 */
296 */
294 Notebook.prototype.get_msg_cell = function (msg_id) {
297 Notebook.prototype.get_msg_cell = function (msg_id) {
295 return IPython.CodeCell.msg_cells[msg_id] || null;
298 return IPython.CodeCell.msg_cells[msg_id] || null;
296 };
299 };
297
300
298 /**
301 /**
299 * Count the cells in this notebook.
302 * Count the cells in this notebook.
300 *
303 *
301 * @method ncells
304 * @method ncells
302 * @return {Number} The number of cells in this notebook
305 * @return {Number} The number of cells in this notebook
303 */
306 */
304 Notebook.prototype.ncells = function () {
307 Notebook.prototype.ncells = function () {
305 return this.get_cell_elements().length;
308 return this.get_cell_elements().length;
306 };
309 };
307
310
308 /**
311 /**
309 * Get all Cell objects in this notebook.
312 * Get all Cell objects in this notebook.
310 *
313 *
311 * @method get_cells
314 * @method get_cells
312 * @return {Array} This notebook's Cell objects
315 * @return {Array} This notebook's Cell objects
313 */
316 */
314 // TODO: we are often calling cells as cells()[i], which we should optimize
317 // TODO: we are often calling cells as cells()[i], which we should optimize
315 // to cells(i) or a new method.
318 // to cells(i) or a new method.
316 Notebook.prototype.get_cells = function () {
319 Notebook.prototype.get_cells = function () {
317 return this.get_cell_elements().toArray().map(function (e) {
320 return this.get_cell_elements().toArray().map(function (e) {
318 return $(e).data("cell");
321 return $(e).data("cell");
319 });
322 });
320 };
323 };
321
324
322 /**
325 /**
323 * Get a Cell object from this notebook.
326 * Get a Cell object from this notebook.
324 *
327 *
325 * @method get_cell
328 * @method get_cell
326 * @param {Number} index An index of a cell to retrieve
329 * @param {Number} index An index of a cell to retrieve
327 * @return {Cell} A particular cell
330 * @return {Cell} A particular cell
328 */
331 */
329 Notebook.prototype.get_cell = function (index) {
332 Notebook.prototype.get_cell = function (index) {
330 var result = null;
333 var result = null;
331 var ce = this.get_cell_element(index);
334 var ce = this.get_cell_element(index);
332 if (ce !== null) {
335 if (ce !== null) {
333 result = ce.data('cell');
336 result = ce.data('cell');
334 }
337 }
335 return result;
338 return result;
336 };
339 };
337
340
338 /**
341 /**
339 * Get the cell below a given cell.
342 * Get the cell below a given cell.
340 *
343 *
341 * @method get_next_cell
344 * @method get_next_cell
342 * @param {Cell} cell The provided cell
345 * @param {Cell} cell The provided cell
343 * @return {Cell} The next cell
346 * @return {Cell} The next cell
344 */
347 */
345 Notebook.prototype.get_next_cell = function (cell) {
348 Notebook.prototype.get_next_cell = function (cell) {
346 var result = null;
349 var result = null;
347 var index = this.find_cell_index(cell);
350 var index = this.find_cell_index(cell);
348 if (this.is_valid_cell_index(index+1)) {
351 if (this.is_valid_cell_index(index+1)) {
349 result = this.get_cell(index+1);
352 result = this.get_cell(index+1);
350 }
353 }
351 return result;
354 return result;
352 };
355 };
353
356
354 /**
357 /**
355 * Get the cell above a given cell.
358 * Get the cell above a given cell.
356 *
359 *
357 * @method get_prev_cell
360 * @method get_prev_cell
358 * @param {Cell} cell The provided cell
361 * @param {Cell} cell The provided cell
359 * @return {Cell} The previous cell
362 * @return {Cell} The previous cell
360 */
363 */
361 Notebook.prototype.get_prev_cell = function (cell) {
364 Notebook.prototype.get_prev_cell = function (cell) {
362 // TODO: off-by-one
365 // TODO: off-by-one
363 // nb.get_prev_cell(nb.get_cell(1)) is null
366 // nb.get_prev_cell(nb.get_cell(1)) is null
364 var result = null;
367 var result = null;
365 var index = this.find_cell_index(cell);
368 var index = this.find_cell_index(cell);
366 if (index !== null && index > 1) {
369 if (index !== null && index > 1) {
367 result = this.get_cell(index-1);
370 result = this.get_cell(index-1);
368 }
371 }
369 return result;
372 return result;
370 };
373 };
371
374
372 /**
375 /**
373 * Get the numeric index of a given cell.
376 * Get the numeric index of a given cell.
374 *
377 *
375 * @method find_cell_index
378 * @method find_cell_index
376 * @param {Cell} cell The provided cell
379 * @param {Cell} cell The provided cell
377 * @return {Number} The cell's numeric index
380 * @return {Number} The cell's numeric index
378 */
381 */
379 Notebook.prototype.find_cell_index = function (cell) {
382 Notebook.prototype.find_cell_index = function (cell) {
380 var result = null;
383 var result = null;
381 this.get_cell_elements().filter(function (index) {
384 this.get_cell_elements().filter(function (index) {
382 if ($(this).data("cell") === cell) {
385 if ($(this).data("cell") === cell) {
383 result = index;
386 result = index;
384 }
387 }
385 });
388 });
386 return result;
389 return result;
387 };
390 };
388
391
389 /**
392 /**
390 * Get a given index , or the selected index if none is provided.
393 * Get a given index , or the selected index if none is provided.
391 *
394 *
392 * @method index_or_selected
395 * @method index_or_selected
393 * @param {Number} index A cell's index
396 * @param {Number} index A cell's index
394 * @return {Number} The given index, or selected index if none is provided.
397 * @return {Number} The given index, or selected index if none is provided.
395 */
398 */
396 Notebook.prototype.index_or_selected = function (index) {
399 Notebook.prototype.index_or_selected = function (index) {
397 var i;
400 var i;
398 if (index === undefined || index === null) {
401 if (index === undefined || index === null) {
399 i = this.get_selected_index();
402 i = this.get_selected_index();
400 if (i === null) {
403 if (i === null) {
401 i = 0;
404 i = 0;
402 }
405 }
403 } else {
406 } else {
404 i = index;
407 i = index;
405 }
408 }
406 return i;
409 return i;
407 };
410 };
408
411
409 /**
412 /**
410 * Get the currently selected cell.
413 * Get the currently selected cell.
411 * @method get_selected_cell
414 * @method get_selected_cell
412 * @return {Cell} The selected cell
415 * @return {Cell} The selected cell
413 */
416 */
414 Notebook.prototype.get_selected_cell = function () {
417 Notebook.prototype.get_selected_cell = function () {
415 var index = this.get_selected_index();
418 var index = this.get_selected_index();
416 return this.get_cell(index);
419 return this.get_cell(index);
417 };
420 };
418
421
419 /**
422 /**
420 * Check whether a cell index is valid.
423 * Check whether a cell index is valid.
421 *
424 *
422 * @method is_valid_cell_index
425 * @method is_valid_cell_index
423 * @param {Number} index A cell index
426 * @param {Number} index A cell index
424 * @return True if the index is valid, false otherwise
427 * @return True if the index is valid, false otherwise
425 */
428 */
426 Notebook.prototype.is_valid_cell_index = function (index) {
429 Notebook.prototype.is_valid_cell_index = function (index) {
427 if (index !== null && index >= 0 && index < this.ncells()) {
430 if (index !== null && index >= 0 && index < this.ncells()) {
428 return true;
431 return true;
429 } else {
432 } else {
430 return false;
433 return false;
431 }
434 }
432 };
435 };
433
436
434 /**
437 /**
435 * Get the index of the currently selected cell.
438 * Get the index of the currently selected cell.
436
439
437 * @method get_selected_index
440 * @method get_selected_index
438 * @return {Number} The selected cell's numeric index
441 * @return {Number} The selected cell's numeric index
439 */
442 */
440 Notebook.prototype.get_selected_index = function () {
443 Notebook.prototype.get_selected_index = function () {
441 var result = null;
444 var result = null;
442 this.get_cell_elements().filter(function (index) {
445 this.get_cell_elements().filter(function (index) {
443 if ($(this).data("cell").selected === true) {
446 if ($(this).data("cell").selected === true) {
444 result = index;
447 result = index;
445 }
448 }
446 });
449 });
447 return result;
450 return result;
448 };
451 };
449
452
450
453
451 // Cell selection.
454 // Cell selection.
452
455
453 /**
456 /**
454 * Programmatically select a cell.
457 * Programmatically select a cell.
455 *
458 *
456 * @method select
459 * @method select
457 * @param {Number} index A cell's index
460 * @param {Number} index A cell's index
458 * @return {Notebook} This notebook
461 * @return {Notebook} This notebook
459 */
462 */
460 Notebook.prototype.select = function (index) {
463 Notebook.prototype.select = function (index) {
461 if (this.is_valid_cell_index(index)) {
464 if (this.is_valid_cell_index(index)) {
462 var sindex = this.get_selected_index();
465 var sindex = this.get_selected_index();
463 if (sindex !== null && index !== sindex) {
466 if (sindex !== null && index !== sindex) {
464 // If we are about to select a different cell, make sure we are
467 // If we are about to select a different cell, make sure we are
465 // first in command mode.
468 // first in command mode.
466 if (this.mode !== 'command') {
469 if (this.mode !== 'command') {
467 this.command_mode();
470 this.command_mode();
468 }
471 }
469 this.get_cell(sindex).unselect();
472 this.get_cell(sindex).unselect();
470 }
473 }
471 var cell = this.get_cell(index);
474 var cell = this.get_cell(index);
472 cell.select();
475 cell.select();
473 if (cell.cell_type === 'heading') {
476 if (cell.cell_type === 'heading') {
474 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
477 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
475 {'cell_type':cell.cell_type,level:cell.level}
478 {'cell_type':cell.cell_type,level:cell.level}
476 );
479 );
477 } else {
480 } else {
478 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
481 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
479 {'cell_type':cell.cell_type}
482 {'cell_type':cell.cell_type}
480 );
483 );
481 }
484 }
482 }
485 }
483 return this;
486 return this;
484 };
487 };
485
488
486 /**
489 /**
487 * Programmatically select the next cell.
490 * Programmatically select the next cell.
488 *
491 *
489 * @method select_next
492 * @method select_next
490 * @return {Notebook} This notebook
493 * @return {Notebook} This notebook
491 */
494 */
492 Notebook.prototype.select_next = function () {
495 Notebook.prototype.select_next = function () {
493 var index = this.get_selected_index();
496 var index = this.get_selected_index();
494 this.select(index+1);
497 this.select(index+1);
495 return this;
498 return this;
496 };
499 };
497
500
498 /**
501 /**
499 * Programmatically select the previous cell.
502 * Programmatically select the previous cell.
500 *
503 *
501 * @method select_prev
504 * @method select_prev
502 * @return {Notebook} This notebook
505 * @return {Notebook} This notebook
503 */
506 */
504 Notebook.prototype.select_prev = function () {
507 Notebook.prototype.select_prev = function () {
505 var index = this.get_selected_index();
508 var index = this.get_selected_index();
506 this.select(index-1);
509 this.select(index-1);
507 return this;
510 return this;
508 };
511 };
509
512
510
513
511 // Edit/Command mode
514 // Edit/Command mode
512
515
513 /**
516 /**
514 * Gets the index of the cell that is in edit mode.
517 * Gets the index of the cell that is in edit mode.
515 *
518 *
516 * @method get_edit_index
519 * @method get_edit_index
517 *
520 *
518 * @return index {int}
521 * @return index {int}
519 **/
522 **/
520 Notebook.prototype.get_edit_index = function () {
523 Notebook.prototype.get_edit_index = function () {
521 var result = null;
524 var result = null;
522 this.get_cell_elements().filter(function (index) {
525 this.get_cell_elements().filter(function (index) {
523 if ($(this).data("cell").mode === 'edit') {
526 if ($(this).data("cell").mode === 'edit') {
524 result = index;
527 result = index;
525 }
528 }
526 });
529 });
527 return result;
530 return result;
528 };
531 };
529
532
530 /**
533 /**
531 * Handle when a a cell blurs and the notebook should enter command mode.
534 * Handle when a a cell blurs and the notebook should enter command mode.
532 *
535 *
533 * @method handle_command_mode
536 * @method handle_command_mode
534 * @param [cell] {Cell} Cell to enter command mode on.
537 * @param [cell] {Cell} Cell to enter command mode on.
535 **/
538 **/
536 Notebook.prototype.handle_command_mode = function (cell) {
539 Notebook.prototype.handle_command_mode = function (cell) {
537 if (this.mode !== 'command') {
540 if (this.mode !== 'command') {
538 cell.command_mode();
541 cell.command_mode();
539 this.mode = 'command';
542 this.mode = 'command';
540 $([IPython.events]).trigger('command_mode.Notebook');
543 $([IPython.events]).trigger('command_mode.Notebook');
541 IPython.keyboard_manager.command_mode();
544 IPython.keyboard_manager.command_mode();
542 }
545 }
543 };
546 };
544
547
545 /**
548 /**
546 * Make the notebook enter command mode.
549 * Make the notebook enter command mode.
547 *
550 *
548 * @method command_mode
551 * @method command_mode
549 **/
552 **/
550 Notebook.prototype.command_mode = function () {
553 Notebook.prototype.command_mode = function () {
551 var cell = this.get_cell(this.get_edit_index());
554 var cell = this.get_cell(this.get_edit_index());
552 if (cell && this.mode !== 'command') {
555 if (cell && this.mode !== 'command') {
553 // We don't call cell.command_mode, but rather call cell.focus_cell()
556 // We don't call cell.command_mode, but rather call cell.focus_cell()
554 // which will blur and CM editor and trigger the call to
557 // which will blur and CM editor and trigger the call to
555 // handle_command_mode.
558 // handle_command_mode.
556 cell.focus_cell();
559 cell.focus_cell();
557 }
560 }
558 };
561 };
559
562
560 /**
563 /**
561 * Handle when a cell fires it's edit_mode event.
564 * Handle when a cell fires it's edit_mode event.
562 *
565 *
563 * @method handle_edit_mode
566 * @method handle_edit_mode
564 * @param [cell] {Cell} Cell to enter edit mode on.
567 * @param [cell] {Cell} Cell to enter edit mode on.
565 **/
568 **/
566 Notebook.prototype.handle_edit_mode = function (cell) {
569 Notebook.prototype.handle_edit_mode = function (cell) {
567 if (cell && this.mode !== 'edit') {
570 if (cell && this.mode !== 'edit') {
568 cell.edit_mode();
571 cell.edit_mode();
569 this.mode = 'edit';
572 this.mode = 'edit';
570 $([IPython.events]).trigger('edit_mode.Notebook');
573 $([IPython.events]).trigger('edit_mode.Notebook');
571 IPython.keyboard_manager.edit_mode();
574 IPython.keyboard_manager.edit_mode();
572 }
575 }
573 };
576 };
574
577
575 /**
578 /**
576 * Make a cell enter edit mode.
579 * Make a cell enter edit mode.
577 *
580 *
578 * @method edit_mode
581 * @method edit_mode
579 **/
582 **/
580 Notebook.prototype.edit_mode = function () {
583 Notebook.prototype.edit_mode = function () {
581 var cell = this.get_selected_cell();
584 var cell = this.get_selected_cell();
582 if (cell && this.mode !== 'edit') {
585 if (cell && this.mode !== 'edit') {
583 cell.unrender();
586 cell.unrender();
584 cell.focus_editor();
587 cell.focus_editor();
585 }
588 }
586 };
589 };
587
590
588 /**
591 /**
589 * Focus the currently selected cell.
592 * Focus the currently selected cell.
590 *
593 *
591 * @method focus_cell
594 * @method focus_cell
592 **/
595 **/
593 Notebook.prototype.focus_cell = function () {
596 Notebook.prototype.focus_cell = function () {
594 var cell = this.get_selected_cell();
597 var cell = this.get_selected_cell();
595 if (cell === null) {return;} // No cell is selected
598 if (cell === null) {return;} // No cell is selected
596 cell.focus_cell();
599 cell.focus_cell();
597 };
600 };
598
601
599 // Cell movement
602 // Cell movement
600
603
601 /**
604 /**
602 * Move given (or selected) cell up and select it.
605 * Move given (or selected) cell up and select it.
603 *
606 *
604 * @method move_cell_up
607 * @method move_cell_up
605 * @param [index] {integer} cell index
608 * @param [index] {integer} cell index
606 * @return {Notebook} This notebook
609 * @return {Notebook} This notebook
607 **/
610 **/
608 Notebook.prototype.move_cell_up = function (index) {
611 Notebook.prototype.move_cell_up = function (index) {
609 var i = this.index_or_selected(index);
612 var i = this.index_or_selected(index);
610 if (this.is_valid_cell_index(i) && i > 0) {
613 if (this.is_valid_cell_index(i) && i > 0) {
611 var pivot = this.get_cell_element(i-1);
614 var pivot = this.get_cell_element(i-1);
612 var tomove = this.get_cell_element(i);
615 var tomove = this.get_cell_element(i);
613 if (pivot !== null && tomove !== null) {
616 if (pivot !== null && tomove !== null) {
614 tomove.detach();
617 tomove.detach();
615 pivot.before(tomove);
618 pivot.before(tomove);
616 this.select(i-1);
619 this.select(i-1);
617 var cell = this.get_selected_cell();
620 var cell = this.get_selected_cell();
618 cell.focus_cell();
621 cell.focus_cell();
619 }
622 }
620 this.set_dirty(true);
623 this.set_dirty(true);
621 }
624 }
622 return this;
625 return this;
623 };
626 };
624
627
625
628
626 /**
629 /**
627 * Move given (or selected) cell down and select it
630 * Move given (or selected) cell down and select it
628 *
631 *
629 * @method move_cell_down
632 * @method move_cell_down
630 * @param [index] {integer} cell index
633 * @param [index] {integer} cell index
631 * @return {Notebook} This notebook
634 * @return {Notebook} This notebook
632 **/
635 **/
633 Notebook.prototype.move_cell_down = function (index) {
636 Notebook.prototype.move_cell_down = function (index) {
634 var i = this.index_or_selected(index);
637 var i = this.index_or_selected(index);
635 if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) {
638 if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) {
636 var pivot = this.get_cell_element(i+1);
639 var pivot = this.get_cell_element(i+1);
637 var tomove = this.get_cell_element(i);
640 var tomove = this.get_cell_element(i);
638 if (pivot !== null && tomove !== null) {
641 if (pivot !== null && tomove !== null) {
639 tomove.detach();
642 tomove.detach();
640 pivot.after(tomove);
643 pivot.after(tomove);
641 this.select(i+1);
644 this.select(i+1);
642 var cell = this.get_selected_cell();
645 var cell = this.get_selected_cell();
643 cell.focus_cell();
646 cell.focus_cell();
644 }
647 }
645 }
648 }
646 this.set_dirty();
649 this.set_dirty();
647 return this;
650 return this;
648 };
651 };
649
652
650
653
651 // Insertion, deletion.
654 // Insertion, deletion.
652
655
653 /**
656 /**
654 * Delete a cell from the notebook.
657 * Delete a cell from the notebook.
655 *
658 *
656 * @method delete_cell
659 * @method delete_cell
657 * @param [index] A cell's numeric index
660 * @param [index] A cell's numeric index
658 * @return {Notebook} This notebook
661 * @return {Notebook} This notebook
659 */
662 */
660 Notebook.prototype.delete_cell = function (index) {
663 Notebook.prototype.delete_cell = function (index) {
661 var i = this.index_or_selected(index);
664 var i = this.index_or_selected(index);
662 var cell = this.get_selected_cell();
665 var cell = this.get_selected_cell();
663 this.undelete_backup = cell.toJSON();
666 this.undelete_backup = cell.toJSON();
664 $('#undelete_cell').removeClass('disabled');
667 $('#undelete_cell').removeClass('disabled');
665 if (this.is_valid_cell_index(i)) {
668 if (this.is_valid_cell_index(i)) {
666 var old_ncells = this.ncells();
669 var old_ncells = this.ncells();
667 var ce = this.get_cell_element(i);
670 var ce = this.get_cell_element(i);
668 ce.remove();
671 ce.remove();
669 if (i === 0) {
672 if (i === 0) {
670 // Always make sure we have at least one cell.
673 // Always make sure we have at least one cell.
671 if (old_ncells === 1) {
674 if (old_ncells === 1) {
672 this.insert_cell_below('code');
675 this.insert_cell_below('code');
673 }
676 }
674 this.select(0);
677 this.select(0);
675 this.undelete_index = 0;
678 this.undelete_index = 0;
676 this.undelete_below = false;
679 this.undelete_below = false;
677 } else if (i === old_ncells-1 && i !== 0) {
680 } else if (i === old_ncells-1 && i !== 0) {
678 this.select(i-1);
681 this.select(i-1);
679 this.undelete_index = i - 1;
682 this.undelete_index = i - 1;
680 this.undelete_below = true;
683 this.undelete_below = true;
681 } else {
684 } else {
682 this.select(i);
685 this.select(i);
683 this.undelete_index = i;
686 this.undelete_index = i;
684 this.undelete_below = false;
687 this.undelete_below = false;
685 }
688 }
686 $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i});
689 $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i});
687 this.set_dirty(true);
690 this.set_dirty(true);
688 }
691 }
689 return this;
692 return this;
690 };
693 };
691
694
692 /**
695 /**
693 * Restore the most recently deleted cell.
696 * Restore the most recently deleted cell.
694 *
697 *
695 * @method undelete
698 * @method undelete
696 */
699 */
697 Notebook.prototype.undelete_cell = function() {
700 Notebook.prototype.undelete_cell = function() {
698 if (this.undelete_backup !== null && this.undelete_index !== null) {
701 if (this.undelete_backup !== null && this.undelete_index !== null) {
699 var current_index = this.get_selected_index();
702 var current_index = this.get_selected_index();
700 if (this.undelete_index < current_index) {
703 if (this.undelete_index < current_index) {
701 current_index = current_index + 1;
704 current_index = current_index + 1;
702 }
705 }
703 if (this.undelete_index >= this.ncells()) {
706 if (this.undelete_index >= this.ncells()) {
704 this.select(this.ncells() - 1);
707 this.select(this.ncells() - 1);
705 }
708 }
706 else {
709 else {
707 this.select(this.undelete_index);
710 this.select(this.undelete_index);
708 }
711 }
709 var cell_data = this.undelete_backup;
712 var cell_data = this.undelete_backup;
710 var new_cell = null;
713 var new_cell = null;
711 if (this.undelete_below) {
714 if (this.undelete_below) {
712 new_cell = this.insert_cell_below(cell_data.cell_type);
715 new_cell = this.insert_cell_below(cell_data.cell_type);
713 } else {
716 } else {
714 new_cell = this.insert_cell_above(cell_data.cell_type);
717 new_cell = this.insert_cell_above(cell_data.cell_type);
715 }
718 }
716 new_cell.fromJSON(cell_data);
719 new_cell.fromJSON(cell_data);
717 if (this.undelete_below) {
720 if (this.undelete_below) {
718 this.select(current_index+1);
721 this.select(current_index+1);
719 } else {
722 } else {
720 this.select(current_index);
723 this.select(current_index);
721 }
724 }
722 this.undelete_backup = null;
725 this.undelete_backup = null;
723 this.undelete_index = null;
726 this.undelete_index = null;
724 }
727 }
725 $('#undelete_cell').addClass('disabled');
728 $('#undelete_cell').addClass('disabled');
726 };
729 };
727
730
728 /**
731 /**
729 * Insert a cell so that after insertion the cell is at given index.
732 * Insert a cell so that after insertion the cell is at given index.
730 *
733 *
731 * Similar to insert_above, but index parameter is mandatory
734 * Similar to insert_above, but index parameter is mandatory
732 *
735 *
733 * Index will be brought back into the accissible range [0,n]
736 * Index will be brought back into the accissible range [0,n]
734 *
737 *
735 * @method insert_cell_at_index
738 * @method insert_cell_at_index
736 * @param type {string} in ['code','markdown','heading']
739 * @param type {string} in ['code','markdown','heading']
737 * @param [index] {int} a valid index where to inser cell
740 * @param [index] {int} a valid index where to inser cell
738 *
741 *
739 * @return cell {cell|null} created cell or null
742 * @return cell {cell|null} created cell or null
740 **/
743 **/
741 Notebook.prototype.insert_cell_at_index = function(type, index){
744 Notebook.prototype.insert_cell_at_index = function(type, index){
742
745
743 var ncells = this.ncells();
746 var ncells = this.ncells();
744 index = Math.min(index,ncells);
747 index = Math.min(index,ncells);
745 index = Math.max(index,0);
748 index = Math.max(index,0);
746 var cell = null;
749 var cell = null;
747
750
748 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
751 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
749 if (type === 'code') {
752 if (type === 'code') {
750 cell = new IPython.CodeCell(this.kernel);
753 cell = new IPython.CodeCell(this.kernel);
751 cell.set_input_prompt();
754 cell.set_input_prompt();
752 } else if (type === 'markdown') {
755 } else if (type === 'markdown') {
753 cell = new IPython.MarkdownCell();
756 cell = new IPython.MarkdownCell();
754 } else if (type === 'raw') {
757 } else if (type === 'raw') {
755 cell = new IPython.RawCell();
758 cell = new IPython.RawCell();
756 } else if (type === 'heading') {
759 } else if (type === 'heading') {
757 cell = new IPython.HeadingCell();
760 cell = new IPython.HeadingCell();
758 }
761 }
759
762
760 if(this._insert_element_at_index(cell.element,index)) {
763 if(this._insert_element_at_index(cell.element,index)) {
761 cell.render();
764 cell.render();
762 $([IPython.events]).trigger('create.Cell', {'cell': cell, 'index': index});
765 $([IPython.events]).trigger('create.Cell', {'cell': cell, 'index': index});
763 cell.refresh();
766 cell.refresh();
764 // We used to select the cell after we refresh it, but there
767 // We used to select the cell after we refresh it, but there
765 // are now cases were this method is called where select is
768 // are now cases were this method is called where select is
766 // not appropriate. The selection logic should be handled by the
769 // not appropriate. The selection logic should be handled by the
767 // caller of the the top level insert_cell methods.
770 // caller of the the top level insert_cell methods.
768 this.set_dirty(true);
771 this.set_dirty(true);
769 }
772 }
770 }
773 }
771 return cell;
774 return cell;
772
775
773 };
776 };
774
777
775 /**
778 /**
776 * Insert an element at given cell index.
779 * Insert an element at given cell index.
777 *
780 *
778 * @method _insert_element_at_index
781 * @method _insert_element_at_index
779 * @param element {dom element} a cell element
782 * @param element {dom element} a cell element
780 * @param [index] {int} a valid index where to inser cell
783 * @param [index] {int} a valid index where to inser cell
781 * @private
784 * @private
782 *
785 *
783 * return true if everything whent fine.
786 * return true if everything whent fine.
784 **/
787 **/
785 Notebook.prototype._insert_element_at_index = function(element, index){
788 Notebook.prototype._insert_element_at_index = function(element, index){
786 if (element === undefined){
789 if (element === undefined){
787 return false;
790 return false;
788 }
791 }
789
792
790 var ncells = this.ncells();
793 var ncells = this.ncells();
791
794
792 if (ncells === 0) {
795 if (ncells === 0) {
793 // special case append if empty
796 // special case append if empty
794 this.element.find('div.end_space').before(element);
797 this.element.find('div.end_space').before(element);
795 } else if ( ncells === index ) {
798 } else if ( ncells === index ) {
796 // special case append it the end, but not empty
799 // special case append it the end, but not empty
797 this.get_cell_element(index-1).after(element);
800 this.get_cell_element(index-1).after(element);
798 } else if (this.is_valid_cell_index(index)) {
801 } else if (this.is_valid_cell_index(index)) {
799 // otherwise always somewhere to append to
802 // otherwise always somewhere to append to
800 this.get_cell_element(index).before(element);
803 this.get_cell_element(index).before(element);
801 } else {
804 } else {
802 return false;
805 return false;
803 }
806 }
804
807
805 if (this.undelete_index !== null && index <= this.undelete_index) {
808 if (this.undelete_index !== null && index <= this.undelete_index) {
806 this.undelete_index = this.undelete_index + 1;
809 this.undelete_index = this.undelete_index + 1;
807 this.set_dirty(true);
810 this.set_dirty(true);
808 }
811 }
809 return true;
812 return true;
810 };
813 };
811
814
812 /**
815 /**
813 * Insert a cell of given type above given index, or at top
816 * Insert a cell of given type above given index, or at top
814 * of notebook if index smaller than 0.
817 * of notebook if index smaller than 0.
815 *
818 *
816 * default index value is the one of currently selected cell
819 * default index value is the one of currently selected cell
817 *
820 *
818 * @method insert_cell_above
821 * @method insert_cell_above
819 * @param type {string} cell type
822 * @param type {string} cell type
820 * @param [index] {integer}
823 * @param [index] {integer}
821 *
824 *
822 * @return handle to created cell or null
825 * @return handle to created cell or null
823 **/
826 **/
824 Notebook.prototype.insert_cell_above = function (type, index) {
827 Notebook.prototype.insert_cell_above = function (type, index) {
825 index = this.index_or_selected(index);
828 index = this.index_or_selected(index);
826 return this.insert_cell_at_index(type, index);
829 return this.insert_cell_at_index(type, index);
827 };
830 };
828
831
829 /**
832 /**
830 * Insert a cell of given type below given index, or at bottom
833 * Insert a cell of given type below given index, or at bottom
831 * of notebook if index greater thatn number of cell
834 * of notebook if index greater thatn number of cell
832 *
835 *
833 * default index value is the one of currently selected cell
836 * default index value is the one of currently selected cell
834 *
837 *
835 * @method insert_cell_below
838 * @method insert_cell_below
836 * @param type {string} cell type
839 * @param type {string} cell type
837 * @param [index] {integer}
840 * @param [index] {integer}
838 *
841 *
839 * @return handle to created cell or null
842 * @return handle to created cell or null
840 *
843 *
841 **/
844 **/
842 Notebook.prototype.insert_cell_below = function (type, index) {
845 Notebook.prototype.insert_cell_below = function (type, index) {
843 index = this.index_or_selected(index);
846 index = this.index_or_selected(index);
844 return this.insert_cell_at_index(type, index+1);
847 return this.insert_cell_at_index(type, index+1);
845 };
848 };
846
849
847
850
848 /**
851 /**
849 * Insert cell at end of notebook
852 * Insert cell at end of notebook
850 *
853 *
851 * @method insert_cell_at_bottom
854 * @method insert_cell_at_bottom
852 * @param {String} type cell type
855 * @param {String} type cell type
853 *
856 *
854 * @return the added cell; or null
857 * @return the added cell; or null
855 **/
858 **/
856 Notebook.prototype.insert_cell_at_bottom = function (type){
859 Notebook.prototype.insert_cell_at_bottom = function (type){
857 var len = this.ncells();
860 var len = this.ncells();
858 return this.insert_cell_below(type,len-1);
861 return this.insert_cell_below(type,len-1);
859 };
862 };
860
863
861 /**
864 /**
862 * Turn a cell into a code cell.
865 * Turn a cell into a code cell.
863 *
866 *
864 * @method to_code
867 * @method to_code
865 * @param {Number} [index] A cell's index
868 * @param {Number} [index] A cell's index
866 */
869 */
867 Notebook.prototype.to_code = function (index) {
870 Notebook.prototype.to_code = function (index) {
868 var i = this.index_or_selected(index);
871 var i = this.index_or_selected(index);
869 if (this.is_valid_cell_index(i)) {
872 if (this.is_valid_cell_index(i)) {
870 var source_element = this.get_cell_element(i);
873 var source_element = this.get_cell_element(i);
871 var source_cell = source_element.data("cell");
874 var source_cell = source_element.data("cell");
872 if (!(source_cell instanceof IPython.CodeCell)) {
875 if (!(source_cell instanceof IPython.CodeCell)) {
873 var target_cell = this.insert_cell_below('code',i);
876 var target_cell = this.insert_cell_below('code',i);
874 var text = source_cell.get_text();
877 var text = source_cell.get_text();
875 if (text === source_cell.placeholder) {
878 if (text === source_cell.placeholder) {
876 text = '';
879 text = '';
877 }
880 }
878 target_cell.set_text(text);
881 target_cell.set_text(text);
879 // make this value the starting point, so that we can only undo
882 // make this value the starting point, so that we can only undo
880 // to this state, instead of a blank cell
883 // to this state, instead of a blank cell
881 target_cell.code_mirror.clearHistory();
884 target_cell.code_mirror.clearHistory();
882 source_element.remove();
885 source_element.remove();
883 this.select(i);
886 this.select(i);
884 this.set_dirty(true);
887 this.set_dirty(true);
885 }
888 }
886 }
889 }
887 };
890 };
888
891
889 /**
892 /**
890 * Turn a cell into a Markdown cell.
893 * Turn a cell into a Markdown cell.
891 *
894 *
892 * @method to_markdown
895 * @method to_markdown
893 * @param {Number} [index] A cell's index
896 * @param {Number} [index] A cell's index
894 */
897 */
895 Notebook.prototype.to_markdown = function (index) {
898 Notebook.prototype.to_markdown = function (index) {
896 var i = this.index_or_selected(index);
899 var i = this.index_or_selected(index);
897 if (this.is_valid_cell_index(i)) {
900 if (this.is_valid_cell_index(i)) {
898 var source_element = this.get_cell_element(i);
901 var source_element = this.get_cell_element(i);
899 var source_cell = source_element.data("cell");
902 var source_cell = source_element.data("cell");
900 if (!(source_cell instanceof IPython.MarkdownCell)) {
903 if (!(source_cell instanceof IPython.MarkdownCell)) {
901 var target_cell = this.insert_cell_below('markdown',i);
904 var target_cell = this.insert_cell_below('markdown',i);
902 var text = source_cell.get_text();
905 var text = source_cell.get_text();
903 if (text === source_cell.placeholder) {
906 if (text === source_cell.placeholder) {
904 text = '';
907 text = '';
905 }
908 }
906 // We must show the editor before setting its contents
909 // We must show the editor before setting its contents
907 target_cell.unrender();
910 target_cell.unrender();
908 target_cell.set_text(text);
911 target_cell.set_text(text);
909 // make this value the starting point, so that we can only undo
912 // make this value the starting point, so that we can only undo
910 // to this state, instead of a blank cell
913 // to this state, instead of a blank cell
911 target_cell.code_mirror.clearHistory();
914 target_cell.code_mirror.clearHistory();
912 source_element.remove();
915 source_element.remove();
913 this.select(i);
916 this.select(i);
914 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
917 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
915 target_cell.render();
918 target_cell.render();
916 }
919 }
917 this.set_dirty(true);
920 this.set_dirty(true);
918 }
921 }
919 }
922 }
920 };
923 };
921
924
922 /**
925 /**
923 * Turn a cell into a raw text cell.
926 * Turn a cell into a raw text cell.
924 *
927 *
925 * @method to_raw
928 * @method to_raw
926 * @param {Number} [index] A cell's index
929 * @param {Number} [index] A cell's index
927 */
930 */
928 Notebook.prototype.to_raw = function (index) {
931 Notebook.prototype.to_raw = function (index) {
929 var i = this.index_or_selected(index);
932 var i = this.index_or_selected(index);
930 if (this.is_valid_cell_index(i)) {
933 if (this.is_valid_cell_index(i)) {
931 var source_element = this.get_cell_element(i);
934 var source_element = this.get_cell_element(i);
932 var source_cell = source_element.data("cell");
935 var source_cell = source_element.data("cell");
933 var target_cell = null;
936 var target_cell = null;
934 if (!(source_cell instanceof IPython.RawCell)) {
937 if (!(source_cell instanceof IPython.RawCell)) {
935 target_cell = this.insert_cell_below('raw',i);
938 target_cell = this.insert_cell_below('raw',i);
936 var text = source_cell.get_text();
939 var text = source_cell.get_text();
937 if (text === source_cell.placeholder) {
940 if (text === source_cell.placeholder) {
938 text = '';
941 text = '';
939 }
942 }
940 // We must show the editor before setting its contents
943 // We must show the editor before setting its contents
941 target_cell.unrender();
944 target_cell.unrender();
942 target_cell.set_text(text);
945 target_cell.set_text(text);
943 // make this value the starting point, so that we can only undo
946 // make this value the starting point, so that we can only undo
944 // to this state, instead of a blank cell
947 // to this state, instead of a blank cell
945 target_cell.code_mirror.clearHistory();
948 target_cell.code_mirror.clearHistory();
946 source_element.remove();
949 source_element.remove();
947 this.select(i);
950 this.select(i);
948 this.set_dirty(true);
951 this.set_dirty(true);
949 }
952 }
950 }
953 }
951 };
954 };
952
955
953 /**
956 /**
954 * Turn a cell into a heading cell.
957 * Turn a cell into a heading cell.
955 *
958 *
956 * @method to_heading
959 * @method to_heading
957 * @param {Number} [index] A cell's index
960 * @param {Number} [index] A cell's index
958 * @param {Number} [level] A heading level (e.g., 1 becomes &lt;h1&gt;)
961 * @param {Number} [level] A heading level (e.g., 1 becomes &lt;h1&gt;)
959 */
962 */
960 Notebook.prototype.to_heading = function (index, level) {
963 Notebook.prototype.to_heading = function (index, level) {
961 level = level || 1;
964 level = level || 1;
962 var i = this.index_or_selected(index);
965 var i = this.index_or_selected(index);
963 if (this.is_valid_cell_index(i)) {
966 if (this.is_valid_cell_index(i)) {
964 var source_element = this.get_cell_element(i);
967 var source_element = this.get_cell_element(i);
965 var source_cell = source_element.data("cell");
968 var source_cell = source_element.data("cell");
966 var target_cell = null;
969 var target_cell = null;
967 if (source_cell instanceof IPython.HeadingCell) {
970 if (source_cell instanceof IPython.HeadingCell) {
968 source_cell.set_level(level);
971 source_cell.set_level(level);
969 } else {
972 } else {
970 target_cell = this.insert_cell_below('heading',i);
973 target_cell = this.insert_cell_below('heading',i);
971 var text = source_cell.get_text();
974 var text = source_cell.get_text();
972 if (text === source_cell.placeholder) {
975 if (text === source_cell.placeholder) {
973 text = '';
976 text = '';
974 }
977 }
975 // We must show the editor before setting its contents
978 // We must show the editor before setting its contents
976 target_cell.set_level(level);
979 target_cell.set_level(level);
977 target_cell.unrender();
980 target_cell.unrender();
978 target_cell.set_text(text);
981 target_cell.set_text(text);
979 // make this value the starting point, so that we can only undo
982 // make this value the starting point, so that we can only undo
980 // to this state, instead of a blank cell
983 // to this state, instead of a blank cell
981 target_cell.code_mirror.clearHistory();
984 target_cell.code_mirror.clearHistory();
982 source_element.remove();
985 source_element.remove();
983 this.select(i);
986 this.select(i);
984 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
987 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
985 target_cell.render();
988 target_cell.render();
986 }
989 }
987 }
990 }
988 this.set_dirty(true);
991 this.set_dirty(true);
989 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
992 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
990 {'cell_type':'heading',level:level}
993 {'cell_type':'heading',level:level}
991 );
994 );
992 }
995 }
993 };
996 };
994
997
995
998
996 // Cut/Copy/Paste
999 // Cut/Copy/Paste
997
1000
998 /**
1001 /**
999 * Enable UI elements for pasting cells.
1002 * Enable UI elements for pasting cells.
1000 *
1003 *
1001 * @method enable_paste
1004 * @method enable_paste
1002 */
1005 */
1003 Notebook.prototype.enable_paste = function () {
1006 Notebook.prototype.enable_paste = function () {
1004 var that = this;
1007 var that = this;
1005 if (!this.paste_enabled) {
1008 if (!this.paste_enabled) {
1006 $('#paste_cell_replace').removeClass('disabled')
1009 $('#paste_cell_replace').removeClass('disabled')
1007 .on('click', function () {that.paste_cell_replace();});
1010 .on('click', function () {that.paste_cell_replace();});
1008 $('#paste_cell_above').removeClass('disabled')
1011 $('#paste_cell_above').removeClass('disabled')
1009 .on('click', function () {that.paste_cell_above();});
1012 .on('click', function () {that.paste_cell_above();});
1010 $('#paste_cell_below').removeClass('disabled')
1013 $('#paste_cell_below').removeClass('disabled')
1011 .on('click', function () {that.paste_cell_below();});
1014 .on('click', function () {that.paste_cell_below();});
1012 this.paste_enabled = true;
1015 this.paste_enabled = true;
1013 }
1016 }
1014 };
1017 };
1015
1018
1016 /**
1019 /**
1017 * Disable UI elements for pasting cells.
1020 * Disable UI elements for pasting cells.
1018 *
1021 *
1019 * @method disable_paste
1022 * @method disable_paste
1020 */
1023 */
1021 Notebook.prototype.disable_paste = function () {
1024 Notebook.prototype.disable_paste = function () {
1022 if (this.paste_enabled) {
1025 if (this.paste_enabled) {
1023 $('#paste_cell_replace').addClass('disabled').off('click');
1026 $('#paste_cell_replace').addClass('disabled').off('click');
1024 $('#paste_cell_above').addClass('disabled').off('click');
1027 $('#paste_cell_above').addClass('disabled').off('click');
1025 $('#paste_cell_below').addClass('disabled').off('click');
1028 $('#paste_cell_below').addClass('disabled').off('click');
1026 this.paste_enabled = false;
1029 this.paste_enabled = false;
1027 }
1030 }
1028 };
1031 };
1029
1032
1030 /**
1033 /**
1031 * Cut a cell.
1034 * Cut a cell.
1032 *
1035 *
1033 * @method cut_cell
1036 * @method cut_cell
1034 */
1037 */
1035 Notebook.prototype.cut_cell = function () {
1038 Notebook.prototype.cut_cell = function () {
1036 this.copy_cell();
1039 this.copy_cell();
1037 this.delete_cell();
1040 this.delete_cell();
1038 };
1041 };
1039
1042
1040 /**
1043 /**
1041 * Copy a cell.
1044 * Copy a cell.
1042 *
1045 *
1043 * @method copy_cell
1046 * @method copy_cell
1044 */
1047 */
1045 Notebook.prototype.copy_cell = function () {
1048 Notebook.prototype.copy_cell = function () {
1046 var cell = this.get_selected_cell();
1049 var cell = this.get_selected_cell();
1047 this.clipboard = cell.toJSON();
1050 this.clipboard = cell.toJSON();
1048 this.enable_paste();
1051 this.enable_paste();
1049 };
1052 };
1050
1053
1051 /**
1054 /**
1052 * Replace the selected cell with a cell in the clipboard.
1055 * Replace the selected cell with a cell in the clipboard.
1053 *
1056 *
1054 * @method paste_cell_replace
1057 * @method paste_cell_replace
1055 */
1058 */
1056 Notebook.prototype.paste_cell_replace = function () {
1059 Notebook.prototype.paste_cell_replace = function () {
1057 if (this.clipboard !== null && this.paste_enabled) {
1060 if (this.clipboard !== null && this.paste_enabled) {
1058 var cell_data = this.clipboard;
1061 var cell_data = this.clipboard;
1059 var new_cell = this.insert_cell_above(cell_data.cell_type);
1062 var new_cell = this.insert_cell_above(cell_data.cell_type);
1060 new_cell.fromJSON(cell_data);
1063 new_cell.fromJSON(cell_data);
1061 var old_cell = this.get_next_cell(new_cell);
1064 var old_cell = this.get_next_cell(new_cell);
1062 this.delete_cell(this.find_cell_index(old_cell));
1065 this.delete_cell(this.find_cell_index(old_cell));
1063 this.select(this.find_cell_index(new_cell));
1066 this.select(this.find_cell_index(new_cell));
1064 }
1067 }
1065 };
1068 };
1066
1069
1067 /**
1070 /**
1068 * Paste a cell from the clipboard above the selected cell.
1071 * Paste a cell from the clipboard above the selected cell.
1069 *
1072 *
1070 * @method paste_cell_above
1073 * @method paste_cell_above
1071 */
1074 */
1072 Notebook.prototype.paste_cell_above = function () {
1075 Notebook.prototype.paste_cell_above = function () {
1073 if (this.clipboard !== null && this.paste_enabled) {
1076 if (this.clipboard !== null && this.paste_enabled) {
1074 var cell_data = this.clipboard;
1077 var cell_data = this.clipboard;
1075 var new_cell = this.insert_cell_above(cell_data.cell_type);
1078 var new_cell = this.insert_cell_above(cell_data.cell_type);
1076 new_cell.fromJSON(cell_data);
1079 new_cell.fromJSON(cell_data);
1077 new_cell.focus_cell();
1080 new_cell.focus_cell();
1078 }
1081 }
1079 };
1082 };
1080
1083
1081 /**
1084 /**
1082 * Paste a cell from the clipboard below the selected cell.
1085 * Paste a cell from the clipboard below the selected cell.
1083 *
1086 *
1084 * @method paste_cell_below
1087 * @method paste_cell_below
1085 */
1088 */
1086 Notebook.prototype.paste_cell_below = function () {
1089 Notebook.prototype.paste_cell_below = function () {
1087 if (this.clipboard !== null && this.paste_enabled) {
1090 if (this.clipboard !== null && this.paste_enabled) {
1088 var cell_data = this.clipboard;
1091 var cell_data = this.clipboard;
1089 var new_cell = this.insert_cell_below(cell_data.cell_type);
1092 var new_cell = this.insert_cell_below(cell_data.cell_type);
1090 new_cell.fromJSON(cell_data);
1093 new_cell.fromJSON(cell_data);
1091 new_cell.focus_cell();
1094 new_cell.focus_cell();
1092 }
1095 }
1093 };
1096 };
1094
1097
1095 // Split/merge
1098 // Split/merge
1096
1099
1097 /**
1100 /**
1098 * Split the selected cell into two, at the cursor.
1101 * Split the selected cell into two, at the cursor.
1099 *
1102 *
1100 * @method split_cell
1103 * @method split_cell
1101 */
1104 */
1102 Notebook.prototype.split_cell = function () {
1105 Notebook.prototype.split_cell = function () {
1103 var mdc = IPython.MarkdownCell;
1106 var mdc = IPython.MarkdownCell;
1104 var rc = IPython.RawCell;
1107 var rc = IPython.RawCell;
1105 var cell = this.get_selected_cell();
1108 var cell = this.get_selected_cell();
1106 if (cell.is_splittable()) {
1109 if (cell.is_splittable()) {
1107 var texta = cell.get_pre_cursor();
1110 var texta = cell.get_pre_cursor();
1108 var textb = cell.get_post_cursor();
1111 var textb = cell.get_post_cursor();
1109 if (cell instanceof IPython.CodeCell) {
1112 if (cell instanceof IPython.CodeCell) {
1110 // In this case the operations keep the notebook in its existing mode
1113 // In this case the operations keep the notebook in its existing mode
1111 // so we don't need to do any post-op mode changes.
1114 // so we don't need to do any post-op mode changes.
1112 cell.set_text(textb);
1115 cell.set_text(textb);
1113 var new_cell = this.insert_cell_above('code');
1116 var new_cell = this.insert_cell_above('code');
1114 new_cell.set_text(texta);
1117 new_cell.set_text(texta);
1115 } else if ((cell instanceof mdc && !cell.rendered) || (cell instanceof rc)) {
1118 } else if ((cell instanceof mdc && !cell.rendered) || (cell instanceof rc)) {
1116 // We know cell is !rendered so we can use set_text.
1119 // We know cell is !rendered so we can use set_text.
1117 cell.set_text(textb);
1120 cell.set_text(textb);
1118 var new_cell = this.insert_cell_above(cell.cell_type);
1121 var new_cell = this.insert_cell_above(cell.cell_type);
1119 // Unrender the new cell so we can call set_text.
1122 // Unrender the new cell so we can call set_text.
1120 new_cell.unrender();
1123 new_cell.unrender();
1121 new_cell.set_text(texta);
1124 new_cell.set_text(texta);
1122 }
1125 }
1123 }
1126 }
1124 };
1127 };
1125
1128
1126 /**
1129 /**
1127 * Combine the selected cell into the cell above it.
1130 * Combine the selected cell into the cell above it.
1128 *
1131 *
1129 * @method merge_cell_above
1132 * @method merge_cell_above
1130 */
1133 */
1131 Notebook.prototype.merge_cell_above = function () {
1134 Notebook.prototype.merge_cell_above = function () {
1132 var mdc = IPython.MarkdownCell;
1135 var mdc = IPython.MarkdownCell;
1133 var rc = IPython.RawCell;
1136 var rc = IPython.RawCell;
1134 var index = this.get_selected_index();
1137 var index = this.get_selected_index();
1135 var cell = this.get_cell(index);
1138 var cell = this.get_cell(index);
1136 var render = cell.rendered;
1139 var render = cell.rendered;
1137 if (!cell.is_mergeable()) {
1140 if (!cell.is_mergeable()) {
1138 return;
1141 return;
1139 }
1142 }
1140 if (index > 0) {
1143 if (index > 0) {
1141 var upper_cell = this.get_cell(index-1);
1144 var upper_cell = this.get_cell(index-1);
1142 if (!upper_cell.is_mergeable()) {
1145 if (!upper_cell.is_mergeable()) {
1143 return;
1146 return;
1144 }
1147 }
1145 var upper_text = upper_cell.get_text();
1148 var upper_text = upper_cell.get_text();
1146 var text = cell.get_text();
1149 var text = cell.get_text();
1147 if (cell instanceof IPython.CodeCell) {
1150 if (cell instanceof IPython.CodeCell) {
1148 cell.set_text(upper_text+'\n'+text);
1151 cell.set_text(upper_text+'\n'+text);
1149 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1152 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1150 cell.unrender(); // Must unrender before we set_text.
1153 cell.unrender(); // Must unrender before we set_text.
1151 cell.set_text(upper_text+'\n\n'+text);
1154 cell.set_text(upper_text+'\n\n'+text);
1152 if (render) {
1155 if (render) {
1153 // The rendered state of the final cell should match
1156 // The rendered state of the final cell should match
1154 // that of the original selected cell;
1157 // that of the original selected cell;
1155 cell.render();
1158 cell.render();
1156 }
1159 }
1157 }
1160 }
1158 this.delete_cell(index-1);
1161 this.delete_cell(index-1);
1159 this.select(this.find_cell_index(cell));
1162 this.select(this.find_cell_index(cell));
1160 }
1163 }
1161 };
1164 };
1162
1165
1163 /**
1166 /**
1164 * Combine the selected cell into the cell below it.
1167 * Combine the selected cell into the cell below it.
1165 *
1168 *
1166 * @method merge_cell_below
1169 * @method merge_cell_below
1167 */
1170 */
1168 Notebook.prototype.merge_cell_below = function () {
1171 Notebook.prototype.merge_cell_below = function () {
1169 var mdc = IPython.MarkdownCell;
1172 var mdc = IPython.MarkdownCell;
1170 var rc = IPython.RawCell;
1173 var rc = IPython.RawCell;
1171 var index = this.get_selected_index();
1174 var index = this.get_selected_index();
1172 var cell = this.get_cell(index);
1175 var cell = this.get_cell(index);
1173 var render = cell.rendered;
1176 var render = cell.rendered;
1174 if (!cell.is_mergeable()) {
1177 if (!cell.is_mergeable()) {
1175 return;
1178 return;
1176 }
1179 }
1177 if (index < this.ncells()-1) {
1180 if (index < this.ncells()-1) {
1178 var lower_cell = this.get_cell(index+1);
1181 var lower_cell = this.get_cell(index+1);
1179 if (!lower_cell.is_mergeable()) {
1182 if (!lower_cell.is_mergeable()) {
1180 return;
1183 return;
1181 }
1184 }
1182 var lower_text = lower_cell.get_text();
1185 var lower_text = lower_cell.get_text();
1183 var text = cell.get_text();
1186 var text = cell.get_text();
1184 if (cell instanceof IPython.CodeCell) {
1187 if (cell instanceof IPython.CodeCell) {
1185 cell.set_text(text+'\n'+lower_text);
1188 cell.set_text(text+'\n'+lower_text);
1186 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1189 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1187 cell.unrender(); // Must unrender before we set_text.
1190 cell.unrender(); // Must unrender before we set_text.
1188 cell.set_text(text+'\n\n'+lower_text);
1191 cell.set_text(text+'\n\n'+lower_text);
1189 if (render) {
1192 if (render) {
1190 // The rendered state of the final cell should match
1193 // The rendered state of the final cell should match
1191 // that of the original selected cell;
1194 // that of the original selected cell;
1192 cell.render();
1195 cell.render();
1193 }
1196 }
1194 }
1197 }
1195 this.delete_cell(index+1);
1198 this.delete_cell(index+1);
1196 this.select(this.find_cell_index(cell));
1199 this.select(this.find_cell_index(cell));
1197 }
1200 }
1198 };
1201 };
1199
1202
1200
1203
1201 // Cell collapsing and output clearing
1204 // Cell collapsing and output clearing
1202
1205
1203 /**
1206 /**
1204 * Hide a cell's output.
1207 * Hide a cell's output.
1205 *
1208 *
1206 * @method collapse_output
1209 * @method collapse_output
1207 * @param {Number} index A cell's numeric index
1210 * @param {Number} index A cell's numeric index
1208 */
1211 */
1209 Notebook.prototype.collapse_output = function (index) {
1212 Notebook.prototype.collapse_output = function (index) {
1210 var i = this.index_or_selected(index);
1213 var i = this.index_or_selected(index);
1211 var cell = this.get_cell(i);
1214 var cell = this.get_cell(i);
1212 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1215 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1213 cell.collapse_output();
1216 cell.collapse_output();
1214 this.set_dirty(true);
1217 this.set_dirty(true);
1215 }
1218 }
1216 };
1219 };
1217
1220
1218 /**
1221 /**
1219 * Hide each code cell's output area.
1222 * Hide each code cell's output area.
1220 *
1223 *
1221 * @method collapse_all_output
1224 * @method collapse_all_output
1222 */
1225 */
1223 Notebook.prototype.collapse_all_output = function () {
1226 Notebook.prototype.collapse_all_output = function () {
1224 $.map(this.get_cells(), function (cell, i) {
1227 $.map(this.get_cells(), function (cell, i) {
1225 if (cell instanceof IPython.CodeCell) {
1228 if (cell instanceof IPython.CodeCell) {
1226 cell.collapse_output();
1229 cell.collapse_output();
1227 }
1230 }
1228 });
1231 });
1229 // this should not be set if the `collapse` key is removed from nbformat
1232 // this should not be set if the `collapse` key is removed from nbformat
1230 this.set_dirty(true);
1233 this.set_dirty(true);
1231 };
1234 };
1232
1235
1233 /**
1236 /**
1234 * Show a cell's output.
1237 * Show a cell's output.
1235 *
1238 *
1236 * @method expand_output
1239 * @method expand_output
1237 * @param {Number} index A cell's numeric index
1240 * @param {Number} index A cell's numeric index
1238 */
1241 */
1239 Notebook.prototype.expand_output = function (index) {
1242 Notebook.prototype.expand_output = function (index) {
1240 var i = this.index_or_selected(index);
1243 var i = this.index_or_selected(index);
1241 var cell = this.get_cell(i);
1244 var cell = this.get_cell(i);
1242 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1245 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1243 cell.expand_output();
1246 cell.expand_output();
1244 this.set_dirty(true);
1247 this.set_dirty(true);
1245 }
1248 }
1246 };
1249 };
1247
1250
1248 /**
1251 /**
1249 * Expand each code cell's output area, and remove scrollbars.
1252 * Expand each code cell's output area, and remove scrollbars.
1250 *
1253 *
1251 * @method expand_all_output
1254 * @method expand_all_output
1252 */
1255 */
1253 Notebook.prototype.expand_all_output = function () {
1256 Notebook.prototype.expand_all_output = function () {
1254 $.map(this.get_cells(), function (cell, i) {
1257 $.map(this.get_cells(), function (cell, i) {
1255 if (cell instanceof IPython.CodeCell) {
1258 if (cell instanceof IPython.CodeCell) {
1256 cell.expand_output();
1259 cell.expand_output();
1257 }
1260 }
1258 });
1261 });
1259 // this should not be set if the `collapse` key is removed from nbformat
1262 // this should not be set if the `collapse` key is removed from nbformat
1260 this.set_dirty(true);
1263 this.set_dirty(true);
1261 };
1264 };
1262
1265
1263 /**
1266 /**
1264 * Clear the selected CodeCell's output area.
1267 * Clear the selected CodeCell's output area.
1265 *
1268 *
1266 * @method clear_output
1269 * @method clear_output
1267 * @param {Number} index A cell's numeric index
1270 * @param {Number} index A cell's numeric index
1268 */
1271 */
1269 Notebook.prototype.clear_output = function (index) {
1272 Notebook.prototype.clear_output = function (index) {
1270 var i = this.index_or_selected(index);
1273 var i = this.index_or_selected(index);
1271 var cell = this.get_cell(i);
1274 var cell = this.get_cell(i);
1272 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1275 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1273 cell.clear_output();
1276 cell.clear_output();
1274 this.set_dirty(true);
1277 this.set_dirty(true);
1275 }
1278 }
1276 };
1279 };
1277
1280
1278 /**
1281 /**
1279 * Clear each code cell's output area.
1282 * Clear each code cell's output area.
1280 *
1283 *
1281 * @method clear_all_output
1284 * @method clear_all_output
1282 */
1285 */
1283 Notebook.prototype.clear_all_output = function () {
1286 Notebook.prototype.clear_all_output = function () {
1284 $.map(this.get_cells(), function (cell, i) {
1287 $.map(this.get_cells(), function (cell, i) {
1285 if (cell instanceof IPython.CodeCell) {
1288 if (cell instanceof IPython.CodeCell) {
1286 cell.clear_output();
1289 cell.clear_output();
1287 }
1290 }
1288 });
1291 });
1289 this.set_dirty(true);
1292 this.set_dirty(true);
1290 };
1293 };
1291
1294
1292 /**
1295 /**
1293 * Scroll the selected CodeCell's output area.
1296 * Scroll the selected CodeCell's output area.
1294 *
1297 *
1295 * @method scroll_output
1298 * @method scroll_output
1296 * @param {Number} index A cell's numeric index
1299 * @param {Number} index A cell's numeric index
1297 */
1300 */
1298 Notebook.prototype.scroll_output = function (index) {
1301 Notebook.prototype.scroll_output = function (index) {
1299 var i = this.index_or_selected(index);
1302 var i = this.index_or_selected(index);
1300 var cell = this.get_cell(i);
1303 var cell = this.get_cell(i);
1301 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1304 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1302 cell.scroll_output();
1305 cell.scroll_output();
1303 this.set_dirty(true);
1306 this.set_dirty(true);
1304 }
1307 }
1305 };
1308 };
1306
1309
1307 /**
1310 /**
1308 * Expand each code cell's output area, and add a scrollbar for long output.
1311 * Expand each code cell's output area, and add a scrollbar for long output.
1309 *
1312 *
1310 * @method scroll_all_output
1313 * @method scroll_all_output
1311 */
1314 */
1312 Notebook.prototype.scroll_all_output = function () {
1315 Notebook.prototype.scroll_all_output = function () {
1313 $.map(this.get_cells(), function (cell, i) {
1316 $.map(this.get_cells(), function (cell, i) {
1314 if (cell instanceof IPython.CodeCell) {
1317 if (cell instanceof IPython.CodeCell) {
1315 cell.scroll_output();
1318 cell.scroll_output();
1316 }
1319 }
1317 });
1320 });
1318 // this should not be set if the `collapse` key is removed from nbformat
1321 // this should not be set if the `collapse` key is removed from nbformat
1319 this.set_dirty(true);
1322 this.set_dirty(true);
1320 };
1323 };
1321
1324
1322 /** Toggle whether a cell's output is collapsed or expanded.
1325 /** Toggle whether a cell's output is collapsed or expanded.
1323 *
1326 *
1324 * @method toggle_output
1327 * @method toggle_output
1325 * @param {Number} index A cell's numeric index
1328 * @param {Number} index A cell's numeric index
1326 */
1329 */
1327 Notebook.prototype.toggle_output = function (index) {
1330 Notebook.prototype.toggle_output = function (index) {
1328 var i = this.index_or_selected(index);
1331 var i = this.index_or_selected(index);
1329 var cell = this.get_cell(i);
1332 var cell = this.get_cell(i);
1330 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1333 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1331 cell.toggle_output();
1334 cell.toggle_output();
1332 this.set_dirty(true);
1335 this.set_dirty(true);
1333 }
1336 }
1334 };
1337 };
1335
1338
1336 /**
1339 /**
1337 * Hide/show the output of all cells.
1340 * Hide/show the output of all cells.
1338 *
1341 *
1339 * @method toggle_all_output
1342 * @method toggle_all_output
1340 */
1343 */
1341 Notebook.prototype.toggle_all_output = function () {
1344 Notebook.prototype.toggle_all_output = function () {
1342 $.map(this.get_cells(), function (cell, i) {
1345 $.map(this.get_cells(), function (cell, i) {
1343 if (cell instanceof IPython.CodeCell) {
1346 if (cell instanceof IPython.CodeCell) {
1344 cell.toggle_output();
1347 cell.toggle_output();
1345 }
1348 }
1346 });
1349 });
1347 // this should not be set if the `collapse` key is removed from nbformat
1350 // this should not be set if the `collapse` key is removed from nbformat
1348 this.set_dirty(true);
1351 this.set_dirty(true);
1349 };
1352 };
1350
1353
1351 /**
1354 /**
1352 * Toggle a scrollbar for long cell outputs.
1355 * Toggle a scrollbar for long cell outputs.
1353 *
1356 *
1354 * @method toggle_output_scroll
1357 * @method toggle_output_scroll
1355 * @param {Number} index A cell's numeric index
1358 * @param {Number} index A cell's numeric index
1356 */
1359 */
1357 Notebook.prototype.toggle_output_scroll = function (index) {
1360 Notebook.prototype.toggle_output_scroll = function (index) {
1358 var i = this.index_or_selected(index);
1361 var i = this.index_or_selected(index);
1359 var cell = this.get_cell(i);
1362 var cell = this.get_cell(i);
1360 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1363 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1361 cell.toggle_output_scroll();
1364 cell.toggle_output_scroll();
1362 this.set_dirty(true);
1365 this.set_dirty(true);
1363 }
1366 }
1364 };
1367 };
1365
1368
1366 /**
1369 /**
1367 * Toggle the scrolling of long output on all cells.
1370 * Toggle the scrolling of long output on all cells.
1368 *
1371 *
1369 * @method toggle_all_output_scrolling
1372 * @method toggle_all_output_scrolling
1370 */
1373 */
1371 Notebook.prototype.toggle_all_output_scroll = function () {
1374 Notebook.prototype.toggle_all_output_scroll = function () {
1372 $.map(this.get_cells(), function (cell, i) {
1375 $.map(this.get_cells(), function (cell, i) {
1373 if (cell instanceof IPython.CodeCell) {
1376 if (cell instanceof IPython.CodeCell) {
1374 cell.toggle_output_scroll();
1377 cell.toggle_output_scroll();
1375 }
1378 }
1376 });
1379 });
1377 // this should not be set if the `collapse` key is removed from nbformat
1380 // this should not be set if the `collapse` key is removed from nbformat
1378 this.set_dirty(true);
1381 this.set_dirty(true);
1379 };
1382 };
1380
1383
1381 // Other cell functions: line numbers, ...
1384 // Other cell functions: line numbers, ...
1382
1385
1383 /**
1386 /**
1384 * Toggle line numbers in the selected cell's input area.
1387 * Toggle line numbers in the selected cell's input area.
1385 *
1388 *
1386 * @method cell_toggle_line_numbers
1389 * @method cell_toggle_line_numbers
1387 */
1390 */
1388 Notebook.prototype.cell_toggle_line_numbers = function() {
1391 Notebook.prototype.cell_toggle_line_numbers = function() {
1389 this.get_selected_cell().toggle_line_numbers();
1392 this.get_selected_cell().toggle_line_numbers();
1390 };
1393 };
1391
1394
1392 // Session related things
1395 // Session related things
1393
1396
1394 /**
1397 /**
1395 * Start a new session and set it on each code cell.
1398 * Start a new session and set it on each code cell.
1396 *
1399 *
1397 * @method start_session
1400 * @method start_session
1398 */
1401 */
1399 Notebook.prototype.start_session = function () {
1402 Notebook.prototype.start_session = function () {
1400 this.session = new IPython.Session(this, this.options);
1403 this.session = new IPython.Session(this, this.options);
1401 this.session.start($.proxy(this._session_started, this));
1404 this.session.start($.proxy(this._session_started, this));
1402 };
1405 };
1403
1406
1404
1407
1405 /**
1408 /**
1406 * Once a session is started, link the code cells to the kernel and pass the
1409 * Once a session is started, link the code cells to the kernel and pass the
1407 * comm manager to the widget manager
1410 * comm manager to the widget manager
1408 *
1411 *
1409 */
1412 */
1410 Notebook.prototype._session_started = function(){
1413 Notebook.prototype._session_started = function(){
1411 this.kernel = this.session.kernel;
1414 this.kernel = this.session.kernel;
1412 var ncells = this.ncells();
1415 var ncells = this.ncells();
1413 for (var i=0; i<ncells; i++) {
1416 for (var i=0; i<ncells; i++) {
1414 var cell = this.get_cell(i);
1417 var cell = this.get_cell(i);
1415 if (cell instanceof IPython.CodeCell) {
1418 if (cell instanceof IPython.CodeCell) {
1416 cell.set_kernel(this.session.kernel);
1419 cell.set_kernel(this.session.kernel);
1417 }
1420 }
1418 }
1421 }
1419 };
1422 };
1420
1423
1421 /**
1424 /**
1422 * Prompt the user to restart the IPython kernel.
1425 * Prompt the user to restart the IPython kernel.
1423 *
1426 *
1424 * @method restart_kernel
1427 * @method restart_kernel
1425 */
1428 */
1426 Notebook.prototype.restart_kernel = function () {
1429 Notebook.prototype.restart_kernel = function () {
1427 var that = this;
1430 var that = this;
1428 IPython.dialog.modal({
1431 IPython.dialog.modal({
1429 title : "Restart kernel or continue running?",
1432 title : "Restart kernel or continue running?",
1430 body : $("<p/>").text(
1433 body : $("<p/>").text(
1431 'Do you want to restart the current kernel? You will lose all variables defined in it.'
1434 'Do you want to restart the current kernel? You will lose all variables defined in it.'
1432 ),
1435 ),
1433 buttons : {
1436 buttons : {
1434 "Continue running" : {},
1437 "Continue running" : {},
1435 "Restart" : {
1438 "Restart" : {
1436 "class" : "btn-danger",
1439 "class" : "btn-danger",
1437 "click" : function() {
1440 "click" : function() {
1438 that.session.restart_kernel();
1441 that.session.restart_kernel();
1439 }
1442 }
1440 }
1443 }
1441 }
1444 }
1442 });
1445 });
1443 };
1446 };
1444
1447
1445 /**
1448 /**
1446 * Execute or render cell outputs and go into command mode.
1449 * Execute or render cell outputs and go into command mode.
1447 *
1450 *
1448 * @method execute_cell
1451 * @method execute_cell
1449 */
1452 */
1450 Notebook.prototype.execute_cell = function () {
1453 Notebook.prototype.execute_cell = function () {
1451 // mode = shift, ctrl, alt
1454 // mode = shift, ctrl, alt
1452 var cell = this.get_selected_cell();
1455 var cell = this.get_selected_cell();
1453 var cell_index = this.find_cell_index(cell);
1456 var cell_index = this.find_cell_index(cell);
1454
1457
1455 cell.execute();
1458 cell.execute();
1456 this.command_mode();
1459 this.command_mode();
1457 this.set_dirty(true);
1460 this.set_dirty(true);
1458 };
1461 };
1459
1462
1460 /**
1463 /**
1461 * Execute or render cell outputs and insert a new cell below.
1464 * Execute or render cell outputs and insert a new cell below.
1462 *
1465 *
1463 * @method execute_cell_and_insert_below
1466 * @method execute_cell_and_insert_below
1464 */
1467 */
1465 Notebook.prototype.execute_cell_and_insert_below = function () {
1468 Notebook.prototype.execute_cell_and_insert_below = function () {
1466 var cell = this.get_selected_cell();
1469 var cell = this.get_selected_cell();
1467 var cell_index = this.find_cell_index(cell);
1470 var cell_index = this.find_cell_index(cell);
1468
1471
1469 cell.execute();
1472 cell.execute();
1470
1473
1471 // If we are at the end always insert a new cell and return
1474 // If we are at the end always insert a new cell and return
1472 if (cell_index === (this.ncells()-1)) {
1475 if (cell_index === (this.ncells()-1)) {
1473 this.command_mode();
1476 this.command_mode();
1474 this.insert_cell_below('code');
1477 this.insert_cell_below('code');
1475 this.select(cell_index+1);
1478 this.select(cell_index+1);
1476 this.edit_mode();
1479 this.edit_mode();
1477 this.scroll_to_bottom();
1480 this.scroll_to_bottom();
1478 this.set_dirty(true);
1481 this.set_dirty(true);
1479 return;
1482 return;
1480 }
1483 }
1481
1484
1482 this.command_mode();
1485 this.command_mode();
1483 this.insert_cell_below('code');
1486 this.insert_cell_below('code');
1484 this.select(cell_index+1);
1487 this.select(cell_index+1);
1485 this.edit_mode();
1488 this.edit_mode();
1486 this.set_dirty(true);
1489 this.set_dirty(true);
1487 };
1490 };
1488
1491
1489 /**
1492 /**
1490 * Execute or render cell outputs and select the next cell.
1493 * Execute or render cell outputs and select the next cell.
1491 *
1494 *
1492 * @method execute_cell_and_select_below
1495 * @method execute_cell_and_select_below
1493 */
1496 */
1494 Notebook.prototype.execute_cell_and_select_below = function () {
1497 Notebook.prototype.execute_cell_and_select_below = function () {
1495
1498
1496 var cell = this.get_selected_cell();
1499 var cell = this.get_selected_cell();
1497 var cell_index = this.find_cell_index(cell);
1500 var cell_index = this.find_cell_index(cell);
1498
1501
1499 cell.execute();
1502 cell.execute();
1500
1503
1501 // If we are at the end always insert a new cell and return
1504 // If we are at the end always insert a new cell and return
1502 if (cell_index === (this.ncells()-1)) {
1505 if (cell_index === (this.ncells()-1)) {
1503 this.command_mode();
1506 this.command_mode();
1504 this.insert_cell_below('code');
1507 this.insert_cell_below('code');
1505 this.select(cell_index+1);
1508 this.select(cell_index+1);
1506 this.edit_mode();
1509 this.edit_mode();
1507 this.scroll_to_bottom();
1510 this.scroll_to_bottom();
1508 this.set_dirty(true);
1511 this.set_dirty(true);
1509 return;
1512 return;
1510 }
1513 }
1511
1514
1512 this.command_mode();
1515 this.command_mode();
1513 this.select(cell_index+1);
1516 this.select(cell_index+1);
1514 this.focus_cell();
1517 this.focus_cell();
1515 this.set_dirty(true);
1518 this.set_dirty(true);
1516 };
1519 };
1517
1520
1518 /**
1521 /**
1519 * Execute all cells below the selected cell.
1522 * Execute all cells below the selected cell.
1520 *
1523 *
1521 * @method execute_cells_below
1524 * @method execute_cells_below
1522 */
1525 */
1523 Notebook.prototype.execute_cells_below = function () {
1526 Notebook.prototype.execute_cells_below = function () {
1524 this.execute_cell_range(this.get_selected_index(), this.ncells());
1527 this.execute_cell_range(this.get_selected_index(), this.ncells());
1525 this.scroll_to_bottom();
1528 this.scroll_to_bottom();
1526 };
1529 };
1527
1530
1528 /**
1531 /**
1529 * Execute all cells above the selected cell.
1532 * Execute all cells above the selected cell.
1530 *
1533 *
1531 * @method execute_cells_above
1534 * @method execute_cells_above
1532 */
1535 */
1533 Notebook.prototype.execute_cells_above = function () {
1536 Notebook.prototype.execute_cells_above = function () {
1534 this.execute_cell_range(0, this.get_selected_index());
1537 this.execute_cell_range(0, this.get_selected_index());
1535 };
1538 };
1536
1539
1537 /**
1540 /**
1538 * Execute all cells.
1541 * Execute all cells.
1539 *
1542 *
1540 * @method execute_all_cells
1543 * @method execute_all_cells
1541 */
1544 */
1542 Notebook.prototype.execute_all_cells = function () {
1545 Notebook.prototype.execute_all_cells = function () {
1543 this.execute_cell_range(0, this.ncells());
1546 this.execute_cell_range(0, this.ncells());
1544 this.scroll_to_bottom();
1547 this.scroll_to_bottom();
1545 };
1548 };
1546
1549
1547 /**
1550 /**
1548 * Execute a contiguous range of cells.
1551 * Execute a contiguous range of cells.
1549 *
1552 *
1550 * @method execute_cell_range
1553 * @method execute_cell_range
1551 * @param {Number} start Index of the first cell to execute (inclusive)
1554 * @param {Number} start Index of the first cell to execute (inclusive)
1552 * @param {Number} end Index of the last cell to execute (exclusive)
1555 * @param {Number} end Index of the last cell to execute (exclusive)
1553 */
1556 */
1554 Notebook.prototype.execute_cell_range = function (start, end) {
1557 Notebook.prototype.execute_cell_range = function (start, end) {
1555 this.command_mode();
1558 this.command_mode();
1556 for (var i=start; i<end; i++) {
1559 for (var i=start; i<end; i++) {
1557 this.select(i);
1560 this.select(i);
1558 this.execute_cell();
1561 this.execute_cell();
1559 }
1562 }
1560 };
1563 };
1561
1564
1562 // Persistance and loading
1565 // Persistance and loading
1563
1566
1564 /**
1567 /**
1565 * Getter method for this notebook's name.
1568 * Getter method for this notebook's name.
1566 *
1569 *
1567 * @method get_notebook_name
1570 * @method get_notebook_name
1568 * @return {String} This notebook's name (excluding file extension)
1571 * @return {String} This notebook's name (excluding file extension)
1569 */
1572 */
1570 Notebook.prototype.get_notebook_name = function () {
1573 Notebook.prototype.get_notebook_name = function () {
1571 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
1574 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
1572 return nbname;
1575 return nbname;
1573 };
1576 };
1574
1577
1575 /**
1578 /**
1576 * Setter method for this notebook's name.
1579 * Setter method for this notebook's name.
1577 *
1580 *
1578 * @method set_notebook_name
1581 * @method set_notebook_name
1579 * @param {String} name A new name for this notebook
1582 * @param {String} name A new name for this notebook
1580 */
1583 */
1581 Notebook.prototype.set_notebook_name = function (name) {
1584 Notebook.prototype.set_notebook_name = function (name) {
1582 this.notebook_name = name;
1585 this.notebook_name = name;
1583 };
1586 };
1584
1587
1585 /**
1588 /**
1586 * Check that a notebook's name is valid.
1589 * Check that a notebook's name is valid.
1587 *
1590 *
1588 * @method test_notebook_name
1591 * @method test_notebook_name
1589 * @param {String} nbname A name for this notebook
1592 * @param {String} nbname A name for this notebook
1590 * @return {Boolean} True if the name is valid, false if invalid
1593 * @return {Boolean} True if the name is valid, false if invalid
1591 */
1594 */
1592 Notebook.prototype.test_notebook_name = function (nbname) {
1595 Notebook.prototype.test_notebook_name = function (nbname) {
1593 nbname = nbname || '';
1596 nbname = nbname || '';
1594 if (nbname.length>0 && !this.notebook_name_blacklist_re.test(nbname)) {
1597 if (nbname.length>0 && !this.notebook_name_blacklist_re.test(nbname)) {
1595 return true;
1598 return true;
1596 } else {
1599 } else {
1597 return false;
1600 return false;
1598 }
1601 }
1599 };
1602 };
1600
1603
1601 /**
1604 /**
1602 * Load a notebook from JSON (.ipynb).
1605 * Load a notebook from JSON (.ipynb).
1603 *
1606 *
1604 * This currently handles one worksheet: others are deleted.
1607 * This currently handles one worksheet: others are deleted.
1605 *
1608 *
1606 * @method fromJSON
1609 * @method fromJSON
1607 * @param {Object} data JSON representation of a notebook
1610 * @param {Object} data JSON representation of a notebook
1608 */
1611 */
1609 Notebook.prototype.fromJSON = function (data) {
1612 Notebook.prototype.fromJSON = function (data) {
1610 var content = data.content;
1613 var content = data.content;
1611 var ncells = this.ncells();
1614 var ncells = this.ncells();
1612 var i;
1615 var i;
1613 for (i=0; i<ncells; i++) {
1616 for (i=0; i<ncells; i++) {
1614 // Always delete cell 0 as they get renumbered as they are deleted.
1617 // Always delete cell 0 as they get renumbered as they are deleted.
1615 this.delete_cell(0);
1618 this.delete_cell(0);
1616 }
1619 }
1617 // Save the metadata and name.
1620 // Save the metadata and name.
1618 this.metadata = content.metadata;
1621 this.metadata = content.metadata;
1619 this.notebook_name = data.name;
1622 this.notebook_name = data.name;
1620 var trusted = true;
1623 var trusted = true;
1621 // Only handle 1 worksheet for now.
1624 // Only handle 1 worksheet for now.
1622 var worksheet = content.worksheets[0];
1625 var worksheet = content.worksheets[0];
1623 if (worksheet !== undefined) {
1626 if (worksheet !== undefined) {
1624 if (worksheet.metadata) {
1627 if (worksheet.metadata) {
1625 this.worksheet_metadata = worksheet.metadata;
1628 this.worksheet_metadata = worksheet.metadata;
1626 }
1629 }
1627 var new_cells = worksheet.cells;
1630 var new_cells = worksheet.cells;
1628 ncells = new_cells.length;
1631 ncells = new_cells.length;
1629 var cell_data = null;
1632 var cell_data = null;
1630 var new_cell = null;
1633 var new_cell = null;
1631 for (i=0; i<ncells; i++) {
1634 for (i=0; i<ncells; i++) {
1632 cell_data = new_cells[i];
1635 cell_data = new_cells[i];
1633 // VERSIONHACK: plaintext -> raw
1636 // VERSIONHACK: plaintext -> raw
1634 // handle never-released plaintext name for raw cells
1637 // handle never-released plaintext name for raw cells
1635 if (cell_data.cell_type === 'plaintext'){
1638 if (cell_data.cell_type === 'plaintext'){
1636 cell_data.cell_type = 'raw';
1639 cell_data.cell_type = 'raw';
1637 }
1640 }
1638
1641
1639 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1642 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1640 new_cell.fromJSON(cell_data);
1643 new_cell.fromJSON(cell_data);
1641 if (new_cell.cell_type == 'code' && !new_cell.output_area.trusted) {
1644 if (new_cell.cell_type == 'code' && !new_cell.output_area.trusted) {
1642 trusted = false;
1645 trusted = false;
1643 }
1646 }
1644 }
1647 }
1645 }
1648 }
1646 if (trusted != this.trusted) {
1649 if (trusted != this.trusted) {
1647 this.trusted = trusted;
1650 this.trusted = trusted;
1648 $([IPython.events]).trigger("trust_changed.Notebook", trusted);
1651 $([IPython.events]).trigger("trust_changed.Notebook", trusted);
1649 }
1652 }
1650 if (content.worksheets.length > 1) {
1653 if (content.worksheets.length > 1) {
1651 IPython.dialog.modal({
1654 IPython.dialog.modal({
1652 title : "Multiple worksheets",
1655 title : "Multiple worksheets",
1653 body : "This notebook has " + data.worksheets.length + " worksheets, " +
1656 body : "This notebook has " + data.worksheets.length + " worksheets, " +
1654 "but this version of IPython can only handle the first. " +
1657 "but this version of IPython can only handle the first. " +
1655 "If you save this notebook, worksheets after the first will be lost.",
1658 "If you save this notebook, worksheets after the first will be lost.",
1656 buttons : {
1659 buttons : {
1657 OK : {
1660 OK : {
1658 class : "btn-danger"
1661 class : "btn-danger"
1659 }
1662 }
1660 }
1663 }
1661 });
1664 });
1662 }
1665 }
1663 };
1666 };
1664
1667
1665 /**
1668 /**
1666 * Dump this notebook into a JSON-friendly object.
1669 * Dump this notebook into a JSON-friendly object.
1667 *
1670 *
1668 * @method toJSON
1671 * @method toJSON
1669 * @return {Object} A JSON-friendly representation of this notebook.
1672 * @return {Object} A JSON-friendly representation of this notebook.
1670 */
1673 */
1671 Notebook.prototype.toJSON = function () {
1674 Notebook.prototype.toJSON = function () {
1672 var cells = this.get_cells();
1675 var cells = this.get_cells();
1673 var ncells = cells.length;
1676 var ncells = cells.length;
1674 var cell_array = new Array(ncells);
1677 var cell_array = new Array(ncells);
1675 var trusted = true;
1678 var trusted = true;
1676 for (var i=0; i<ncells; i++) {
1679 for (var i=0; i<ncells; i++) {
1677 var cell = cells[i];
1680 var cell = cells[i];
1678 if (cell.cell_type == 'code' && !cell.output_area.trusted) {
1681 if (cell.cell_type == 'code' && !cell.output_area.trusted) {
1679 trusted = false;
1682 trusted = false;
1680 }
1683 }
1681 cell_array[i] = cell.toJSON();
1684 cell_array[i] = cell.toJSON();
1682 }
1685 }
1683 var data = {
1686 var data = {
1684 // Only handle 1 worksheet for now.
1687 // Only handle 1 worksheet for now.
1685 worksheets : [{
1688 worksheets : [{
1686 cells: cell_array,
1689 cells: cell_array,
1687 metadata: this.worksheet_metadata
1690 metadata: this.worksheet_metadata
1688 }],
1691 }],
1689 metadata : this.metadata
1692 metadata : this.metadata
1690 };
1693 };
1691 if (trusted != this.trusted) {
1694 if (trusted != this.trusted) {
1692 this.trusted = trusted;
1695 this.trusted = trusted;
1693 $([IPython.events]).trigger("trust_changed.Notebook", trusted);
1696 $([IPython.events]).trigger("trust_changed.Notebook", trusted);
1694 }
1697 }
1695 return data;
1698 return data;
1696 };
1699 };
1697
1700
1698 /**
1701 /**
1699 * Start an autosave timer, for periodically saving the notebook.
1702 * Start an autosave timer, for periodically saving the notebook.
1700 *
1703 *
1701 * @method set_autosave_interval
1704 * @method set_autosave_interval
1702 * @param {Integer} interval the autosave interval in milliseconds
1705 * @param {Integer} interval the autosave interval in milliseconds
1703 */
1706 */
1704 Notebook.prototype.set_autosave_interval = function (interval) {
1707 Notebook.prototype.set_autosave_interval = function (interval) {
1705 var that = this;
1708 var that = this;
1706 // clear previous interval, so we don't get simultaneous timers
1709 // clear previous interval, so we don't get simultaneous timers
1707 if (this.autosave_timer) {
1710 if (this.autosave_timer) {
1708 clearInterval(this.autosave_timer);
1711 clearInterval(this.autosave_timer);
1709 }
1712 }
1710
1713
1711 this.autosave_interval = this.minimum_autosave_interval = interval;
1714 this.autosave_interval = this.minimum_autosave_interval = interval;
1712 if (interval) {
1715 if (interval) {
1713 this.autosave_timer = setInterval(function() {
1716 this.autosave_timer = setInterval(function() {
1714 if (that.dirty) {
1717 if (that.dirty) {
1715 that.save_notebook();
1718 that.save_notebook();
1716 }
1719 }
1717 }, interval);
1720 }, interval);
1718 $([IPython.events]).trigger("autosave_enabled.Notebook", interval);
1721 $([IPython.events]).trigger("autosave_enabled.Notebook", interval);
1719 } else {
1722 } else {
1720 this.autosave_timer = null;
1723 this.autosave_timer = null;
1721 $([IPython.events]).trigger("autosave_disabled.Notebook");
1724 $([IPython.events]).trigger("autosave_disabled.Notebook");
1722 }
1725 }
1723 };
1726 };
1724
1727
1725 /**
1728 /**
1726 * Save this notebook on the server.
1729 * Save this notebook on the server. This becomes a notebook instance's
1730 * .save_notebook method *after* the entire notebook has been loaded.
1727 *
1731 *
1728 * @method save_notebook
1732 * @method save_notebook
1729 */
1733 */
1730 Notebook.prototype.save_notebook = function (extra_settings) {
1734 Notebook.prototype.save_notebook = function (extra_settings) {
1731 // Create a JSON model to be sent to the server.
1735 // Create a JSON model to be sent to the server.
1732 var model = {};
1736 var model = {};
1733 model.name = this.notebook_name;
1737 model.name = this.notebook_name;
1734 model.path = this.notebook_path;
1738 model.path = this.notebook_path;
1735 model.content = this.toJSON();
1739 model.content = this.toJSON();
1736 model.content.nbformat = this.nbformat;
1740 model.content.nbformat = this.nbformat;
1737 model.content.nbformat_minor = this.nbformat_minor;
1741 model.content.nbformat_minor = this.nbformat_minor;
1738 // time the ajax call for autosave tuning purposes.
1742 // time the ajax call for autosave tuning purposes.
1739 var start = new Date().getTime();
1743 var start = new Date().getTime();
1740 // We do the call with settings so we can set cache to false.
1744 // We do the call with settings so we can set cache to false.
1741 var settings = {
1745 var settings = {
1742 processData : false,
1746 processData : false,
1743 cache : false,
1747 cache : false,
1744 type : "PUT",
1748 type : "PUT",
1745 data : JSON.stringify(model),
1749 data : JSON.stringify(model),
1746 headers : {'Content-Type': 'application/json'},
1750 headers : {'Content-Type': 'application/json'},
1747 success : $.proxy(this.save_notebook_success, this, start),
1751 success : $.proxy(this.save_notebook_success, this, start),
1748 error : $.proxy(this.save_notebook_error, this)
1752 error : $.proxy(this.save_notebook_error, this)
1749 };
1753 };
1750 if (extra_settings) {
1754 if (extra_settings) {
1751 for (var key in extra_settings) {
1755 for (var key in extra_settings) {
1752 settings[key] = extra_settings[key];
1756 settings[key] = extra_settings[key];
1753 }
1757 }
1754 }
1758 }
1755 $([IPython.events]).trigger('notebook_saving.Notebook');
1759 $([IPython.events]).trigger('notebook_saving.Notebook');
1756 var url = utils.url_join_encode(
1760 var url = utils.url_join_encode(
1757 this.base_url,
1761 this.base_url,
1758 'api/notebooks',
1762 'api/notebooks',
1759 this.notebook_path,
1763 this.notebook_path,
1760 this.notebook_name
1764 this.notebook_name
1761 );
1765 );
1762 $.ajax(url, settings);
1766 $.ajax(url, settings);
1763 };
1767 };
1764
1768
1765 /**
1769 /**
1766 * Success callback for saving a notebook.
1770 * Success callback for saving a notebook.
1767 *
1771 *
1768 * @method save_notebook_success
1772 * @method save_notebook_success
1769 * @param {Integer} start the time when the save request started
1773 * @param {Integer} start the time when the save request started
1770 * @param {Object} data JSON representation of a notebook
1774 * @param {Object} data JSON representation of a notebook
1771 * @param {String} status Description of response status
1775 * @param {String} status Description of response status
1772 * @param {jqXHR} xhr jQuery Ajax object
1776 * @param {jqXHR} xhr jQuery Ajax object
1773 */
1777 */
1774 Notebook.prototype.save_notebook_success = function (start, data, status, xhr) {
1778 Notebook.prototype.save_notebook_success = function (start, data, status, xhr) {
1775 this.set_dirty(false);
1779 this.set_dirty(false);
1776 $([IPython.events]).trigger('notebook_saved.Notebook');
1780 $([IPython.events]).trigger('notebook_saved.Notebook');
1777 this._update_autosave_interval(start);
1781 this._update_autosave_interval(start);
1778 if (this._checkpoint_after_save) {
1782 if (this._checkpoint_after_save) {
1779 this.create_checkpoint();
1783 this.create_checkpoint();
1780 this._checkpoint_after_save = false;
1784 this._checkpoint_after_save = false;
1781 }
1785 }
1782 };
1786 };
1783
1787
1784 /**
1788 /**
1785 * update the autosave interval based on how long the last save took
1789 * update the autosave interval based on how long the last save took
1786 *
1790 *
1787 * @method _update_autosave_interval
1791 * @method _update_autosave_interval
1788 * @param {Integer} timestamp when the save request started
1792 * @param {Integer} timestamp when the save request started
1789 */
1793 */
1790 Notebook.prototype._update_autosave_interval = function (start) {
1794 Notebook.prototype._update_autosave_interval = function (start) {
1791 var duration = (new Date().getTime() - start);
1795 var duration = (new Date().getTime() - start);
1792 if (this.autosave_interval) {
1796 if (this.autosave_interval) {
1793 // new save interval: higher of 10x save duration or parameter (default 30 seconds)
1797 // new save interval: higher of 10x save duration or parameter (default 30 seconds)
1794 var interval = Math.max(10 * duration, this.minimum_autosave_interval);
1798 var interval = Math.max(10 * duration, this.minimum_autosave_interval);
1795 // round to 10 seconds, otherwise we will be setting a new interval too often
1799 // round to 10 seconds, otherwise we will be setting a new interval too often
1796 interval = 10000 * Math.round(interval / 10000);
1800 interval = 10000 * Math.round(interval / 10000);
1797 // set new interval, if it's changed
1801 // set new interval, if it's changed
1798 if (interval != this.autosave_interval) {
1802 if (interval != this.autosave_interval) {
1799 this.set_autosave_interval(interval);
1803 this.set_autosave_interval(interval);
1800 }
1804 }
1801 }
1805 }
1802 };
1806 };
1803
1807
1804 /**
1808 /**
1805 * Failure callback for saving a notebook.
1809 * Failure callback for saving a notebook.
1806 *
1810 *
1807 * @method save_notebook_error
1811 * @method save_notebook_error
1808 * @param {jqXHR} xhr jQuery Ajax object
1812 * @param {jqXHR} xhr jQuery Ajax object
1809 * @param {String} status Description of response status
1813 * @param {String} status Description of response status
1810 * @param {String} error HTTP error message
1814 * @param {String} error HTTP error message
1811 */
1815 */
1812 Notebook.prototype.save_notebook_error = function (xhr, status, error) {
1816 Notebook.prototype.save_notebook_error = function (xhr, status, error) {
1813 $([IPython.events]).trigger('notebook_save_failed.Notebook', [xhr, status, error]);
1817 $([IPython.events]).trigger('notebook_save_failed.Notebook', [xhr, status, error]);
1814 };
1818 };
1815
1819
1816 /**
1820 /**
1817 * Explicitly trust the output of this notebook.
1821 * Explicitly trust the output of this notebook.
1818 *
1822 *
1819 * @method trust_notebook
1823 * @method trust_notebook
1820 */
1824 */
1821 Notebook.prototype.trust_notebook = function (extra_settings) {
1825 Notebook.prototype.trust_notebook = function (extra_settings) {
1822 var body = $("<div>").append($("<p>")
1826 var body = $("<div>").append($("<p>")
1823 .text("A trusted IPython notebook may execute hidden malicious code ")
1827 .text("A trusted IPython notebook may execute hidden malicious code ")
1824 .append($("<strong>")
1828 .append($("<strong>")
1825 .append(
1829 .append(
1826 $("<em>").text("when you open it")
1830 $("<em>").text("when you open it")
1827 )
1831 )
1828 ).append(".").append(
1832 ).append(".").append(
1829 " Selecting trust will immediately reload this notebook in a trusted state."
1833 " Selecting trust will immediately reload this notebook in a trusted state."
1830 ).append(
1834 ).append(
1831 " For more information, see the "
1835 " For more information, see the "
1832 ).append($("<a>").attr("href", "http://ipython.org/security.html")
1836 ).append($("<a>").attr("href", "http://ipython.org/ipython-doc/2/notebook/security.html")
1833 .text("IPython security documentation")
1837 .text("IPython security documentation")
1834 ).append(".")
1838 ).append(".")
1835 );
1839 );
1836
1840
1837 var nb = this;
1841 var nb = this;
1838 IPython.dialog.modal({
1842 IPython.dialog.modal({
1839 title: "Trust this notebook?",
1843 title: "Trust this notebook?",
1840 body: body,
1844 body: body,
1841
1845
1842 buttons: {
1846 buttons: {
1843 Cancel : {},
1847 Cancel : {},
1844 Trust : {
1848 Trust : {
1845 class : "btn-danger",
1849 class : "btn-danger",
1846 click : function () {
1850 click : function () {
1847 var cells = nb.get_cells();
1851 var cells = nb.get_cells();
1848 for (var i = 0; i < cells.length; i++) {
1852 for (var i = 0; i < cells.length; i++) {
1849 var cell = cells[i];
1853 var cell = cells[i];
1850 if (cell.cell_type == 'code') {
1854 if (cell.cell_type == 'code') {
1851 cell.output_area.trusted = true;
1855 cell.output_area.trusted = true;
1852 }
1856 }
1853 }
1857 }
1854 $([IPython.events]).on('notebook_saved.Notebook', function () {
1858 $([IPython.events]).on('notebook_saved.Notebook', function () {
1855 window.location.reload();
1859 window.location.reload();
1856 });
1860 });
1857 nb.save_notebook();
1861 nb.save_notebook();
1858 }
1862 }
1859 }
1863 }
1860 }
1864 }
1861 });
1865 });
1862 };
1866 };
1863
1867
1864 Notebook.prototype.new_notebook = function(){
1868 Notebook.prototype.new_notebook = function(){
1865 var path = this.notebook_path;
1869 var path = this.notebook_path;
1866 var base_url = this.base_url;
1870 var base_url = this.base_url;
1867 var settings = {
1871 var settings = {
1868 processData : false,
1872 processData : false,
1869 cache : false,
1873 cache : false,
1870 type : "POST",
1874 type : "POST",
1871 dataType : "json",
1875 dataType : "json",
1872 async : false,
1876 async : false,
1873 success : function (data, status, xhr){
1877 success : function (data, status, xhr){
1874 var notebook_name = data.name;
1878 var notebook_name = data.name;
1875 window.open(
1879 window.open(
1876 utils.url_join_encode(
1880 utils.url_join_encode(
1877 base_url,
1881 base_url,
1878 'notebooks',
1882 'notebooks',
1879 path,
1883 path,
1880 notebook_name
1884 notebook_name
1881 ),
1885 ),
1882 '_blank'
1886 '_blank'
1883 );
1887 );
1884 }
1888 }
1885 };
1889 };
1886 var url = utils.url_join_encode(
1890 var url = utils.url_join_encode(
1887 base_url,
1891 base_url,
1888 'api/notebooks',
1892 'api/notebooks',
1889 path
1893 path
1890 );
1894 );
1891 $.ajax(url,settings);
1895 $.ajax(url,settings);
1892 };
1896 };
1893
1897
1894
1898
1895 Notebook.prototype.copy_notebook = function(){
1899 Notebook.prototype.copy_notebook = function(){
1896 var path = this.notebook_path;
1900 var path = this.notebook_path;
1897 var base_url = this.base_url;
1901 var base_url = this.base_url;
1898 var settings = {
1902 var settings = {
1899 processData : false,
1903 processData : false,
1900 cache : false,
1904 cache : false,
1901 type : "POST",
1905 type : "POST",
1902 dataType : "json",
1906 dataType : "json",
1903 data : JSON.stringify({copy_from : this.notebook_name}),
1907 data : JSON.stringify({copy_from : this.notebook_name}),
1904 async : false,
1908 async : false,
1905 success : function (data, status, xhr) {
1909 success : function (data, status, xhr) {
1906 window.open(utils.url_join_encode(
1910 window.open(utils.url_join_encode(
1907 base_url,
1911 base_url,
1908 'notebooks',
1912 'notebooks',
1909 data.path,
1913 data.path,
1910 data.name
1914 data.name
1911 ), '_blank');
1915 ), '_blank');
1912 }
1916 }
1913 };
1917 };
1914 var url = utils.url_join_encode(
1918 var url = utils.url_join_encode(
1915 base_url,
1919 base_url,
1916 'api/notebooks',
1920 'api/notebooks',
1917 path
1921 path
1918 );
1922 );
1919 $.ajax(url,settings);
1923 $.ajax(url,settings);
1920 };
1924 };
1921
1925
1922 Notebook.prototype.rename = function (nbname) {
1926 Notebook.prototype.rename = function (nbname) {
1923 var that = this;
1927 var that = this;
1924 if (!nbname.match(/\.ipynb$/)) {
1928 if (!nbname.match(/\.ipynb$/)) {
1925 nbname = nbname + ".ipynb";
1929 nbname = nbname + ".ipynb";
1926 }
1930 }
1927 var data = {name: nbname};
1931 var data = {name: nbname};
1928 var settings = {
1932 var settings = {
1929 processData : false,
1933 processData : false,
1930 cache : false,
1934 cache : false,
1931 type : "PATCH",
1935 type : "PATCH",
1932 data : JSON.stringify(data),
1936 data : JSON.stringify(data),
1933 dataType: "json",
1937 dataType: "json",
1934 headers : {'Content-Type': 'application/json'},
1938 headers : {'Content-Type': 'application/json'},
1935 success : $.proxy(that.rename_success, this),
1939 success : $.proxy(that.rename_success, this),
1936 error : $.proxy(that.rename_error, this)
1940 error : $.proxy(that.rename_error, this)
1937 };
1941 };
1938 $([IPython.events]).trigger('rename_notebook.Notebook', data);
1942 $([IPython.events]).trigger('rename_notebook.Notebook', data);
1939 var url = utils.url_join_encode(
1943 var url = utils.url_join_encode(
1940 this.base_url,
1944 this.base_url,
1941 'api/notebooks',
1945 'api/notebooks',
1942 this.notebook_path,
1946 this.notebook_path,
1943 this.notebook_name
1947 this.notebook_name
1944 );
1948 );
1945 $.ajax(url, settings);
1949 $.ajax(url, settings);
1946 };
1950 };
1947
1951
1948 Notebook.prototype.delete = function () {
1952 Notebook.prototype.delete = function () {
1949 var that = this;
1953 var that = this;
1950 var settings = {
1954 var settings = {
1951 processData : false,
1955 processData : false,
1952 cache : false,
1956 cache : false,
1953 type : "DELETE",
1957 type : "DELETE",
1954 dataType: "json",
1958 dataType: "json",
1955 };
1959 };
1956 var url = utils.url_join_encode(
1960 var url = utils.url_join_encode(
1957 this.base_url,
1961 this.base_url,
1958 'api/notebooks',
1962 'api/notebooks',
1959 this.notebook_path,
1963 this.notebook_path,
1960 this.notebook_name
1964 this.notebook_name
1961 );
1965 );
1962 $.ajax(url, settings);
1966 $.ajax(url, settings);
1963 };
1967 };
1964
1968
1965
1969
1966 Notebook.prototype.rename_success = function (json, status, xhr) {
1970 Notebook.prototype.rename_success = function (json, status, xhr) {
1967 var name = this.notebook_name = json.name;
1971 var name = this.notebook_name = json.name;
1968 var path = json.path;
1972 var path = json.path;
1969 this.session.rename_notebook(name, path);
1973 this.session.rename_notebook(name, path);
1970 $([IPython.events]).trigger('notebook_renamed.Notebook', json);
1974 $([IPython.events]).trigger('notebook_renamed.Notebook', json);
1971 };
1975 };
1972
1976
1973 Notebook.prototype.rename_error = function (xhr, status, error) {
1977 Notebook.prototype.rename_error = function (xhr, status, error) {
1974 var that = this;
1978 var that = this;
1975 var dialog = $('<div/>').append(
1979 var dialog = $('<div/>').append(
1976 $("<p/>").addClass("rename-message")
1980 $("<p/>").addClass("rename-message")
1977 .text('This notebook name already exists.')
1981 .text('This notebook name already exists.')
1978 );
1982 );
1979 $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]);
1983 $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]);
1980 IPython.dialog.modal({
1984 IPython.dialog.modal({
1981 title: "Notebook Rename Error!",
1985 title: "Notebook Rename Error!",
1982 body: dialog,
1986 body: dialog,
1983 buttons : {
1987 buttons : {
1984 "Cancel": {},
1988 "Cancel": {},
1985 "OK": {
1989 "OK": {
1986 class: "btn-primary",
1990 class: "btn-primary",
1987 click: function () {
1991 click: function () {
1988 IPython.save_widget.rename_notebook();
1992 IPython.save_widget.rename_notebook();
1989 }}
1993 }}
1990 },
1994 },
1991 open : function (event, ui) {
1995 open : function (event, ui) {
1992 var that = $(this);
1996 var that = $(this);
1993 // Upon ENTER, click the OK button.
1997 // Upon ENTER, click the OK button.
1994 that.find('input[type="text"]').keydown(function (event, ui) {
1998 that.find('input[type="text"]').keydown(function (event, ui) {
1995 if (event.which === IPython.keyboard.keycodes.enter) {
1999 if (event.which === IPython.keyboard.keycodes.enter) {
1996 that.find('.btn-primary').first().click();
2000 that.find('.btn-primary').first().click();
1997 }
2001 }
1998 });
2002 });
1999 that.find('input[type="text"]').focus();
2003 that.find('input[type="text"]').focus();
2000 }
2004 }
2001 });
2005 });
2002 };
2006 };
2003
2007
2004 /**
2008 /**
2005 * Request a notebook's data from the server.
2009 * Request a notebook's data from the server.
2006 *
2010 *
2007 * @method load_notebook
2011 * @method load_notebook
2008 * @param {String} notebook_name and path A notebook to load
2012 * @param {String} notebook_name and path A notebook to load
2009 */
2013 */
2010 Notebook.prototype.load_notebook = function (notebook_name, notebook_path) {
2014 Notebook.prototype.load_notebook = function (notebook_name, notebook_path) {
2011 var that = this;
2015 var that = this;
2012 this.notebook_name = notebook_name;
2016 this.notebook_name = notebook_name;
2013 this.notebook_path = notebook_path;
2017 this.notebook_path = notebook_path;
2014 // We do the call with settings so we can set cache to false.
2018 // We do the call with settings so we can set cache to false.
2015 var settings = {
2019 var settings = {
2016 processData : false,
2020 processData : false,
2017 cache : false,
2021 cache : false,
2018 type : "GET",
2022 type : "GET",
2019 dataType : "json",
2023 dataType : "json",
2020 success : $.proxy(this.load_notebook_success,this),
2024 success : $.proxy(this.load_notebook_success,this),
2021 error : $.proxy(this.load_notebook_error,this),
2025 error : $.proxy(this.load_notebook_error,this),
2022 };
2026 };
2023 $([IPython.events]).trigger('notebook_loading.Notebook');
2027 $([IPython.events]).trigger('notebook_loading.Notebook');
2024 var url = utils.url_join_encode(
2028 var url = utils.url_join_encode(
2025 this.base_url,
2029 this.base_url,
2026 'api/notebooks',
2030 'api/notebooks',
2027 this.notebook_path,
2031 this.notebook_path,
2028 this.notebook_name
2032 this.notebook_name
2029 );
2033 );
2030 $.ajax(url, settings);
2034 $.ajax(url, settings);
2031 };
2035 };
2032
2036
2033 /**
2037 /**
2034 * Success callback for loading a notebook from the server.
2038 * Success callback for loading a notebook from the server.
2035 *
2039 *
2036 * Load notebook data from the JSON response.
2040 * Load notebook data from the JSON response.
2037 *
2041 *
2038 * @method load_notebook_success
2042 * @method load_notebook_success
2039 * @param {Object} data JSON representation of a notebook
2043 * @param {Object} data JSON representation of a notebook
2040 * @param {String} status Description of response status
2044 * @param {String} status Description of response status
2041 * @param {jqXHR} xhr jQuery Ajax object
2045 * @param {jqXHR} xhr jQuery Ajax object
2042 */
2046 */
2043 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
2047 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
2044 this.fromJSON(data);
2048 this.fromJSON(data);
2045 if (this.ncells() === 0) {
2049 if (this.ncells() === 0) {
2046 this.insert_cell_below('code');
2050 this.insert_cell_below('code');
2047 this.edit_mode(0);
2051 this.edit_mode(0);
2048 } else {
2052 } else {
2049 this.select(0);
2053 this.select(0);
2050 this.handle_command_mode(this.get_cell(0));
2054 this.handle_command_mode(this.get_cell(0));
2051 }
2055 }
2052 this.set_dirty(false);
2056 this.set_dirty(false);
2053 this.scroll_to_top();
2057 this.scroll_to_top();
2054 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
2058 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
2055 var msg = "This notebook has been converted from an older " +
2059 var msg = "This notebook has been converted from an older " +
2056 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
2060 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
2057 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
2061 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
2058 "newer notebook format will be used and older versions of IPython " +
2062 "newer notebook format will be used and older versions of IPython " +
2059 "may not be able to read it. To keep the older version, close the " +
2063 "may not be able to read it. To keep the older version, close the " +
2060 "notebook without saving it.";
2064 "notebook without saving it.";
2061 IPython.dialog.modal({
2065 IPython.dialog.modal({
2062 title : "Notebook converted",
2066 title : "Notebook converted",
2063 body : msg,
2067 body : msg,
2064 buttons : {
2068 buttons : {
2065 OK : {
2069 OK : {
2066 class : "btn-primary"
2070 class : "btn-primary"
2067 }
2071 }
2068 }
2072 }
2069 });
2073 });
2070 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
2074 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
2071 var that = this;
2075 var that = this;
2072 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
2076 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
2073 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
2077 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
2074 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
2078 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
2075 this_vs + ". You can still work with this notebook, but some features " +
2079 this_vs + ". You can still work with this notebook, but some features " +
2076 "introduced in later notebook versions may not be available.";
2080 "introduced in later notebook versions may not be available.";
2077
2081
2078 IPython.dialog.modal({
2082 IPython.dialog.modal({
2079 title : "Newer Notebook",
2083 title : "Newer Notebook",
2080 body : msg,
2084 body : msg,
2081 buttons : {
2085 buttons : {
2082 OK : {
2086 OK : {
2083 class : "btn-danger"
2087 class : "btn-danger"
2084 }
2088 }
2085 }
2089 }
2086 });
2090 });
2087
2091
2088 }
2092 }
2089
2093
2090 // Create the session after the notebook is completely loaded to prevent
2094 // Create the session after the notebook is completely loaded to prevent
2091 // code execution upon loading, which is a security risk.
2095 // code execution upon loading, which is a security risk.
2092 if (this.session === null) {
2096 if (this.session === null) {
2093 this.start_session();
2097 this.start_session();
2094 }
2098 }
2095 // load our checkpoint list
2099 // load our checkpoint list
2096 this.list_checkpoints();
2100 this.list_checkpoints();
2097
2101
2098 // load toolbar state
2102 // load toolbar state
2099 if (this.metadata.celltoolbar) {
2103 if (this.metadata.celltoolbar) {
2100 IPython.CellToolbar.global_show();
2104 IPython.CellToolbar.global_show();
2101 IPython.CellToolbar.activate_preset(this.metadata.celltoolbar);
2105 IPython.CellToolbar.activate_preset(this.metadata.celltoolbar);
2102 }
2106 }
2103
2107
2108 // now that we're fully loaded, it is safe to restore save functionality
2109 delete(this.save_notebook);
2104 $([IPython.events]).trigger('notebook_loaded.Notebook');
2110 $([IPython.events]).trigger('notebook_loaded.Notebook');
2105 };
2111 };
2106
2112
2107 /**
2113 /**
2108 * Failure callback for loading a notebook from the server.
2114 * Failure callback for loading a notebook from the server.
2109 *
2115 *
2110 * @method load_notebook_error
2116 * @method load_notebook_error
2111 * @param {jqXHR} xhr jQuery Ajax object
2117 * @param {jqXHR} xhr jQuery Ajax object
2112 * @param {String} status Description of response status
2118 * @param {String} status Description of response status
2113 * @param {String} error HTTP error message
2119 * @param {String} error HTTP error message
2114 */
2120 */
2115 Notebook.prototype.load_notebook_error = function (xhr, status, error) {
2121 Notebook.prototype.load_notebook_error = function (xhr, status, error) {
2116 $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]);
2122 $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]);
2117 var msg;
2123 var msg;
2118 if (xhr.status === 400) {
2124 if (xhr.status === 400) {
2119 msg = error;
2125 msg = error;
2120 } else if (xhr.status === 500) {
2126 } else if (xhr.status === 500) {
2121 msg = "An unknown error occurred while loading this notebook. " +
2127 msg = "An unknown error occurred while loading this notebook. " +
2122 "This version can load notebook formats " +
2128 "This version can load notebook formats " +
2123 "v" + this.nbformat + " or earlier.";
2129 "v" + this.nbformat + " or earlier.";
2124 }
2130 }
2125 IPython.dialog.modal({
2131 IPython.dialog.modal({
2126 title: "Error loading notebook",
2132 title: "Error loading notebook",
2127 body : msg,
2133 body : msg,
2128 buttons : {
2134 buttons : {
2129 "OK": {}
2135 "OK": {}
2130 }
2136 }
2131 });
2137 });
2132 };
2138 };
2133
2139
2134 /********************* checkpoint-related *********************/
2140 /********************* checkpoint-related *********************/
2135
2141
2136 /**
2142 /**
2137 * Save the notebook then immediately create a checkpoint.
2143 * Save the notebook then immediately create a checkpoint.
2138 *
2144 *
2139 * @method save_checkpoint
2145 * @method save_checkpoint
2140 */
2146 */
2141 Notebook.prototype.save_checkpoint = function () {
2147 Notebook.prototype.save_checkpoint = function () {
2142 this._checkpoint_after_save = true;
2148 this._checkpoint_after_save = true;
2143 this.save_notebook();
2149 this.save_notebook();
2144 };
2150 };
2145
2151
2146 /**
2152 /**
2147 * Add a checkpoint for this notebook.
2153 * Add a checkpoint for this notebook.
2148 * for use as a callback from checkpoint creation.
2154 * for use as a callback from checkpoint creation.
2149 *
2155 *
2150 * @method add_checkpoint
2156 * @method add_checkpoint
2151 */
2157 */
2152 Notebook.prototype.add_checkpoint = function (checkpoint) {
2158 Notebook.prototype.add_checkpoint = function (checkpoint) {
2153 var found = false;
2159 var found = false;
2154 for (var i = 0; i < this.checkpoints.length; i++) {
2160 for (var i = 0; i < this.checkpoints.length; i++) {
2155 var existing = this.checkpoints[i];
2161 var existing = this.checkpoints[i];
2156 if (existing.id == checkpoint.id) {
2162 if (existing.id == checkpoint.id) {
2157 found = true;
2163 found = true;
2158 this.checkpoints[i] = checkpoint;
2164 this.checkpoints[i] = checkpoint;
2159 break;
2165 break;
2160 }
2166 }
2161 }
2167 }
2162 if (!found) {
2168 if (!found) {
2163 this.checkpoints.push(checkpoint);
2169 this.checkpoints.push(checkpoint);
2164 }
2170 }
2165 this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1];
2171 this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1];
2166 };
2172 };
2167
2173
2168 /**
2174 /**
2169 * List checkpoints for this notebook.
2175 * List checkpoints for this notebook.
2170 *
2176 *
2171 * @method list_checkpoints
2177 * @method list_checkpoints
2172 */
2178 */
2173 Notebook.prototype.list_checkpoints = function () {
2179 Notebook.prototype.list_checkpoints = function () {
2174 var url = utils.url_join_encode(
2180 var url = utils.url_join_encode(
2175 this.base_url,
2181 this.base_url,
2176 'api/notebooks',
2182 'api/notebooks',
2177 this.notebook_path,
2183 this.notebook_path,
2178 this.notebook_name,
2184 this.notebook_name,
2179 'checkpoints'
2185 'checkpoints'
2180 );
2186 );
2181 $.get(url).done(
2187 $.get(url).done(
2182 $.proxy(this.list_checkpoints_success, this)
2188 $.proxy(this.list_checkpoints_success, this)
2183 ).fail(
2189 ).fail(
2184 $.proxy(this.list_checkpoints_error, this)
2190 $.proxy(this.list_checkpoints_error, this)
2185 );
2191 );
2186 };
2192 };
2187
2193
2188 /**
2194 /**
2189 * Success callback for listing checkpoints.
2195 * Success callback for listing checkpoints.
2190 *
2196 *
2191 * @method list_checkpoint_success
2197 * @method list_checkpoint_success
2192 * @param {Object} data JSON representation of a checkpoint
2198 * @param {Object} data JSON representation of a checkpoint
2193 * @param {String} status Description of response status
2199 * @param {String} status Description of response status
2194 * @param {jqXHR} xhr jQuery Ajax object
2200 * @param {jqXHR} xhr jQuery Ajax object
2195 */
2201 */
2196 Notebook.prototype.list_checkpoints_success = function (data, status, xhr) {
2202 Notebook.prototype.list_checkpoints_success = function (data, status, xhr) {
2197 data = $.parseJSON(data);
2203 data = $.parseJSON(data);
2198 this.checkpoints = data;
2204 this.checkpoints = data;
2199 if (data.length) {
2205 if (data.length) {
2200 this.last_checkpoint = data[data.length - 1];
2206 this.last_checkpoint = data[data.length - 1];
2201 } else {
2207 } else {
2202 this.last_checkpoint = null;
2208 this.last_checkpoint = null;
2203 }
2209 }
2204 $([IPython.events]).trigger('checkpoints_listed.Notebook', [data]);
2210 $([IPython.events]).trigger('checkpoints_listed.Notebook', [data]);
2205 };
2211 };
2206
2212
2207 /**
2213 /**
2208 * Failure callback for listing a checkpoint.
2214 * Failure callback for listing a checkpoint.
2209 *
2215 *
2210 * @method list_checkpoint_error
2216 * @method list_checkpoint_error
2211 * @param {jqXHR} xhr jQuery Ajax object
2217 * @param {jqXHR} xhr jQuery Ajax object
2212 * @param {String} status Description of response status
2218 * @param {String} status Description of response status
2213 * @param {String} error_msg HTTP error message
2219 * @param {String} error_msg HTTP error message
2214 */
2220 */
2215 Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) {
2221 Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) {
2216 $([IPython.events]).trigger('list_checkpoints_failed.Notebook');
2222 $([IPython.events]).trigger('list_checkpoints_failed.Notebook');
2217 };
2223 };
2218
2224
2219 /**
2225 /**
2220 * Create a checkpoint of this notebook on the server from the most recent save.
2226 * Create a checkpoint of this notebook on the server from the most recent save.
2221 *
2227 *
2222 * @method create_checkpoint
2228 * @method create_checkpoint
2223 */
2229 */
2224 Notebook.prototype.create_checkpoint = function () {
2230 Notebook.prototype.create_checkpoint = function () {
2225 var url = utils.url_join_encode(
2231 var url = utils.url_join_encode(
2226 this.base_url,
2232 this.base_url,
2227 'api/notebooks',
2233 'api/notebooks',
2228 this.notebook_path,
2234 this.notebook_path,
2229 this.notebook_name,
2235 this.notebook_name,
2230 'checkpoints'
2236 'checkpoints'
2231 );
2237 );
2232 $.post(url).done(
2238 $.post(url).done(
2233 $.proxy(this.create_checkpoint_success, this)
2239 $.proxy(this.create_checkpoint_success, this)
2234 ).fail(
2240 ).fail(
2235 $.proxy(this.create_checkpoint_error, this)
2241 $.proxy(this.create_checkpoint_error, this)
2236 );
2242 );
2237 };
2243 };
2238
2244
2239 /**
2245 /**
2240 * Success callback for creating a checkpoint.
2246 * Success callback for creating a checkpoint.
2241 *
2247 *
2242 * @method create_checkpoint_success
2248 * @method create_checkpoint_success
2243 * @param {Object} data JSON representation of a checkpoint
2249 * @param {Object} data JSON representation of a checkpoint
2244 * @param {String} status Description of response status
2250 * @param {String} status Description of response status
2245 * @param {jqXHR} xhr jQuery Ajax object
2251 * @param {jqXHR} xhr jQuery Ajax object
2246 */
2252 */
2247 Notebook.prototype.create_checkpoint_success = function (data, status, xhr) {
2253 Notebook.prototype.create_checkpoint_success = function (data, status, xhr) {
2248 data = $.parseJSON(data);
2254 data = $.parseJSON(data);
2249 this.add_checkpoint(data);
2255 this.add_checkpoint(data);
2250 $([IPython.events]).trigger('checkpoint_created.Notebook', data);
2256 $([IPython.events]).trigger('checkpoint_created.Notebook', data);
2251 };
2257 };
2252
2258
2253 /**
2259 /**
2254 * Failure callback for creating a checkpoint.
2260 * Failure callback for creating a checkpoint.
2255 *
2261 *
2256 * @method create_checkpoint_error
2262 * @method create_checkpoint_error
2257 * @param {jqXHR} xhr jQuery Ajax object
2263 * @param {jqXHR} xhr jQuery Ajax object
2258 * @param {String} status Description of response status
2264 * @param {String} status Description of response status
2259 * @param {String} error_msg HTTP error message
2265 * @param {String} error_msg HTTP error message
2260 */
2266 */
2261 Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) {
2267 Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) {
2262 $([IPython.events]).trigger('checkpoint_failed.Notebook');
2268 $([IPython.events]).trigger('checkpoint_failed.Notebook');
2263 };
2269 };
2264
2270
2265 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2271 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2266 var that = this;
2272 var that = this;
2267 checkpoint = checkpoint || this.last_checkpoint;
2273 checkpoint = checkpoint || this.last_checkpoint;
2268 if ( ! checkpoint ) {
2274 if ( ! checkpoint ) {
2269 console.log("restore dialog, but no checkpoint to restore to!");
2275 console.log("restore dialog, but no checkpoint to restore to!");
2270 return;
2276 return;
2271 }
2277 }
2272 var body = $('<div/>').append(
2278 var body = $('<div/>').append(
2273 $('<p/>').addClass("p-space").text(
2279 $('<p/>').addClass("p-space").text(
2274 "Are you sure you want to revert the notebook to " +
2280 "Are you sure you want to revert the notebook to " +
2275 "the latest checkpoint?"
2281 "the latest checkpoint?"
2276 ).append(
2282 ).append(
2277 $("<strong/>").text(
2283 $("<strong/>").text(
2278 " This cannot be undone."
2284 " This cannot be undone."
2279 )
2285 )
2280 )
2286 )
2281 ).append(
2287 ).append(
2282 $('<p/>').addClass("p-space").text("The checkpoint was last updated at:")
2288 $('<p/>').addClass("p-space").text("The checkpoint was last updated at:")
2283 ).append(
2289 ).append(
2284 $('<p/>').addClass("p-space").text(
2290 $('<p/>').addClass("p-space").text(
2285 Date(checkpoint.last_modified)
2291 Date(checkpoint.last_modified)
2286 ).css("text-align", "center")
2292 ).css("text-align", "center")
2287 );
2293 );
2288
2294
2289 IPython.dialog.modal({
2295 IPython.dialog.modal({
2290 title : "Revert notebook to checkpoint",
2296 title : "Revert notebook to checkpoint",
2291 body : body,
2297 body : body,
2292 buttons : {
2298 buttons : {
2293 Revert : {
2299 Revert : {
2294 class : "btn-danger",
2300 class : "btn-danger",
2295 click : function () {
2301 click : function () {
2296 that.restore_checkpoint(checkpoint.id);
2302 that.restore_checkpoint(checkpoint.id);
2297 }
2303 }
2298 },
2304 },
2299 Cancel : {}
2305 Cancel : {}
2300 }
2306 }
2301 });
2307 });
2302 };
2308 };
2303
2309
2304 /**
2310 /**
2305 * Restore the notebook to a checkpoint state.
2311 * Restore the notebook to a checkpoint state.
2306 *
2312 *
2307 * @method restore_checkpoint
2313 * @method restore_checkpoint
2308 * @param {String} checkpoint ID
2314 * @param {String} checkpoint ID
2309 */
2315 */
2310 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2316 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2311 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2317 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2312 var url = utils.url_join_encode(
2318 var url = utils.url_join_encode(
2313 this.base_url,
2319 this.base_url,
2314 'api/notebooks',
2320 'api/notebooks',
2315 this.notebook_path,
2321 this.notebook_path,
2316 this.notebook_name,
2322 this.notebook_name,
2317 'checkpoints',
2323 'checkpoints',
2318 checkpoint
2324 checkpoint
2319 );
2325 );
2320 $.post(url).done(
2326 $.post(url).done(
2321 $.proxy(this.restore_checkpoint_success, this)
2327 $.proxy(this.restore_checkpoint_success, this)
2322 ).fail(
2328 ).fail(
2323 $.proxy(this.restore_checkpoint_error, this)
2329 $.proxy(this.restore_checkpoint_error, this)
2324 );
2330 );
2325 };
2331 };
2326
2332
2327 /**
2333 /**
2328 * Success callback for restoring a notebook to a checkpoint.
2334 * Success callback for restoring a notebook to a checkpoint.
2329 *
2335 *
2330 * @method restore_checkpoint_success
2336 * @method restore_checkpoint_success
2331 * @param {Object} data (ignored, should be empty)
2337 * @param {Object} data (ignored, should be empty)
2332 * @param {String} status Description of response status
2338 * @param {String} status Description of response status
2333 * @param {jqXHR} xhr jQuery Ajax object
2339 * @param {jqXHR} xhr jQuery Ajax object
2334 */
2340 */
2335 Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) {
2341 Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) {
2336 $([IPython.events]).trigger('checkpoint_restored.Notebook');
2342 $([IPython.events]).trigger('checkpoint_restored.Notebook');
2337 this.load_notebook(this.notebook_name, this.notebook_path);
2343 this.load_notebook(this.notebook_name, this.notebook_path);
2338 };
2344 };
2339
2345
2340 /**
2346 /**
2341 * Failure callback for restoring a notebook to a checkpoint.
2347 * Failure callback for restoring a notebook to a checkpoint.
2342 *
2348 *
2343 * @method restore_checkpoint_error
2349 * @method restore_checkpoint_error
2344 * @param {jqXHR} xhr jQuery Ajax object
2350 * @param {jqXHR} xhr jQuery Ajax object
2345 * @param {String} status Description of response status
2351 * @param {String} status Description of response status
2346 * @param {String} error_msg HTTP error message
2352 * @param {String} error_msg HTTP error message
2347 */
2353 */
2348 Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) {
2354 Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) {
2349 $([IPython.events]).trigger('checkpoint_restore_failed.Notebook');
2355 $([IPython.events]).trigger('checkpoint_restore_failed.Notebook');
2350 };
2356 };
2351
2357
2352 /**
2358 /**
2353 * Delete a notebook checkpoint.
2359 * Delete a notebook checkpoint.
2354 *
2360 *
2355 * @method delete_checkpoint
2361 * @method delete_checkpoint
2356 * @param {String} checkpoint ID
2362 * @param {String} checkpoint ID
2357 */
2363 */
2358 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2364 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2359 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2365 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2360 var url = utils.url_join_encode(
2366 var url = utils.url_join_encode(
2361 this.base_url,
2367 this.base_url,
2362 'api/notebooks',
2368 'api/notebooks',
2363 this.notebook_path,
2369 this.notebook_path,
2364 this.notebook_name,
2370 this.notebook_name,
2365 'checkpoints',
2371 'checkpoints',
2366 checkpoint
2372 checkpoint
2367 );
2373 );
2368 $.ajax(url, {
2374 $.ajax(url, {
2369 type: 'DELETE',
2375 type: 'DELETE',
2370 success: $.proxy(this.delete_checkpoint_success, this),
2376 success: $.proxy(this.delete_checkpoint_success, this),
2371 error: $.proxy(this.delete_notebook_error,this)
2377 error: $.proxy(this.delete_notebook_error,this)
2372 });
2378 });
2373 };
2379 };
2374
2380
2375 /**
2381 /**
2376 * Success callback for deleting a notebook checkpoint
2382 * Success callback for deleting a notebook checkpoint
2377 *
2383 *
2378 * @method delete_checkpoint_success
2384 * @method delete_checkpoint_success
2379 * @param {Object} data (ignored, should be empty)
2385 * @param {Object} data (ignored, should be empty)
2380 * @param {String} status Description of response status
2386 * @param {String} status Description of response status
2381 * @param {jqXHR} xhr jQuery Ajax object
2387 * @param {jqXHR} xhr jQuery Ajax object
2382 */
2388 */
2383 Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) {
2389 Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) {
2384 $([IPython.events]).trigger('checkpoint_deleted.Notebook', data);
2390 $([IPython.events]).trigger('checkpoint_deleted.Notebook', data);
2385 this.load_notebook(this.notebook_name, this.notebook_path);
2391 this.load_notebook(this.notebook_name, this.notebook_path);
2386 };
2392 };
2387
2393
2388 /**
2394 /**
2389 * Failure callback for deleting a notebook checkpoint.
2395 * Failure callback for deleting a notebook checkpoint.
2390 *
2396 *
2391 * @method delete_checkpoint_error
2397 * @method delete_checkpoint_error
2392 * @param {jqXHR} xhr jQuery Ajax object
2398 * @param {jqXHR} xhr jQuery Ajax object
2393 * @param {String} status Description of response status
2399 * @param {String} status Description of response status
2394 * @param {String} error_msg HTTP error message
2400 * @param {String} error_msg HTTP error message
2395 */
2401 */
2396 Notebook.prototype.delete_checkpoint_error = function (xhr, status, error_msg) {
2402 Notebook.prototype.delete_checkpoint_error = function (xhr, status, error_msg) {
2397 $([IPython.events]).trigger('checkpoint_delete_failed.Notebook');
2403 $([IPython.events]).trigger('checkpoint_delete_failed.Notebook');
2398 };
2404 };
2399
2405
2400
2406
2401 IPython.Notebook = Notebook;
2407 IPython.Notebook = Notebook;
2402
2408
2403
2409
2404 return IPython;
2410 return IPython;
2405
2411
2406 }(IPython));
2412 }(IPython));
2407
2413
@@ -1,235 +1,235 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2012 The IPython Development Team
2 // Copyright (C) 2012 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Notification widget
9 // Notification widget
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15
15
16
16
17 var NotificationArea = function (selector) {
17 var NotificationArea = function (selector) {
18 this.selector = selector;
18 this.selector = selector;
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
21 }
21 }
22 this.widget_dict = {};
22 this.widget_dict = {};
23 };
23 };
24
24
25 NotificationArea.prototype.temp_message = function (msg, timeout, css_class) {
25 NotificationArea.prototype.temp_message = function (msg, timeout, css_class) {
26 var uuid = utils.uuid();
26 var uuid = utils.uuid();
27 if( css_class == 'danger') {css_class = 'ui-state-error';}
27 if( css_class == 'danger') {css_class = 'ui-state-error';}
28 if( css_class == 'warning') {css_class = 'ui-state-highlight';}
28 if( css_class == 'warning') {css_class = 'ui-state-highlight';}
29 var tdiv = $('<div>')
29 var tdiv = $('<div>')
30 .attr('id',uuid)
30 .attr('id',uuid)
31 .addClass('notification_widget ui-widget ui-widget-content ui-corner-all')
31 .addClass('notification_widget ui-widget ui-widget-content ui-corner-all')
32 .addClass('border-box-sizing')
32 .addClass('border-box-sizing')
33 .addClass(css_class)
33 .addClass(css_class)
34 .hide()
34 .hide()
35 .text(msg);
35 .text(msg);
36
36
37 $(this.selector).append(tdiv);
37 $(this.selector).append(tdiv);
38 var tmout = Math.max(1500,(timeout||1500));
38 var tmout = Math.max(1500,(timeout||1500));
39 tdiv.fadeIn(100);
39 tdiv.fadeIn(100);
40
40
41 setTimeout(function () {
41 setTimeout(function () {
42 tdiv.fadeOut(100, function () {tdiv.remove();});
42 tdiv.fadeOut(100, function () {tdiv.remove();});
43 }, tmout);
43 }, tmout);
44 };
44 };
45
45
46 NotificationArea.prototype.widget = function(name) {
46 NotificationArea.prototype.widget = function(name) {
47 if(this.widget_dict[name] === undefined) {
47 if(this.widget_dict[name] === undefined) {
48 return this.new_notification_widget(name);
48 return this.new_notification_widget(name);
49 }
49 }
50 return this.get_widget(name);
50 return this.get_widget(name);
51 };
51 };
52
52
53 NotificationArea.prototype.get_widget = function(name) {
53 NotificationArea.prototype.get_widget = function(name) {
54 if(this.widget_dict[name] === undefined) {
54 if(this.widget_dict[name] === undefined) {
55 throw('no widgets with this name');
55 throw('no widgets with this name');
56 }
56 }
57 return this.widget_dict[name];
57 return this.widget_dict[name];
58 };
58 };
59
59
60 NotificationArea.prototype.new_notification_widget = function(name) {
60 NotificationArea.prototype.new_notification_widget = function(name) {
61 if(this.widget_dict[name] !== undefined) {
61 if(this.widget_dict[name] !== undefined) {
62 throw('widget with that name already exists ! ');
62 throw('widget with that name already exists ! ');
63 }
63 }
64 var div = $('<div/>').attr('id','notification_'+name);
64 var div = $('<div/>').attr('id','notification_'+name);
65 $(this.selector).append(div);
65 $(this.selector).append(div);
66 this.widget_dict[name] = new IPython.NotificationWidget('#notification_'+name);
66 this.widget_dict[name] = new IPython.NotificationWidget('#notification_'+name);
67 return this.widget_dict[name];
67 return this.widget_dict[name];
68 };
68 };
69
69
70 NotificationArea.prototype.init_notification_widgets = function() {
70 NotificationArea.prototype.init_notification_widgets = function() {
71 var knw = this.new_notification_widget('kernel');
71 var knw = this.new_notification_widget('kernel');
72 var $kernel_ind_icon = $("#kernel_indicator_icon");
72 var $kernel_ind_icon = $("#kernel_indicator_icon");
73 var $modal_ind_icon = $("#modal_indicator_icon");
73 var $modal_ind_icon = $("#modal_indicator_icon");
74
74
75 // Command/Edit mode
75 // Command/Edit mode
76 $([IPython.events]).on('edit_mode.Notebook',function () {
76 $([IPython.events]).on('edit_mode.Notebook',function () {
77 IPython.save_widget.update_document_title();
77 IPython.save_widget.update_document_title();
78 $modal_ind_icon.attr('class','edit_mode_icon').attr('title','Edit Mode');
78 $modal_ind_icon.attr('class','edit_mode_icon').attr('title','Edit Mode');
79 });
79 });
80
80
81 $([IPython.events]).on('command_mode.Notebook',function () {
81 $([IPython.events]).on('command_mode.Notebook',function () {
82 IPython.save_widget.update_document_title();
82 IPython.save_widget.update_document_title();
83 $modal_ind_icon.attr('class','command_mode_icon').attr('title','Command Mode');
83 $modal_ind_icon.attr('class','command_mode_icon').attr('title','Command Mode');
84 });
84 });
85
85
86 // Implicitly start off in Command mode, switching to Edit mode will trigger event
86 // Implicitly start off in Command mode, switching to Edit mode will trigger event
87 $modal_ind_icon.attr('class','command-mode_icon').attr('title','Command Mode');
87 $modal_ind_icon.attr('class','command-mode_icon').attr('title','Command Mode');
88
88
89 // Kernel events
89 // Kernel events
90 $([IPython.events]).on('status_idle.Kernel',function () {
90 $([IPython.events]).on('status_idle.Kernel',function () {
91 IPython.save_widget.update_document_title();
91 IPython.save_widget.update_document_title();
92 $kernel_ind_icon.attr('class','kernel_idle_icon').attr('title','Kernel Idle');
92 $kernel_ind_icon.attr('class','kernel_idle_icon').attr('title','Kernel Idle');
93 });
93 });
94
94
95 $([IPython.events]).on('status_busy.Kernel',function () {
95 $([IPython.events]).on('status_busy.Kernel',function () {
96 window.document.title='(Busy) '+window.document.title;
96 window.document.title='(Busy) '+window.document.title;
97 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
97 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
98 });
98 });
99
99
100 $([IPython.events]).on('status_restarting.Kernel',function () {
100 $([IPython.events]).on('status_restarting.Kernel',function () {
101 IPython.save_widget.update_document_title();
101 IPython.save_widget.update_document_title();
102 knw.set_message("Restarting kernel", 2000);
102 knw.set_message("Restarting kernel", 2000);
103 });
103 });
104
104
105 $([IPython.events]).on('status_interrupting.Kernel',function () {
105 $([IPython.events]).on('status_interrupting.Kernel',function () {
106 knw.set_message("Interrupting kernel", 2000);
106 knw.set_message("Interrupting kernel", 2000);
107 });
107 });
108
108
109 // Start the kernel indicator in the busy state, and send a kernel_info request.
109 // Start the kernel indicator in the busy state, and send a kernel_info request.
110 // When the kernel_info reply arrives, the kernel is idle.
110 // When the kernel_info reply arrives, the kernel is idle.
111 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
111 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
112
112
113 $([IPython.events]).on('status_started.Kernel', function (evt, data) {
113 $([IPython.events]).on('status_started.Kernel', function (evt, data) {
114 data.kernel.kernel_info(function () {
114 data.kernel.kernel_info(function () {
115 $([IPython.events]).trigger('status_idle.Kernel');
115 $([IPython.events]).trigger('status_idle.Kernel');
116 });
116 });
117 });
117 });
118
118
119 $([IPython.events]).on('status_dead.Kernel',function () {
119 $([IPython.events]).on('status_dead.Kernel',function () {
120 var msg = 'The kernel has died, and the automatic restart has failed.' +
120 var msg = 'The kernel has died, and the automatic restart has failed.' +
121 ' It is possible the kernel cannot be restarted.' +
121 ' It is possible the kernel cannot be restarted.' +
122 ' If you are not able to restart the kernel, you will still be able to save' +
122 ' If you are not able to restart the kernel, you will still be able to save' +
123 ' the notebook, but running code will no longer work until the notebook' +
123 ' the notebook, but running code will no longer work until the notebook' +
124 ' is reopened.';
124 ' is reopened.';
125
125
126 IPython.dialog.modal({
126 IPython.dialog.modal({
127 title: "Dead kernel",
127 title: "Dead kernel",
128 body : msg,
128 body : msg,
129 buttons : {
129 buttons : {
130 "Manual Restart": {
130 "Manual Restart": {
131 class: "btn-danger",
131 class: "btn-danger",
132 click: function () {
132 click: function () {
133 $([IPython.events]).trigger('status_restarting.Kernel');
133 $([IPython.events]).trigger('status_restarting.Kernel');
134 IPython.notebook.start_kernel();
134 IPython.notebook.start_kernel();
135 }
135 }
136 },
136 },
137 "Don't restart": {}
137 "Don't restart": {}
138 }
138 }
139 });
139 });
140 });
140 });
141
141
142 $([IPython.events]).on('websocket_closed.Kernel', function (event, data) {
142 $([IPython.events]).on('websocket_closed.Kernel', function (event, data) {
143 var kernel = data.kernel;
143 var kernel = data.kernel;
144 var ws_url = data.ws_url;
144 var ws_url = data.ws_url;
145 var early = data.early;
145 var early = data.early;
146 var msg;
146 var msg;
147 if (!early) {
147 if (!early) {
148 knw.set_message('Reconnecting WebSockets', 1000);
148 knw.set_message('Reconnecting WebSockets', 1000);
149 setTimeout(function () {
149 setTimeout(function () {
150 kernel.start_channels();
150 kernel.start_channels();
151 }, 5000);
151 }, 5000);
152 return;
152 return;
153 }
153 }
154 console.log('WebSocket connection failed: ', ws_url);
154 console.log('WebSocket connection failed: ', ws_url);
155 msg = "A WebSocket connection could not be established." +
155 msg = "A WebSocket connection could not be established." +
156 " You will NOT be able to run code. Check your" +
156 " You will NOT be able to run code. Check your" +
157 " network connection or notebook server configuration.";
157 " network connection or notebook server configuration.";
158 IPython.dialog.modal({
158 IPython.dialog.modal({
159 title: "WebSocket connection failed",
159 title: "WebSocket connection failed",
160 body: msg,
160 body: msg,
161 buttons : {
161 buttons : {
162 "OK": {},
162 "OK": {},
163 "Reconnect": {
163 "Reconnect": {
164 click: function () {
164 click: function () {
165 knw.set_message('Reconnecting WebSockets', 1000);
165 knw.set_message('Reconnecting WebSockets', 1000);
166 setTimeout(function () {
166 setTimeout(function () {
167 kernel.start_channels();
167 kernel.start_channels();
168 }, 5000);
168 }, 5000);
169 }
169 }
170 }
170 }
171 }
171 }
172 });
172 });
173 });
173 });
174
174
175
175
176 var nnw = this.new_notification_widget('notebook');
176 var nnw = this.new_notification_widget('notebook');
177
177
178 // Notebook events
178 // Notebook events
179 $([IPython.events]).on('notebook_loading.Notebook', function () {
179 $([IPython.events]).on('notebook_loading.Notebook', function () {
180 nnw.set_message("Loading notebook",500);
180 nnw.set_message("Loading notebook",500);
181 });
181 });
182 $([IPython.events]).on('notebook_loaded.Notebook', function () {
182 $([IPython.events]).on('notebook_loaded.Notebook', function () {
183 nnw.set_message("Notebook loaded",500);
183 nnw.set_message("Notebook loaded",500);
184 });
184 });
185 $([IPython.events]).on('notebook_saving.Notebook', function () {
185 $([IPython.events]).on('notebook_saving.Notebook', function () {
186 nnw.set_message("Saving notebook",500);
186 nnw.set_message("Saving notebook",500);
187 });
187 });
188 $([IPython.events]).on('notebook_saved.Notebook', function () {
188 $([IPython.events]).on('notebook_saved.Notebook', function () {
189 nnw.set_message("Notebook saved",2000);
189 nnw.set_message("Notebook saved",2000);
190 });
190 });
191 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
191 $([IPython.events]).on('notebook_save_failed.Notebook', function (evt, xhr, status, data) {
192 nnw.set_message("Notebook save failed");
192 nnw.set_message(data || "Notebook save failed");
193 });
193 });
194
194
195 // Checkpoint events
195 // Checkpoint events
196 $([IPython.events]).on('checkpoint_created.Notebook', function (evt, data) {
196 $([IPython.events]).on('checkpoint_created.Notebook', function (evt, data) {
197 var msg = "Checkpoint created";
197 var msg = "Checkpoint created";
198 if (data.last_modified) {
198 if (data.last_modified) {
199 var d = new Date(data.last_modified);
199 var d = new Date(data.last_modified);
200 msg = msg + ": " + d.format("HH:MM:ss");
200 msg = msg + ": " + d.format("HH:MM:ss");
201 }
201 }
202 nnw.set_message(msg, 2000);
202 nnw.set_message(msg, 2000);
203 });
203 });
204 $([IPython.events]).on('checkpoint_failed.Notebook', function () {
204 $([IPython.events]).on('checkpoint_failed.Notebook', function () {
205 nnw.set_message("Checkpoint failed");
205 nnw.set_message("Checkpoint failed");
206 });
206 });
207 $([IPython.events]).on('checkpoint_deleted.Notebook', function () {
207 $([IPython.events]).on('checkpoint_deleted.Notebook', function () {
208 nnw.set_message("Checkpoint deleted", 500);
208 nnw.set_message("Checkpoint deleted", 500);
209 });
209 });
210 $([IPython.events]).on('checkpoint_delete_failed.Notebook', function () {
210 $([IPython.events]).on('checkpoint_delete_failed.Notebook', function () {
211 nnw.set_message("Checkpoint delete failed");
211 nnw.set_message("Checkpoint delete failed");
212 });
212 });
213 $([IPython.events]).on('checkpoint_restoring.Notebook', function () {
213 $([IPython.events]).on('checkpoint_restoring.Notebook', function () {
214 nnw.set_message("Restoring to checkpoint...", 500);
214 nnw.set_message("Restoring to checkpoint...", 500);
215 });
215 });
216 $([IPython.events]).on('checkpoint_restore_failed.Notebook', function () {
216 $([IPython.events]).on('checkpoint_restore_failed.Notebook', function () {
217 nnw.set_message("Checkpoint restore failed");
217 nnw.set_message("Checkpoint restore failed");
218 });
218 });
219
219
220 // Autosave events
220 // Autosave events
221 $([IPython.events]).on('autosave_disabled.Notebook', function () {
221 $([IPython.events]).on('autosave_disabled.Notebook', function () {
222 nnw.set_message("Autosave disabled", 2000);
222 nnw.set_message("Autosave disabled", 2000);
223 });
223 });
224 $([IPython.events]).on('autosave_enabled.Notebook', function (evt, interval) {
224 $([IPython.events]).on('autosave_enabled.Notebook', function (evt, interval) {
225 nnw.set_message("Saving every " + interval / 1000 + "s", 1000);
225 nnw.set_message("Saving every " + interval / 1000 + "s", 1000);
226 });
226 });
227
227
228 };
228 };
229
229
230 IPython.NotificationArea = NotificationArea;
230 IPython.NotificationArea = NotificationArea;
231
231
232 return IPython;
232 return IPython;
233
233
234 }(IPython));
234 }(IPython));
235
235
@@ -1,874 +1,878 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008 The IPython Development Team
2 // Copyright (C) 2008 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // OutputArea
9 // OutputArea
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule OutputArea
15 * @submodule OutputArea
16 */
16 */
17 var IPython = (function (IPython) {
17 var IPython = (function (IPython) {
18 "use strict";
18 "use strict";
19
19
20 var utils = IPython.utils;
20 var utils = IPython.utils;
21
21
22 /**
22 /**
23 * @class OutputArea
23 * @class OutputArea
24 *
24 *
25 * @constructor
25 * @constructor
26 */
26 */
27
27
28 var OutputArea = function (selector, prompt_area) {
28 var OutputArea = function (selector, prompt_area) {
29 this.selector = selector;
29 this.selector = selector;
30 this.wrapper = $(selector);
30 this.wrapper = $(selector);
31 this.outputs = [];
31 this.outputs = [];
32 this.collapsed = false;
32 this.collapsed = false;
33 this.scrolled = false;
33 this.scrolled = false;
34 this.trusted = true;
34 this.trusted = true;
35 this.clear_queued = null;
35 this.clear_queued = null;
36 if (prompt_area === undefined) {
36 if (prompt_area === undefined) {
37 this.prompt_area = true;
37 this.prompt_area = true;
38 } else {
38 } else {
39 this.prompt_area = prompt_area;
39 this.prompt_area = prompt_area;
40 }
40 }
41 this.create_elements();
41 this.create_elements();
42 this.style();
42 this.style();
43 this.bind_events();
43 this.bind_events();
44 };
44 };
45
45
46
46
47 /**
47 /**
48 * Class prototypes
48 * Class prototypes
49 **/
49 **/
50
50
51 OutputArea.prototype.create_elements = function () {
51 OutputArea.prototype.create_elements = function () {
52 this.element = $("<div/>");
52 this.element = $("<div/>");
53 this.collapse_button = $("<div/>");
53 this.collapse_button = $("<div/>");
54 this.prompt_overlay = $("<div/>");
54 this.prompt_overlay = $("<div/>");
55 this.wrapper.append(this.prompt_overlay);
55 this.wrapper.append(this.prompt_overlay);
56 this.wrapper.append(this.element);
56 this.wrapper.append(this.element);
57 this.wrapper.append(this.collapse_button);
57 this.wrapper.append(this.collapse_button);
58 };
58 };
59
59
60
60
61 OutputArea.prototype.style = function () {
61 OutputArea.prototype.style = function () {
62 this.collapse_button.hide();
62 this.collapse_button.hide();
63 this.prompt_overlay.hide();
63 this.prompt_overlay.hide();
64
64
65 this.wrapper.addClass('output_wrapper');
65 this.wrapper.addClass('output_wrapper');
66 this.element.addClass('output');
66 this.element.addClass('output');
67
67
68 this.collapse_button.addClass("btn output_collapsed");
68 this.collapse_button.addClass("btn output_collapsed");
69 this.collapse_button.attr('title', 'click to expand output');
69 this.collapse_button.attr('title', 'click to expand output');
70 this.collapse_button.text('. . .');
70 this.collapse_button.text('. . .');
71
71
72 this.prompt_overlay.addClass('out_prompt_overlay prompt');
72 this.prompt_overlay.addClass('out_prompt_overlay prompt');
73 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
73 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
74
74
75 this.collapse();
75 this.collapse();
76 };
76 };
77
77
78 /**
78 /**
79 * Should the OutputArea scroll?
79 * Should the OutputArea scroll?
80 * Returns whether the height (in lines) exceeds a threshold.
80 * Returns whether the height (in lines) exceeds a threshold.
81 *
81 *
82 * @private
82 * @private
83 * @method _should_scroll
83 * @method _should_scroll
84 * @param [lines=100]{Integer}
84 * @param [lines=100]{Integer}
85 * @return {Bool}
85 * @return {Bool}
86 *
86 *
87 */
87 */
88 OutputArea.prototype._should_scroll = function (lines) {
88 OutputArea.prototype._should_scroll = function (lines) {
89 if (lines <=0 ){ return }
89 if (lines <=0 ){ return }
90 if (!lines) {
90 if (!lines) {
91 lines = 100;
91 lines = 100;
92 }
92 }
93 // line-height from http://stackoverflow.com/questions/1185151
93 // line-height from http://stackoverflow.com/questions/1185151
94 var fontSize = this.element.css('font-size');
94 var fontSize = this.element.css('font-size');
95 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
95 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
96
96
97 return (this.element.height() > lines * lineHeight);
97 return (this.element.height() > lines * lineHeight);
98 };
98 };
99
99
100
100
101 OutputArea.prototype.bind_events = function () {
101 OutputArea.prototype.bind_events = function () {
102 var that = this;
102 var that = this;
103 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
103 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
104 this.prompt_overlay.click(function () { that.toggle_scroll(); });
104 this.prompt_overlay.click(function () { that.toggle_scroll(); });
105
105
106 this.element.resize(function () {
106 this.element.resize(function () {
107 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
107 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
108 if ( IPython.utils.browser[0] === "Firefox" ) {
108 if ( IPython.utils.browser[0] === "Firefox" ) {
109 return;
109 return;
110 }
110 }
111 // maybe scroll output,
111 // maybe scroll output,
112 // if it's grown large enough and hasn't already been scrolled.
112 // if it's grown large enough and hasn't already been scrolled.
113 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
113 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
114 that.scroll_area();
114 that.scroll_area();
115 }
115 }
116 });
116 });
117 this.collapse_button.click(function () {
117 this.collapse_button.click(function () {
118 that.expand();
118 that.expand();
119 });
119 });
120 };
120 };
121
121
122
122
123 OutputArea.prototype.collapse = function () {
123 OutputArea.prototype.collapse = function () {
124 if (!this.collapsed) {
124 if (!this.collapsed) {
125 this.element.hide();
125 this.element.hide();
126 this.prompt_overlay.hide();
126 this.prompt_overlay.hide();
127 if (this.element.html()){
127 if (this.element.html()){
128 this.collapse_button.show();
128 this.collapse_button.show();
129 }
129 }
130 this.collapsed = true;
130 this.collapsed = true;
131 }
131 }
132 };
132 };
133
133
134
134
135 OutputArea.prototype.expand = function () {
135 OutputArea.prototype.expand = function () {
136 if (this.collapsed) {
136 if (this.collapsed) {
137 this.collapse_button.hide();
137 this.collapse_button.hide();
138 this.element.show();
138 this.element.show();
139 this.prompt_overlay.show();
139 this.prompt_overlay.show();
140 this.collapsed = false;
140 this.collapsed = false;
141 }
141 }
142 };
142 };
143
143
144
144
145 OutputArea.prototype.toggle_output = function () {
145 OutputArea.prototype.toggle_output = function () {
146 if (this.collapsed) {
146 if (this.collapsed) {
147 this.expand();
147 this.expand();
148 } else {
148 } else {
149 this.collapse();
149 this.collapse();
150 }
150 }
151 };
151 };
152
152
153
153
154 OutputArea.prototype.scroll_area = function () {
154 OutputArea.prototype.scroll_area = function () {
155 this.element.addClass('output_scroll');
155 this.element.addClass('output_scroll');
156 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
156 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
157 this.scrolled = true;
157 this.scrolled = true;
158 };
158 };
159
159
160
160
161 OutputArea.prototype.unscroll_area = function () {
161 OutputArea.prototype.unscroll_area = function () {
162 this.element.removeClass('output_scroll');
162 this.element.removeClass('output_scroll');
163 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
163 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
164 this.scrolled = false;
164 this.scrolled = false;
165 };
165 };
166
166
167 /**
167 /**
168 *
168 *
169 * Scroll OutputArea if height supperior than a threshold (in lines).
169 * Scroll OutputArea if height supperior than a threshold (in lines).
170 *
170 *
171 * Threshold is a maximum number of lines. If unspecified, defaults to
171 * Threshold is a maximum number of lines. If unspecified, defaults to
172 * OutputArea.minimum_scroll_threshold.
172 * OutputArea.minimum_scroll_threshold.
173 *
173 *
174 * Negative threshold will prevent the OutputArea from ever scrolling.
174 * Negative threshold will prevent the OutputArea from ever scrolling.
175 *
175 *
176 * @method scroll_if_long
176 * @method scroll_if_long
177 *
177 *
178 * @param [lines=20]{Number} Default to 20 if not set,
178 * @param [lines=20]{Number} Default to 20 if not set,
179 * behavior undefined for value of `0`.
179 * behavior undefined for value of `0`.
180 *
180 *
181 **/
181 **/
182 OutputArea.prototype.scroll_if_long = function (lines) {
182 OutputArea.prototype.scroll_if_long = function (lines) {
183 var n = lines | OutputArea.minimum_scroll_threshold;
183 var n = lines | OutputArea.minimum_scroll_threshold;
184 if(n <= 0){
184 if(n <= 0){
185 return
185 return
186 }
186 }
187
187
188 if (this._should_scroll(n)) {
188 if (this._should_scroll(n)) {
189 // only allow scrolling long-enough output
189 // only allow scrolling long-enough output
190 this.scroll_area();
190 this.scroll_area();
191 }
191 }
192 };
192 };
193
193
194
194
195 OutputArea.prototype.toggle_scroll = function () {
195 OutputArea.prototype.toggle_scroll = function () {
196 if (this.scrolled) {
196 if (this.scrolled) {
197 this.unscroll_area();
197 this.unscroll_area();
198 } else {
198 } else {
199 // only allow scrolling long-enough output
199 // only allow scrolling long-enough output
200 this.scroll_if_long();
200 this.scroll_if_long();
201 }
201 }
202 };
202 };
203
203
204
204
205 // typeset with MathJax if MathJax is available
205 // typeset with MathJax if MathJax is available
206 OutputArea.prototype.typeset = function () {
206 OutputArea.prototype.typeset = function () {
207 if (window.MathJax){
207 if (window.MathJax){
208 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
208 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
209 }
209 }
210 };
210 };
211
211
212
212
213 OutputArea.prototype.handle_output = function (msg) {
213 OutputArea.prototype.handle_output = function (msg) {
214 var json = {};
214 var json = {};
215 var msg_type = json.output_type = msg.header.msg_type;
215 var msg_type = json.output_type = msg.header.msg_type;
216 var content = msg.content;
216 var content = msg.content;
217 if (msg_type === "stream") {
217 if (msg_type === "stream") {
218 json.text = content.data;
218 json.text = content.data;
219 json.stream = content.name;
219 json.stream = content.name;
220 } else if (msg_type === "display_data") {
220 } else if (msg_type === "display_data") {
221 json = content.data;
221 json = content.data;
222 json.output_type = msg_type;
222 json.output_type = msg_type;
223 json.metadata = content.metadata;
223 json.metadata = content.metadata;
224 } else if (msg_type === "pyout") {
224 } else if (msg_type === "pyout") {
225 json = content.data;
225 json = content.data;
226 json.output_type = msg_type;
226 json.output_type = msg_type;
227 json.metadata = content.metadata;
227 json.metadata = content.metadata;
228 json.prompt_number = content.execution_count;
228 json.prompt_number = content.execution_count;
229 } else if (msg_type === "pyerr") {
229 } else if (msg_type === "pyerr") {
230 json.ename = content.ename;
230 json.ename = content.ename;
231 json.evalue = content.evalue;
231 json.evalue = content.evalue;
232 json.traceback = content.traceback;
232 json.traceback = content.traceback;
233 }
233 }
234 this.append_output(json);
234 this.append_output(json);
235 };
235 };
236
236
237
237
238 OutputArea.prototype.rename_keys = function (data, key_map) {
238 OutputArea.prototype.rename_keys = function (data, key_map) {
239 var remapped = {};
239 var remapped = {};
240 for (var key in data) {
240 for (var key in data) {
241 var new_key = key_map[key] || key;
241 var new_key = key_map[key] || key;
242 remapped[new_key] = data[key];
242 remapped[new_key] = data[key];
243 }
243 }
244 return remapped;
244 return remapped;
245 };
245 };
246
246
247
247
248 OutputArea.output_types = [
248 OutputArea.output_types = [
249 'application/javascript',
249 'application/javascript',
250 'text/html',
250 'text/html',
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 (json[key] !== undefined && typeof json[key] !== 'string') {
264 if (json[key] !== undefined && typeof json[key] !== 'string') {
265 console.log("Invalid type for " + key, json[key]);
265 console.log("Invalid type for " + key, json[key]);
266 delete json[key];
266 delete json[key];
267 }
267 }
268 });
268 });
269 return json;
269 return json;
270 };
270 };
271
271
272 OutputArea.prototype.append_output = function (json) {
272 OutputArea.prototype.append_output = function (json) {
273 this.expand();
273 this.expand();
274 // Clear the output if clear is queued.
274 // Clear the output if clear is queued.
275 var needs_height_reset = false;
275 var needs_height_reset = false;
276 if (this.clear_queued) {
276 if (this.clear_queued) {
277 this.clear_output(false);
277 this.clear_output(false);
278 needs_height_reset = true;
278 needs_height_reset = true;
279 }
279 }
280
280
281 // validate output data types
281 // validate output data types
282 json = this.validate_output(json);
282 json = this.validate_output(json);
283
283
284 if (json.output_type === 'pyout') {
284 if (json.output_type === 'pyout') {
285 this.append_pyout(json);
285 this.append_pyout(json);
286 } else if (json.output_type === 'pyerr') {
286 } else if (json.output_type === 'pyerr') {
287 this.append_pyerr(json);
287 this.append_pyerr(json);
288 } else if (json.output_type === 'display_data') {
288 } else if (json.output_type === 'display_data') {
289 this.append_display_data(json);
289 this.append_display_data(json);
290 } else if (json.output_type === 'stream') {
290 } else if (json.output_type === 'stream') {
291 this.append_stream(json);
291 this.append_stream(json);
292 }
292 }
293
293
294 this.outputs.push(json);
294 this.outputs.push(json);
295
295
296 // Only reset the height to automatic if the height is currently
296 // Only reset the height to automatic if the height is currently
297 // fixed (done by wait=True flag on clear_output).
297 // fixed (done by wait=True flag on clear_output).
298 if (needs_height_reset) {
298 if (needs_height_reset) {
299 this.element.height('');
299 this.element.height('');
300 }
300 }
301
301
302 var that = this;
302 var that = this;
303 setTimeout(function(){that.element.trigger('resize');}, 100);
303 setTimeout(function(){that.element.trigger('resize');}, 100);
304 };
304 };
305
305
306
306
307 OutputArea.prototype.create_output_area = function () {
307 OutputArea.prototype.create_output_area = function () {
308 var oa = $("<div/>").addClass("output_area");
308 var oa = $("<div/>").addClass("output_area");
309 if (this.prompt_area) {
309 if (this.prompt_area) {
310 oa.append($('<div/>').addClass('prompt'));
310 oa.append($('<div/>').addClass('prompt'));
311 }
311 }
312 return oa;
312 return oa;
313 };
313 };
314
314
315
315
316 function _get_metadata_key(metadata, key, mime) {
316 function _get_metadata_key(metadata, key, mime) {
317 var mime_md = metadata[mime];
317 var mime_md = metadata[mime];
318 // mime-specific higher priority
318 // mime-specific higher priority
319 if (mime_md && mime_md[key] !== undefined) {
319 if (mime_md && mime_md[key] !== undefined) {
320 return mime_md[key];
320 return mime_md[key];
321 }
321 }
322 // fallback on global
322 // fallback on global
323 return metadata[key];
323 return metadata[key];
324 }
324 }
325
325
326 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
326 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
327 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
327 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
328 if (_get_metadata_key(md, 'isolated', mime)) {
328 if (_get_metadata_key(md, 'isolated', mime)) {
329 // Create an iframe to isolate the subarea from the rest of the
329 // Create an iframe to isolate the subarea from the rest of the
330 // document
330 // document
331 var iframe = $('<iframe/>').addClass('box-flex1');
331 var iframe = $('<iframe/>').addClass('box-flex1');
332 iframe.css({'height':1, 'width':'100%', 'display':'block'});
332 iframe.css({'height':1, 'width':'100%', 'display':'block'});
333 iframe.attr('frameborder', 0);
333 iframe.attr('frameborder', 0);
334 iframe.attr('scrolling', 'auto');
334 iframe.attr('scrolling', 'auto');
335
335
336 // Once the iframe is loaded, the subarea is dynamically inserted
336 // Once the iframe is loaded, the subarea is dynamically inserted
337 iframe.on('load', function() {
337 iframe.on('load', function() {
338 // Workaround needed by Firefox, to properly render svg inside
338 // Workaround needed by Firefox, to properly render svg inside
339 // iframes, see http://stackoverflow.com/questions/10177190/
339 // iframes, see http://stackoverflow.com/questions/10177190/
340 // svg-dynamically-added-to-iframe-does-not-render-correctly
340 // svg-dynamically-added-to-iframe-does-not-render-correctly
341 this.contentDocument.open();
341 this.contentDocument.open();
342
342
343 // Insert the subarea into the iframe
343 // Insert the subarea into the iframe
344 // We must directly write the html. When using Jquery's append
344 // We must directly write the html. When using Jquery's append
345 // method, javascript is evaluated in the parent document and
345 // method, javascript is evaluated in the parent document and
346 // not in the iframe document. At this point, subarea doesn't
346 // not in the iframe document. At this point, subarea doesn't
347 // contain any user content.
347 // contain any user content.
348 this.contentDocument.write(subarea.html());
348 this.contentDocument.write(subarea.html());
349
349
350 this.contentDocument.close();
350 this.contentDocument.close();
351
351
352 var body = this.contentDocument.body;
352 var body = this.contentDocument.body;
353 // Adjust the iframe height automatically
353 // Adjust the iframe height automatically
354 iframe.height(body.scrollHeight + 'px');
354 iframe.height(body.scrollHeight + 'px');
355 });
355 });
356
356
357 // Elements should be appended to the inner subarea and not to the
357 // Elements should be appended to the inner subarea and not to the
358 // iframe
358 // iframe
359 iframe.append = function(that) {
359 iframe.append = function(that) {
360 subarea.append(that);
360 subarea.append(that);
361 };
361 };
362
362
363 return iframe;
363 return iframe;
364 } else {
364 } else {
365 return subarea;
365 return subarea;
366 }
366 }
367 }
367 }
368
368
369
369
370 OutputArea.prototype._append_javascript_error = function (err, element) {
370 OutputArea.prototype._append_javascript_error = function (err, element) {
371 // display a message when a javascript error occurs in display output
371 // display a message when a javascript error occurs in display output
372 var msg = "Javascript error adding output!"
372 var msg = "Javascript error adding output!"
373 if ( element === undefined ) return;
373 if ( element === undefined ) return;
374 element
374 element
375 .append($('<div/>').text(msg).addClass('js-error'))
375 .append($('<div/>').text(msg).addClass('js-error'))
376 .append($('<div/>').text(err.toString()).addClass('js-error'))
376 .append($('<div/>').text(err.toString()).addClass('js-error'))
377 .append($('<div/>').text('See your browser Javascript console for more details.').addClass('js-error'));
377 .append($('<div/>').text('See your browser Javascript console for more details.').addClass('js-error'));
378 };
378 };
379
379
380 OutputArea.prototype._safe_append = function (toinsert) {
380 OutputArea.prototype._safe_append = function (toinsert) {
381 // safely append an item to the document
381 // safely append an item to the document
382 // this is an object created by user code,
382 // this is an object created by user code,
383 // and may have errors, which should not be raised
383 // and may have errors, which should not be raised
384 // under any circumstances.
384 // under any circumstances.
385 try {
385 try {
386 this.element.append(toinsert);
386 this.element.append(toinsert);
387 } catch(err) {
387 } catch(err) {
388 console.log(err);
388 console.log(err);
389 // Create an actual output_area and output_subarea, which creates
389 // Create an actual output_area and output_subarea, which creates
390 // the prompt area and the proper indentation.
390 // the prompt area and the proper indentation.
391 var toinsert = this.create_output_area();
391 var toinsert = this.create_output_area();
392 var subarea = $('<div/>').addClass('output_subarea');
392 var subarea = $('<div/>').addClass('output_subarea');
393 toinsert.append(subarea);
393 toinsert.append(subarea);
394 this._append_javascript_error(err, subarea);
394 this._append_javascript_error(err, subarea);
395 this.element.append(toinsert);
395 this.element.append(toinsert);
396 }
396 }
397 };
397 };
398
398
399
399
400 OutputArea.prototype.append_pyout = function (json) {
400 OutputArea.prototype.append_pyout = function (json) {
401 var n = json.prompt_number || ' ';
401 var n = json.prompt_number || ' ';
402 var toinsert = this.create_output_area();
402 var toinsert = this.create_output_area();
403 if (this.prompt_area) {
403 if (this.prompt_area) {
404 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
404 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
405 }
405 }
406 var inserted = this.append_mime_type(json, toinsert);
406 var inserted = this.append_mime_type(json, toinsert);
407 if (inserted) {
407 if (inserted) {
408 inserted.addClass('output_pyout');
408 inserted.addClass('output_pyout');
409 }
409 }
410 this._safe_append(toinsert);
410 this._safe_append(toinsert);
411 // If we just output latex, typeset it.
411 // If we just output latex, typeset it.
412 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
412 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
413 this.typeset();
413 this.typeset();
414 }
414 }
415 };
415 };
416
416
417
417
418 OutputArea.prototype.append_pyerr = function (json) {
418 OutputArea.prototype.append_pyerr = function (json) {
419 var tb = json.traceback;
419 var tb = json.traceback;
420 if (tb !== undefined && tb.length > 0) {
420 if (tb !== undefined && tb.length > 0) {
421 var s = '';
421 var s = '';
422 var len = tb.length;
422 var len = tb.length;
423 for (var i=0; i<len; i++) {
423 for (var i=0; i<len; i++) {
424 s = s + tb[i] + '\n';
424 s = s + tb[i] + '\n';
425 }
425 }
426 s = s + '\n';
426 s = s + '\n';
427 var toinsert = this.create_output_area();
427 var toinsert = this.create_output_area();
428 var append_text = OutputArea.append_map['text/plain'];
428 var append_text = OutputArea.append_map['text/plain'];
429 if (append_text) {
429 if (append_text) {
430 append_text.apply(this, [s, {}, toinsert]).addClass('output_pyerr');
430 append_text.apply(this, [s, {}, toinsert]).addClass('output_pyerr');
431 }
431 }
432 this._safe_append(toinsert);
432 this._safe_append(toinsert);
433 }
433 }
434 };
434 };
435
435
436
436
437 OutputArea.prototype.append_stream = function (json) {
437 OutputArea.prototype.append_stream = function (json) {
438 // temporary fix: if stream undefined (json file written prior to this patch),
438 // temporary fix: if stream undefined (json file written prior to this patch),
439 // default to most likely stdout:
439 // default to most likely stdout:
440 if (json.stream === undefined){
440 if (json.stream === undefined){
441 json.stream = 'stdout';
441 json.stream = 'stdout';
442 }
442 }
443 var text = json.text;
443 var text = json.text;
444 var subclass = "output_"+json.stream;
444 var subclass = "output_"+json.stream;
445 if (this.outputs.length > 0){
445 if (this.outputs.length > 0){
446 // have at least one output to consider
446 // have at least one output to consider
447 var last = this.outputs[this.outputs.length-1];
447 var last = this.outputs[this.outputs.length-1];
448 if (last.output_type == 'stream' && json.stream == last.stream){
448 if (last.output_type == 'stream' && json.stream == last.stream){
449 // latest output was in the same stream,
449 // latest output was in the same stream,
450 // so append directly into its pre tag
450 // so append directly into its pre tag
451 // escape ANSI & HTML specials:
451 // escape ANSI & HTML specials:
452 var pre = this.element.find('div.'+subclass).last().find('pre');
452 var pre = this.element.find('div.'+subclass).last().find('pre');
453 var html = utils.fixCarriageReturn(
453 var html = utils.fixCarriageReturn(
454 pre.html() + utils.fixConsole(text));
454 pre.html() + utils.fixConsole(text));
455 // The only user content injected with this HTML call is
455 // The only user content injected with this HTML call is
456 // escaped by the fixConsole() method.
456 // escaped by the fixConsole() method.
457 pre.html(html);
457 pre.html(html);
458 return;
458 return;
459 }
459 }
460 }
460 }
461
461
462 if (!text.replace("\r", "")) {
462 if (!text.replace("\r", "")) {
463 // text is nothing (empty string, \r, etc.)
463 // text is nothing (empty string, \r, etc.)
464 // so don't append any elements, which might add undesirable space
464 // so don't append any elements, which might add undesirable space
465 return;
465 return;
466 }
466 }
467
467
468 // If we got here, attach a new div
468 // If we got here, attach a new div
469 var toinsert = this.create_output_area();
469 var toinsert = this.create_output_area();
470 var append_text = OutputArea.append_map['text/plain'];
470 var append_text = OutputArea.append_map['text/plain'];
471 if (append_text) {
471 if (append_text) {
472 append_text.apply(this, [text, {}, toinsert]).addClass("output_stream " + subclass);
472 append_text.apply(this, [text, {}, toinsert]).addClass("output_stream " + subclass);
473 }
473 }
474 this._safe_append(toinsert);
474 this._safe_append(toinsert);
475 };
475 };
476
476
477
477
478 OutputArea.prototype.append_display_data = function (json) {
478 OutputArea.prototype.append_display_data = function (json) {
479 var toinsert = this.create_output_area();
479 var toinsert = this.create_output_area();
480 if (this.append_mime_type(json, toinsert)) {
480 if (this.append_mime_type(json, toinsert)) {
481 this._safe_append(toinsert);
481 this._safe_append(toinsert);
482 // If we just output latex, typeset it.
482 // If we just output latex, typeset it.
483 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
483 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
484 this.typeset();
484 this.typeset();
485 }
485 }
486 }
486 }
487 };
487 };
488
488
489
489
490 OutputArea.safe_outputs = {
490 OutputArea.safe_outputs = {
491 'text/plain' : true,
491 'text/plain' : true,
492 'text/latex' : true,
492 'text/latex' : true,
493 'image/png' : true,
493 'image/png' : true,
494 'image/jpeg' : true
494 'image/jpeg' : true
495 };
495 };
496
496
497 OutputArea.prototype.append_mime_type = function (json, element) {
497 OutputArea.prototype.append_mime_type = function (json, element) {
498 for (var type_i in OutputArea.display_order) {
498 for (var type_i in OutputArea.display_order) {
499 var type = OutputArea.display_order[type_i];
499 var type = OutputArea.display_order[type_i];
500 var append = OutputArea.append_map[type];
500 var append = OutputArea.append_map[type];
501 if ((json[type] !== undefined) && append) {
501 if ((json[type] !== undefined) && append) {
502 var value = json[type];
502 var value = json[type];
503 if (!this.trusted && !OutputArea.safe_outputs[type]) {
503 if (!this.trusted && !OutputArea.safe_outputs[type]) {
504 // not trusted, sanitize HTML
504 // not trusted, sanitize HTML
505 if (type==='text/html' || type==='text/svg') {
505 if (type==='text/html' || type==='text/svg') {
506 value = IPython.security.sanitize_html(value);
506 value = IPython.security.sanitize_html(value);
507 } else {
507 } else {
508 // don't display if we don't know how to sanitize it
508 // don't display if we don't know how to sanitize it
509 console.log("Ignoring untrusted " + type + " output.");
509 console.log("Ignoring untrusted " + type + " output.");
510 continue;
510 continue;
511 }
511 }
512 }
512 }
513 var md = json.metadata || {};
513 var md = json.metadata || {};
514 var toinsert = append.apply(this, [value, md, element]);
514 var toinsert = append.apply(this, [value, md, element]);
515 $([IPython.events]).trigger('output_appended.OutputArea', [type, value, md, toinsert]);
515 $([IPython.events]).trigger('output_appended.OutputArea', [type, value, md, toinsert]);
516 return toinsert;
516 return toinsert;
517 }
517 }
518 }
518 }
519 return null;
519 return null;
520 };
520 };
521
521
522
522
523 var append_html = function (html, md, element) {
523 var append_html = function (html, md, element) {
524 var type = 'text/html';
524 var type = 'text/html';
525 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
525 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
526 IPython.keyboard_manager.register_events(toinsert);
526 IPython.keyboard_manager.register_events(toinsert);
527 toinsert.append(html);
527 toinsert.append(html);
528 element.append(toinsert);
528 element.append(toinsert);
529 return toinsert;
529 return toinsert;
530 };
530 };
531
531
532
532
533 var append_javascript = function (js, md, element) {
533 var append_javascript = function (js, md, element) {
534 // We just eval the JS code, element appears in the local scope.
534 // We just eval the JS code, element appears in the local scope.
535 var type = 'application/javascript';
535 var type = 'application/javascript';
536 var toinsert = this.create_output_subarea(md, "output_javascript", type);
536 var toinsert = this.create_output_subarea(md, "output_javascript", type);
537 IPython.keyboard_manager.register_events(toinsert);
537 IPython.keyboard_manager.register_events(toinsert);
538 element.append(toinsert);
538 element.append(toinsert);
539 // FIXME TODO : remove `container element for 3.0`
539 // FIXME TODO : remove `container element for 3.0`
540 //backward compat, js should be eval'ed in a context where `container` is defined.
540 //backward compat, js should be eval'ed in a context where `container` is defined.
541 var container = element;
541 var container = element;
542 container.show = function(){console.log('Warning "container.show()" is deprecated.')};
542 container.show = function(){console.log('Warning "container.show()" is deprecated.')};
543 // end backward compat
543 // end backward compat
544
545 // Fix for ipython/issues/5293, make sure `element` is the area which
546 // output can be inserted into at the time of JS execution.
547 element = toinsert;
544 try {
548 try {
545 eval(js);
549 eval(js);
546 } catch(err) {
550 } catch(err) {
547 console.log(err);
551 console.log(err);
548 this._append_javascript_error(err, toinsert);
552 this._append_javascript_error(err, toinsert);
549 }
553 }
550 return toinsert;
554 return toinsert;
551 };
555 };
552
556
553
557
554 var append_text = function (data, md, element) {
558 var append_text = function (data, md, element) {
555 var type = 'text/plain';
559 var type = 'text/plain';
556 var toinsert = this.create_output_subarea(md, "output_text", type);
560 var toinsert = this.create_output_subarea(md, "output_text", type);
557 // escape ANSI & HTML specials in plaintext:
561 // escape ANSI & HTML specials in plaintext:
558 data = utils.fixConsole(data);
562 data = utils.fixConsole(data);
559 data = utils.fixCarriageReturn(data);
563 data = utils.fixCarriageReturn(data);
560 data = utils.autoLinkUrls(data);
564 data = utils.autoLinkUrls(data);
561 // The only user content injected with this HTML call is
565 // The only user content injected with this HTML call is
562 // escaped by the fixConsole() method.
566 // escaped by the fixConsole() method.
563 toinsert.append($("<pre/>").html(data));
567 toinsert.append($("<pre/>").html(data));
564 element.append(toinsert);
568 element.append(toinsert);
565 return toinsert;
569 return toinsert;
566 };
570 };
567
571
568
572
569 var append_svg = function (svg, md, element) {
573 var append_svg = function (svg, md, element) {
570 var type = 'image/svg+xml';
574 var type = 'image/svg+xml';
571 var toinsert = this.create_output_subarea(md, "output_svg", type);
575 var toinsert = this.create_output_subarea(md, "output_svg", type);
572 toinsert.append(svg);
576 toinsert.append(svg);
573 element.append(toinsert);
577 element.append(toinsert);
574 return toinsert;
578 return toinsert;
575 };
579 };
576
580
577
581
578 OutputArea.prototype._dblclick_to_reset_size = function (img) {
582 OutputArea.prototype._dblclick_to_reset_size = function (img) {
579 // wrap image after it's loaded on the page,
583 // wrap image after it's loaded on the page,
580 // otherwise the measured initial size will be incorrect
584 // otherwise the measured initial size will be incorrect
581 img.on("load", function (){
585 img.on("load", function (){
582 var h0 = img.height();
586 var h0 = img.height();
583 var w0 = img.width();
587 var w0 = img.width();
584 if (!(h0 && w0)) {
588 if (!(h0 && w0)) {
585 // zero size, don't make it resizable
589 // zero size, don't make it resizable
586 return;
590 return;
587 }
591 }
588 img.resizable({
592 img.resizable({
589 aspectRatio: true,
593 aspectRatio: true,
590 autoHide: true
594 autoHide: true
591 });
595 });
592 img.dblclick(function () {
596 img.dblclick(function () {
593 // resize wrapper & image together for some reason:
597 // resize wrapper & image together for some reason:
594 img.parent().height(h0);
598 img.parent().height(h0);
595 img.height(h0);
599 img.height(h0);
596 img.parent().width(w0);
600 img.parent().width(w0);
597 img.width(w0);
601 img.width(w0);
598 });
602 });
599 });
603 });
600 };
604 };
601
605
602 var set_width_height = function (img, md, mime) {
606 var set_width_height = function (img, md, mime) {
603 // set width and height of an img element from metadata
607 // set width and height of an img element from metadata
604 var height = _get_metadata_key(md, 'height', mime);
608 var height = _get_metadata_key(md, 'height', mime);
605 if (height !== undefined) img.attr('height', height);
609 if (height !== undefined) img.attr('height', height);
606 var width = _get_metadata_key(md, 'width', mime);
610 var width = _get_metadata_key(md, 'width', mime);
607 if (width !== undefined) img.attr('width', width);
611 if (width !== undefined) img.attr('width', width);
608 };
612 };
609
613
610 var append_png = function (png, md, element) {
614 var append_png = function (png, md, element) {
611 var type = 'image/png';
615 var type = 'image/png';
612 var toinsert = this.create_output_subarea(md, "output_png", type);
616 var toinsert = this.create_output_subarea(md, "output_png", type);
613 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
617 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
614 set_width_height(img, md, 'image/png');
618 set_width_height(img, md, 'image/png');
615 this._dblclick_to_reset_size(img);
619 this._dblclick_to_reset_size(img);
616 toinsert.append(img);
620 toinsert.append(img);
617 element.append(toinsert);
621 element.append(toinsert);
618 return toinsert;
622 return toinsert;
619 };
623 };
620
624
621
625
622 var append_jpeg = function (jpeg, md, element) {
626 var append_jpeg = function (jpeg, md, element) {
623 var type = 'image/jpeg';
627 var type = 'image/jpeg';
624 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
628 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
625 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
629 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
626 set_width_height(img, md, 'image/jpeg');
630 set_width_height(img, md, 'image/jpeg');
627 this._dblclick_to_reset_size(img);
631 this._dblclick_to_reset_size(img);
628 toinsert.append(img);
632 toinsert.append(img);
629 element.append(toinsert);
633 element.append(toinsert);
630 return toinsert;
634 return toinsert;
631 };
635 };
632
636
633
637
634 var append_pdf = function (pdf, md, element) {
638 var append_pdf = function (pdf, md, element) {
635 var type = 'application/pdf';
639 var type = 'application/pdf';
636 var toinsert = this.create_output_subarea(md, "output_pdf", type);
640 var toinsert = this.create_output_subarea(md, "output_pdf", type);
637 var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf);
641 var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf);
638 a.attr('target', '_blank');
642 a.attr('target', '_blank');
639 a.text('View PDF')
643 a.text('View PDF')
640 toinsert.append(a);
644 toinsert.append(a);
641 element.append(toinsert);
645 element.append(toinsert);
642 return toinsert;
646 return toinsert;
643 }
647 }
644
648
645 var append_latex = function (latex, md, element) {
649 var append_latex = function (latex, md, element) {
646 // This method cannot do the typesetting because the latex first has to
650 // This method cannot do the typesetting because the latex first has to
647 // be on the page.
651 // be on the page.
648 var type = 'text/latex';
652 var type = 'text/latex';
649 var toinsert = this.create_output_subarea(md, "output_latex", type);
653 var toinsert = this.create_output_subarea(md, "output_latex", type);
650 toinsert.append(latex);
654 toinsert.append(latex);
651 element.append(toinsert);
655 element.append(toinsert);
652 return toinsert;
656 return toinsert;
653 };
657 };
654
658
655
659
656 OutputArea.prototype.append_raw_input = function (msg) {
660 OutputArea.prototype.append_raw_input = function (msg) {
657 var that = this;
661 var that = this;
658 this.expand();
662 this.expand();
659 var content = msg.content;
663 var content = msg.content;
660 var area = this.create_output_area();
664 var area = this.create_output_area();
661
665
662 // disable any other raw_inputs, if they are left around
666 // disable any other raw_inputs, if they are left around
663 $("div.output_subarea.raw_input_container").remove();
667 $("div.output_subarea.raw_input_container").remove();
664
668
665 area.append(
669 area.append(
666 $("<div/>")
670 $("<div/>")
667 .addClass("box-flex1 output_subarea raw_input_container")
671 .addClass("box-flex1 output_subarea raw_input_container")
668 .append(
672 .append(
669 $("<span/>")
673 $("<span/>")
670 .addClass("raw_input_prompt")
674 .addClass("raw_input_prompt")
671 .text(content.prompt)
675 .text(content.prompt)
672 )
676 )
673 .append(
677 .append(
674 $("<input/>")
678 $("<input/>")
675 .addClass("raw_input")
679 .addClass("raw_input")
676 .attr('type', 'text')
680 .attr('type', 'text')
677 .attr("size", 47)
681 .attr("size", 47)
678 .keydown(function (event, ui) {
682 .keydown(function (event, ui) {
679 // make sure we submit on enter,
683 // make sure we submit on enter,
680 // and don't re-execute the *cell* on shift-enter
684 // and don't re-execute the *cell* on shift-enter
681 if (event.which === IPython.keyboard.keycodes.enter) {
685 if (event.which === IPython.keyboard.keycodes.enter) {
682 that._submit_raw_input();
686 that._submit_raw_input();
683 return false;
687 return false;
684 }
688 }
685 })
689 })
686 )
690 )
687 );
691 );
688
692
689 this.element.append(area);
693 this.element.append(area);
690 var raw_input = area.find('input.raw_input');
694 var raw_input = area.find('input.raw_input');
691 // Register events that enable/disable the keyboard manager while raw
695 // Register events that enable/disable the keyboard manager while raw
692 // input is focused.
696 // input is focused.
693 IPython.keyboard_manager.register_events(raw_input);
697 IPython.keyboard_manager.register_events(raw_input);
694 // Note, the following line used to read raw_input.focus().focus().
698 // Note, the following line used to read raw_input.focus().focus().
695 // This seemed to be needed otherwise only the cell would be focused.
699 // This seemed to be needed otherwise only the cell would be focused.
696 // But with the modal UI, this seems to work fine with one call to focus().
700 // But with the modal UI, this seems to work fine with one call to focus().
697 raw_input.focus();
701 raw_input.focus();
698 }
702 }
699
703
700 OutputArea.prototype._submit_raw_input = function (evt) {
704 OutputArea.prototype._submit_raw_input = function (evt) {
701 var container = this.element.find("div.raw_input_container");
705 var container = this.element.find("div.raw_input_container");
702 var theprompt = container.find("span.raw_input_prompt");
706 var theprompt = container.find("span.raw_input_prompt");
703 var theinput = container.find("input.raw_input");
707 var theinput = container.find("input.raw_input");
704 var value = theinput.val();
708 var value = theinput.val();
705 var content = {
709 var content = {
706 output_type : 'stream',
710 output_type : 'stream',
707 name : 'stdout',
711 name : 'stdout',
708 text : theprompt.text() + value + '\n'
712 text : theprompt.text() + value + '\n'
709 }
713 }
710 // remove form container
714 // remove form container
711 container.parent().remove();
715 container.parent().remove();
712 // replace with plaintext version in stdout
716 // replace with plaintext version in stdout
713 this.append_output(content, false);
717 this.append_output(content, false);
714 $([IPython.events]).trigger('send_input_reply.Kernel', value);
718 $([IPython.events]).trigger('send_input_reply.Kernel', value);
715 }
719 }
716
720
717
721
718 OutputArea.prototype.handle_clear_output = function (msg) {
722 OutputArea.prototype.handle_clear_output = function (msg) {
719 // msg spec v4 had stdout, stderr, display keys
723 // msg spec v4 had stdout, stderr, display keys
720 // v4.1 replaced these with just wait
724 // v4.1 replaced these with just wait
721 // The default behavior is the same (stdout=stderr=display=True, wait=False),
725 // The default behavior is the same (stdout=stderr=display=True, wait=False),
722 // so v4 messages will still be properly handled,
726 // so v4 messages will still be properly handled,
723 // except for the rarely used clearing less than all output.
727 // except for the rarely used clearing less than all output.
724 this.clear_output(msg.content.wait || false);
728 this.clear_output(msg.content.wait || false);
725 };
729 };
726
730
727
731
728 OutputArea.prototype.clear_output = function(wait) {
732 OutputArea.prototype.clear_output = function(wait) {
729 if (wait) {
733 if (wait) {
730
734
731 // If a clear is queued, clear before adding another to the queue.
735 // If a clear is queued, clear before adding another to the queue.
732 if (this.clear_queued) {
736 if (this.clear_queued) {
733 this.clear_output(false);
737 this.clear_output(false);
734 };
738 };
735
739
736 this.clear_queued = true;
740 this.clear_queued = true;
737 } else {
741 } else {
738
742
739 // Fix the output div's height if the clear_output is waiting for
743 // Fix the output div's height if the clear_output is waiting for
740 // new output (it is being used in an animation).
744 // new output (it is being used in an animation).
741 if (this.clear_queued) {
745 if (this.clear_queued) {
742 var height = this.element.height();
746 var height = this.element.height();
743 this.element.height(height);
747 this.element.height(height);
744 this.clear_queued = false;
748 this.clear_queued = false;
745 }
749 }
746
750
747 // clear all, no need for logic
751 // clear all, no need for logic
748 this.element.html("");
752 this.element.html("");
749 this.outputs = [];
753 this.outputs = [];
750 this.trusted = true;
754 this.trusted = true;
751 this.unscroll_area();
755 this.unscroll_area();
752 return;
756 return;
753 };
757 };
754 };
758 };
755
759
756
760
757 // JSON serialization
761 // JSON serialization
758
762
759 OutputArea.prototype.fromJSON = function (outputs) {
763 OutputArea.prototype.fromJSON = function (outputs) {
760 var len = outputs.length;
764 var len = outputs.length;
761 var data;
765 var data;
762
766
763 for (var i=0; i<len; i++) {
767 for (var i=0; i<len; i++) {
764 data = outputs[i];
768 data = outputs[i];
765 var msg_type = data.output_type;
769 var msg_type = data.output_type;
766 if (msg_type === "display_data" || msg_type === "pyout") {
770 if (msg_type === "display_data" || msg_type === "pyout") {
767 // convert short keys to mime keys
771 // convert short keys to mime keys
768 // TODO: remove mapping of short keys when we update to nbformat 4
772 // TODO: remove mapping of short keys when we update to nbformat 4
769 data = this.rename_keys(data, OutputArea.mime_map_r);
773 data = this.rename_keys(data, OutputArea.mime_map_r);
770 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
774 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
771 }
775 }
772
776
773 this.append_output(data);
777 this.append_output(data);
774 }
778 }
775 };
779 };
776
780
777
781
778 OutputArea.prototype.toJSON = function () {
782 OutputArea.prototype.toJSON = function () {
779 var outputs = [];
783 var outputs = [];
780 var len = this.outputs.length;
784 var len = this.outputs.length;
781 var data;
785 var data;
782 for (var i=0; i<len; i++) {
786 for (var i=0; i<len; i++) {
783 data = this.outputs[i];
787 data = this.outputs[i];
784 var msg_type = data.output_type;
788 var msg_type = data.output_type;
785 if (msg_type === "display_data" || msg_type === "pyout") {
789 if (msg_type === "display_data" || msg_type === "pyout") {
786 // convert mime keys to short keys
790 // convert mime keys to short keys
787 data = this.rename_keys(data, OutputArea.mime_map);
791 data = this.rename_keys(data, OutputArea.mime_map);
788 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
792 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
789 }
793 }
790 outputs[i] = data;
794 outputs[i] = data;
791 }
795 }
792 return outputs;
796 return outputs;
793 };
797 };
794
798
795 /**
799 /**
796 * Class properties
800 * Class properties
797 **/
801 **/
798
802
799 /**
803 /**
800 * Threshold to trigger autoscroll when the OutputArea is resized,
804 * Threshold to trigger autoscroll when the OutputArea is resized,
801 * typically when new outputs are added.
805 * typically when new outputs are added.
802 *
806 *
803 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
807 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
804 * unless it is < 0, in which case autoscroll will never be triggered
808 * unless it is < 0, in which case autoscroll will never be triggered
805 *
809 *
806 * @property auto_scroll_threshold
810 * @property auto_scroll_threshold
807 * @type Number
811 * @type Number
808 * @default 100
812 * @default 100
809 *
813 *
810 **/
814 **/
811 OutputArea.auto_scroll_threshold = 100;
815 OutputArea.auto_scroll_threshold = 100;
812
816
813 /**
817 /**
814 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
818 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
815 * shorter than this are never scrolled.
819 * shorter than this are never scrolled.
816 *
820 *
817 * @property minimum_scroll_threshold
821 * @property minimum_scroll_threshold
818 * @type Number
822 * @type Number
819 * @default 20
823 * @default 20
820 *
824 *
821 **/
825 **/
822 OutputArea.minimum_scroll_threshold = 20;
826 OutputArea.minimum_scroll_threshold = 20;
823
827
824
828
825
829
826 OutputArea.mime_map = {
830 OutputArea.mime_map = {
827 "text/plain" : "text",
831 "text/plain" : "text",
828 "text/html" : "html",
832 "text/html" : "html",
829 "image/svg+xml" : "svg",
833 "image/svg+xml" : "svg",
830 "image/png" : "png",
834 "image/png" : "png",
831 "image/jpeg" : "jpeg",
835 "image/jpeg" : "jpeg",
832 "text/latex" : "latex",
836 "text/latex" : "latex",
833 "application/json" : "json",
837 "application/json" : "json",
834 "application/javascript" : "javascript",
838 "application/javascript" : "javascript",
835 };
839 };
836
840
837 OutputArea.mime_map_r = {
841 OutputArea.mime_map_r = {
838 "text" : "text/plain",
842 "text" : "text/plain",
839 "html" : "text/html",
843 "html" : "text/html",
840 "svg" : "image/svg+xml",
844 "svg" : "image/svg+xml",
841 "png" : "image/png",
845 "png" : "image/png",
842 "jpeg" : "image/jpeg",
846 "jpeg" : "image/jpeg",
843 "latex" : "text/latex",
847 "latex" : "text/latex",
844 "json" : "application/json",
848 "json" : "application/json",
845 "javascript" : "application/javascript",
849 "javascript" : "application/javascript",
846 };
850 };
847
851
848 OutputArea.display_order = [
852 OutputArea.display_order = [
849 'application/javascript',
853 'application/javascript',
850 'text/html',
854 'text/html',
851 'text/latex',
855 'text/latex',
852 'image/svg+xml',
856 'image/svg+xml',
853 'image/png',
857 'image/png',
854 'image/jpeg',
858 'image/jpeg',
855 'application/pdf',
859 'application/pdf',
856 'text/plain'
860 'text/plain'
857 ];
861 ];
858
862
859 OutputArea.append_map = {
863 OutputArea.append_map = {
860 "text/plain" : append_text,
864 "text/plain" : append_text,
861 "text/html" : append_html,
865 "text/html" : append_html,
862 "image/svg+xml" : append_svg,
866 "image/svg+xml" : append_svg,
863 "image/png" : append_png,
867 "image/png" : append_png,
864 "image/jpeg" : append_jpeg,
868 "image/jpeg" : append_jpeg,
865 "text/latex" : append_latex,
869 "text/latex" : append_latex,
866 "application/javascript" : append_javascript,
870 "application/javascript" : append_javascript,
867 "application/pdf" : append_pdf
871 "application/pdf" : append_pdf
868 };
872 };
869
873
870 IPython.OutputArea = OutputArea;
874 IPython.OutputArea = OutputArea;
871
875
872 return IPython;
876 return IPython;
873
877
874 }(IPython));
878 }(IPython));
@@ -1,391 +1,387 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7 //============================================================================
7 //============================================================================
8 // Tooltip
8 // Tooltip
9 //============================================================================
9 //============================================================================
10 //
10 //
11 // you can set the autocall time by setting `IPython.tooltip.time_before_tooltip` in ms
11 // you can set the autocall time by setting `IPython.tooltip.time_before_tooltip` in ms
12 //
12 //
13 // you can configure the differents action of pressing tab several times in a row by
13 // you can configure the differents action of pressing tab several times in a row by
14 // setting/appending different fonction in the array
14 // setting/appending different fonction in the array
15 // IPython.tooltip.tabs_functions
15 // IPython.tooltip.tabs_functions
16 //
16 //
17 // eg :
17 // eg :
18 // IPython.tooltip.tabs_functions[4] = function (){console.log('this is the action of the 4th tab pressing')}
18 // IPython.tooltip.tabs_functions[4] = function (){console.log('this is the action of the 4th tab pressing')}
19 //
19 //
20 var IPython = (function (IPython) {
20 var IPython = (function (IPython) {
21 "use strict";
21 "use strict";
22
22
23 var utils = IPython.utils;
23 var utils = IPython.utils;
24
24
25 // tooltip constructor
25 // tooltip constructor
26 var Tooltip = function () {
26 var Tooltip = function () {
27 var that = this;
27 var that = this;
28 this.time_before_tooltip = 1200;
28 this.time_before_tooltip = 1200;
29
29
30 // handle to html
30 // handle to html
31 this.tooltip = $('#tooltip');
31 this.tooltip = $('#tooltip');
32 this._hidden = true;
32 this._hidden = true;
33
33
34 // variable for consecutive call
34 // variable for consecutive call
35 this._old_cell = null;
35 this._old_cell = null;
36 this._old_request = null;
36 this._old_request = null;
37 this._consecutive_counter = 0;
37 this._consecutive_counter = 0;
38
38
39 // 'sticky ?'
39 // 'sticky ?'
40 this._sticky = false;
40 this._sticky = false;
41
41
42 // display tooltip if the docstring is empty?
42 // display tooltip if the docstring is empty?
43 this._hide_if_no_docstring = false;
43 this._hide_if_no_docstring = false;
44
44
45 // contain the button in the upper right corner
45 // contain the button in the upper right corner
46 this.buttons = $('<div/>').addClass('tooltipbuttons');
46 this.buttons = $('<div/>').addClass('tooltipbuttons');
47
47
48 // will contain the docstring
48 // will contain the docstring
49 this.text = $('<div/>').addClass('tooltiptext').addClass('smalltooltip');
49 this.text = $('<div/>').addClass('tooltiptext').addClass('smalltooltip');
50
50
51 // build the buttons menu on the upper right
51 // build the buttons menu on the upper right
52 // expand the tooltip to see more
52 // expand the tooltip to see more
53 var expandlink = $('<a/>').attr('href', "#").addClass("ui-corner-all") //rounded corner
53 var expandlink = $('<a/>').attr('href', "#").addClass("ui-corner-all") //rounded corner
54 .attr('role', "button").attr('id', 'expanbutton').attr('title', 'Grow the tooltip vertically (press tab 2 times)').click(function () {
54 .attr('role', "button").attr('id', 'expanbutton').attr('title', 'Grow the tooltip vertically (press tab 2 times)').click(function () {
55 that.expand();
55 that.expand();
56 }).append(
56 }).append(
57 $('<span/>').text('Expand').addClass('ui-icon').addClass('ui-icon-plus'));
57 $('<span/>').text('Expand').addClass('ui-icon').addClass('ui-icon-plus'));
58
58
59 // open in pager
59 // open in pager
60 var morelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button').attr('title', 'show the current docstring in pager (press tab 4 times)');
60 var morelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button').attr('title', 'show the current docstring in pager (press tab 4 times)');
61 var morespan = $('<span/>').text('Open in Pager').addClass('ui-icon').addClass('ui-icon-arrowstop-l-n');
61 var morespan = $('<span/>').text('Open in Pager').addClass('ui-icon').addClass('ui-icon-arrowstop-l-n');
62 morelink.append(morespan);
62 morelink.append(morespan);
63 morelink.click(function () {
63 morelink.click(function () {
64 that.showInPager(that._old_cell);
64 that.showInPager(that._old_cell);
65 });
65 });
66
66
67 // close the tooltip
67 // close the tooltip
68 var closelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button');
68 var closelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button');
69 var closespan = $('<span/>').text('Close').addClass('ui-icon').addClass('ui-icon-close');
69 var closespan = $('<span/>').text('Close').addClass('ui-icon').addClass('ui-icon-close');
70 closelink.append(closespan);
70 closelink.append(closespan);
71 closelink.click(function () {
71 closelink.click(function () {
72 that.remove_and_cancel_tooltip(true);
72 that.remove_and_cancel_tooltip(true);
73 });
73 });
74
74
75 this._clocklink = $('<a/>').attr('href', "#");
75 this._clocklink = $('<a/>').attr('href', "#");
76 this._clocklink.attr('role', "button");
76 this._clocklink.attr('role', "button");
77 this._clocklink.addClass('ui-button');
77 this._clocklink.addClass('ui-button');
78 this._clocklink.attr('title', 'Tootip is not dismissed while typing for 10 seconds');
78 this._clocklink.attr('title', 'Tootip is not dismissed while typing for 10 seconds');
79 var clockspan = $('<span/>').text('Close');
79 var clockspan = $('<span/>').text('Close');
80 clockspan.addClass('ui-icon');
80 clockspan.addClass('ui-icon');
81 clockspan.addClass('ui-icon-clock');
81 clockspan.addClass('ui-icon-clock');
82 this._clocklink.append(clockspan);
82 this._clocklink.append(clockspan);
83 this._clocklink.click(function () {
83 this._clocklink.click(function () {
84 that.cancel_stick();
84 that.cancel_stick();
85 });
85 });
86
86
87
87
88
88
89
89
90 //construct the tooltip
90 //construct the tooltip
91 // add in the reverse order you want them to appear
91 // add in the reverse order you want them to appear
92 this.buttons.append(closelink);
92 this.buttons.append(closelink);
93 this.buttons.append(expandlink);
93 this.buttons.append(expandlink);
94 this.buttons.append(morelink);
94 this.buttons.append(morelink);
95 this.buttons.append(this._clocklink);
95 this.buttons.append(this._clocklink);
96 this._clocklink.hide();
96 this._clocklink.hide();
97
97
98
98
99 // we need a phony element to make the small arrow
99 // we need a phony element to make the small arrow
100 // of the tooltip in css
100 // of the tooltip in css
101 // we will move the arrow later
101 // we will move the arrow later
102 this.arrow = $('<div/>').addClass('pretooltiparrow');
102 this.arrow = $('<div/>').addClass('pretooltiparrow');
103 this.tooltip.append(this.buttons);
103 this.tooltip.append(this.buttons);
104 this.tooltip.append(this.arrow);
104 this.tooltip.append(this.arrow);
105 this.tooltip.append(this.text);
105 this.tooltip.append(this.text);
106
106
107 // function that will be called if you press tab 1, 2, 3... times in a row
107 // function that will be called if you press tab 1, 2, 3... times in a row
108 this.tabs_functions = [function (cell, text) {
108 this.tabs_functions = [function (cell, text) {
109 that._request_tooltip(cell, text);
109 that._request_tooltip(cell, text);
110 }, function () {
110 }, function () {
111 that.expand();
111 that.expand();
112 }, function () {
112 }, function () {
113 that.stick();
113 that.stick();
114 }, function (cell) {
114 }, function (cell) {
115 that.cancel_stick();
115 that.cancel_stick();
116 that.showInPager(cell);
116 that.showInPager(cell);
117 }];
117 }];
118 // call after all the tabs function above have bee call to clean their effects
118 // call after all the tabs function above have bee call to clean their effects
119 // if necessary
119 // if necessary
120 this.reset_tabs_function = function (cell, text) {
120 this.reset_tabs_function = function (cell, text) {
121 this._old_cell = (cell) ? cell : null;
121 this._old_cell = (cell) ? cell : null;
122 this._old_request = (text) ? text : null;
122 this._old_request = (text) ? text : null;
123 this._consecutive_counter = 0;
123 this._consecutive_counter = 0;
124 };
124 };
125 };
125 };
126
126
127 Tooltip.prototype.is_visible = function () {
127 Tooltip.prototype.is_visible = function () {
128 return !this._hidden;
128 return !this._hidden;
129 };
129 };
130
130
131 Tooltip.prototype.showInPager = function (cell) {
131 Tooltip.prototype.showInPager = function (cell) {
132 // reexecute last call in pager by appending ? to show back in pager
132 // reexecute last call in pager by appending ? to show back in pager
133 var that = this;
133 var that = this;
134 var empty = function () {};
134 var callbacks = {'shell' : {
135 cell.kernel.execute(
135 'payload' : {
136 that.name + '?', {
136 'page' : $.proxy(cell._open_with_pager, cell)
137 'execute_reply': empty,
137 }
138 'output': empty,
138 }
139 'clear_output': empty,
139 };
140 'cell': cell
140 cell.kernel.execute(that.name + '?', callbacks, {'silent': false, 'store_history': true});
141 }, {
142 'silent': false,
143 'store_history': true
144 });
145 this.remove_and_cancel_tooltip();
141 this.remove_and_cancel_tooltip();
146 };
142 };
147
143
148 // grow the tooltip verticaly
144 // grow the tooltip verticaly
149 Tooltip.prototype.expand = function () {
145 Tooltip.prototype.expand = function () {
150 this.text.removeClass('smalltooltip');
146 this.text.removeClass('smalltooltip');
151 this.text.addClass('bigtooltip');
147 this.text.addClass('bigtooltip');
152 $('#expanbutton').hide('slow');
148 $('#expanbutton').hide('slow');
153 };
149 };
154
150
155 // deal with all the logic of hiding the tooltip
151 // deal with all the logic of hiding the tooltip
156 // and reset it's status
152 // and reset it's status
157 Tooltip.prototype._hide = function () {
153 Tooltip.prototype._hide = function () {
158 this._hidden = true;
154 this._hidden = true;
159 this.tooltip.fadeOut('fast');
155 this.tooltip.fadeOut('fast');
160 $('#expanbutton').show('slow');
156 $('#expanbutton').show('slow');
161 this.text.removeClass('bigtooltip');
157 this.text.removeClass('bigtooltip');
162 this.text.addClass('smalltooltip');
158 this.text.addClass('smalltooltip');
163 // keep scroll top to be sure to always see the first line
159 // keep scroll top to be sure to always see the first line
164 this.text.scrollTop(0);
160 this.text.scrollTop(0);
165 this.code_mirror = null;
161 this.code_mirror = null;
166 };
162 };
167
163
168 // return true on successfully removing a visible tooltip; otherwise return
164 // return true on successfully removing a visible tooltip; otherwise return
169 // false.
165 // false.
170 Tooltip.prototype.remove_and_cancel_tooltip = function (force) {
166 Tooltip.prototype.remove_and_cancel_tooltip = function (force) {
171 // note that we don't handle closing directly inside the calltip
167 // note that we don't handle closing directly inside the calltip
172 // as in the completer, because it is not focusable, so won't
168 // as in the completer, because it is not focusable, so won't
173 // get the event.
169 // get the event.
174 this.cancel_pending();
170 this.cancel_pending();
175 if (!this._hidden) {
171 if (!this._hidden) {
176 if (force || !this._sticky) {
172 if (force || !this._sticky) {
177 this.cancel_stick();
173 this.cancel_stick();
178 this._hide();
174 this._hide();
179 }
175 }
180 this.reset_tabs_function();
176 this.reset_tabs_function();
181 return true;
177 return true;
182 } else {
178 } else {
183 return false;
179 return false;
184 }
180 }
185 };
181 };
186
182
187 // cancel autocall done after '(' for example.
183 // cancel autocall done after '(' for example.
188 Tooltip.prototype.cancel_pending = function () {
184 Tooltip.prototype.cancel_pending = function () {
189 if (this._tooltip_timeout !== null) {
185 if (this._tooltip_timeout !== null) {
190 clearTimeout(this._tooltip_timeout);
186 clearTimeout(this._tooltip_timeout);
191 this._tooltip_timeout = null;
187 this._tooltip_timeout = null;
192 }
188 }
193 };
189 };
194
190
195 // will trigger tooltip after timeout
191 // will trigger tooltip after timeout
196 Tooltip.prototype.pending = function (cell, hide_if_no_docstring) {
192 Tooltip.prototype.pending = function (cell, hide_if_no_docstring) {
197 var that = this;
193 var that = this;
198 this._tooltip_timeout = setTimeout(function () {
194 this._tooltip_timeout = setTimeout(function () {
199 that.request(cell, hide_if_no_docstring);
195 that.request(cell, hide_if_no_docstring);
200 }, that.time_before_tooltip);
196 }, that.time_before_tooltip);
201 };
197 };
202
198
203 // easy access for julia monkey patching.
199 // easy access for julia monkey patching.
204 Tooltip.last_token_re = /[a-z_][0-9a-z._]*$/gi;
200 Tooltip.last_token_re = /[a-z_][0-9a-z._]*$/gi;
205
201
206 Tooltip.prototype.extract_oir_token = function(line){
202 Tooltip.prototype.extract_oir_token = function(line){
207 // use internally just to make the request to the kernel
203 // use internally just to make the request to the kernel
208 // Feel free to shorten this logic if you are better
204 // Feel free to shorten this logic if you are better
209 // than me in regEx
205 // than me in regEx
210 // basicaly you shoul be able to get xxx.xxx.xxx from
206 // basicaly you shoul be able to get xxx.xxx.xxx from
211 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
207 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
212 // remove everything between matchin bracket (need to iterate)
208 // remove everything between matchin bracket (need to iterate)
213 var matchBracket = /\([^\(\)]+\)/g;
209 var matchBracket = /\([^\(\)]+\)/g;
214 var endBracket = /\([^\(]*$/g;
210 var endBracket = /\([^\(]*$/g;
215 var oldline = line;
211 var oldline = line;
216
212
217 line = line.replace(matchBracket, "");
213 line = line.replace(matchBracket, "");
218 while (oldline != line) {
214 while (oldline != line) {
219 oldline = line;
215 oldline = line;
220 line = line.replace(matchBracket, "");
216 line = line.replace(matchBracket, "");
221 }
217 }
222 // remove everything after last open bracket
218 // remove everything after last open bracket
223 line = line.replace(endBracket, "");
219 line = line.replace(endBracket, "");
224 // reset the regex object
220 // reset the regex object
225 Tooltip.last_token_re.lastIndex = 0;
221 Tooltip.last_token_re.lastIndex = 0;
226 return Tooltip.last_token_re.exec(line);
222 return Tooltip.last_token_re.exec(line);
227 };
223 };
228
224
229 Tooltip.prototype._request_tooltip = function (cell, line) {
225 Tooltip.prototype._request_tooltip = function (cell, line) {
230 var callbacks = $.proxy(this._show, this);
226 var callbacks = $.proxy(this._show, this);
231 var oir_token = this.extract_oir_token(line);
227 var oir_token = this.extract_oir_token(line);
232 var msg_id = cell.kernel.object_info(oir_token, callbacks);
228 var msg_id = cell.kernel.object_info(oir_token, callbacks);
233 };
229 };
234
230
235 // make an imediate completion request
231 // make an imediate completion request
236 Tooltip.prototype.request = function (cell, hide_if_no_docstring) {
232 Tooltip.prototype.request = function (cell, hide_if_no_docstring) {
237 // request(codecell)
233 // request(codecell)
238 // Deal with extracting the text from the cell and counting
234 // Deal with extracting the text from the cell and counting
239 // call in a row
235 // call in a row
240 this.cancel_pending();
236 this.cancel_pending();
241 var editor = cell.code_mirror;
237 var editor = cell.code_mirror;
242 var cursor = editor.getCursor();
238 var cursor = editor.getCursor();
243 var text = editor.getRange({
239 var text = editor.getRange({
244 line: cursor.line,
240 line: cursor.line,
245 ch: 0
241 ch: 0
246 }, cursor).trim();
242 }, cursor).trim();
247
243
248 this._hide_if_no_docstring = hide_if_no_docstring;
244 this._hide_if_no_docstring = hide_if_no_docstring;
249
245
250 if(editor.somethingSelected()){
246 if(editor.somethingSelected()){
251 text = editor.getSelection();
247 text = editor.getSelection();
252 }
248 }
253
249
254 // need a permanent handel to code_mirror for future auto recall
250 // need a permanent handel to code_mirror for future auto recall
255 this.code_mirror = editor;
251 this.code_mirror = editor;
256
252
257 // now we treat the different number of keypress
253 // now we treat the different number of keypress
258 // first if same cell, same text, increment counter by 1
254 // first if same cell, same text, increment counter by 1
259 if (this._old_cell == cell && this._old_request == text && this._hidden === false) {
255 if (this._old_cell == cell && this._old_request == text && this._hidden === false) {
260 this._consecutive_counter++;
256 this._consecutive_counter++;
261 } else {
257 } else {
262 // else reset
258 // else reset
263 this.cancel_stick();
259 this.cancel_stick();
264 this.reset_tabs_function (cell, text);
260 this.reset_tabs_function (cell, text);
265 }
261 }
266
262
267 // don't do anything if line beggin with '(' or is empty
263 // don't do anything if line beggin with '(' or is empty
268 if (text === "" || text === "(") {
264 if (text === "" || text === "(") {
269 return;
265 return;
270 }
266 }
271
267
272 this.tabs_functions[this._consecutive_counter](cell, text);
268 this.tabs_functions[this._consecutive_counter](cell, text);
273
269
274 // then if we are at the end of list function, reset
270 // then if we are at the end of list function, reset
275 if (this._consecutive_counter == this.tabs_functions.length) {
271 if (this._consecutive_counter == this.tabs_functions.length) {
276 this.reset_tabs_function (cell, text);
272 this.reset_tabs_function (cell, text);
277 }
273 }
278
274
279 return;
275 return;
280 };
276 };
281
277
282 // cancel the option of having the tooltip to stick
278 // cancel the option of having the tooltip to stick
283 Tooltip.prototype.cancel_stick = function () {
279 Tooltip.prototype.cancel_stick = function () {
284 clearTimeout(this._stick_timeout);
280 clearTimeout(this._stick_timeout);
285 this._stick_timeout = null;
281 this._stick_timeout = null;
286 this._clocklink.hide('slow');
282 this._clocklink.hide('slow');
287 this._sticky = false;
283 this._sticky = false;
288 };
284 };
289
285
290 // put the tooltip in a sicky state for 10 seconds
286 // put the tooltip in a sicky state for 10 seconds
291 // it won't be removed by remove_and_cancell() unless you called with
287 // it won't be removed by remove_and_cancell() unless you called with
292 // the first parameter set to true.
288 // the first parameter set to true.
293 // remove_and_cancell_tooltip(true)
289 // remove_and_cancell_tooltip(true)
294 Tooltip.prototype.stick = function (time) {
290 Tooltip.prototype.stick = function (time) {
295 time = (time !== undefined) ? time : 10;
291 time = (time !== undefined) ? time : 10;
296 var that = this;
292 var that = this;
297 this._sticky = true;
293 this._sticky = true;
298 this._clocklink.show('slow');
294 this._clocklink.show('slow');
299 this._stick_timeout = setTimeout(function () {
295 this._stick_timeout = setTimeout(function () {
300 that._sticky = false;
296 that._sticky = false;
301 that._clocklink.hide('slow');
297 that._clocklink.hide('slow');
302 }, time * 1000);
298 }, time * 1000);
303 };
299 };
304
300
305 // should be called with the kernel reply to actually show the tooltip
301 // should be called with the kernel reply to actually show the tooltip
306 Tooltip.prototype._show = function (reply) {
302 Tooltip.prototype._show = function (reply) {
307 // move the bubble if it is not hidden
303 // move the bubble if it is not hidden
308 // otherwise fade it
304 // otherwise fade it
309 var content = reply.content;
305 var content = reply.content;
310 if (!content.found) {
306 if (!content.found) {
311 // object not found, nothing to show
307 // object not found, nothing to show
312 return;
308 return;
313 }
309 }
314 this.name = content.name;
310 this.name = content.name;
315
311
316 // do some math to have the tooltip arrow on more or less on left or right
312 // do some math to have the tooltip arrow on more or less on left or right
317 // width of the editor
313 // width of the editor
318 var w = $(this.code_mirror.getScrollerElement()).width();
314 var w = $(this.code_mirror.getScrollerElement()).width();
319 // ofset of the editor
315 // ofset of the editor
320 var o = $(this.code_mirror.getScrollerElement()).offset();
316 var o = $(this.code_mirror.getScrollerElement()).offset();
321
317
322 // whatever anchor/head order but arrow at mid x selection
318 // whatever anchor/head order but arrow at mid x selection
323 var anchor = this.code_mirror.cursorCoords(false);
319 var anchor = this.code_mirror.cursorCoords(false);
324 var head = this.code_mirror.cursorCoords(true);
320 var head = this.code_mirror.cursorCoords(true);
325 var xinit = (head.left+anchor.left)/2;
321 var xinit = (head.left+anchor.left)/2;
326 var xinter = o.left + (xinit - o.left) / w * (w - 450);
322 var xinter = o.left + (xinit - o.left) / w * (w - 450);
327 var posarrowleft = xinit - xinter;
323 var posarrowleft = xinit - xinter;
328
324
329 if (this._hidden === false) {
325 if (this._hidden === false) {
330 this.tooltip.animate({
326 this.tooltip.animate({
331 'left': xinter - 30 + 'px',
327 'left': xinter - 30 + 'px',
332 'top': (head.bottom + 10) + 'px'
328 'top': (head.bottom + 10) + 'px'
333 });
329 });
334 } else {
330 } else {
335 this.tooltip.css({
331 this.tooltip.css({
336 'left': xinter - 30 + 'px'
332 'left': xinter - 30 + 'px'
337 });
333 });
338 this.tooltip.css({
334 this.tooltip.css({
339 'top': (head.bottom + 10) + 'px'
335 'top': (head.bottom + 10) + 'px'
340 });
336 });
341 }
337 }
342 this.arrow.animate({
338 this.arrow.animate({
343 'left': posarrowleft + 'px'
339 'left': posarrowleft + 'px'
344 });
340 });
345
341
346 // build docstring
342 // build docstring
347 var defstring = content.call_def;
343 var defstring = content.call_def;
348 if (!defstring) {
344 if (!defstring) {
349 defstring = content.init_definition;
345 defstring = content.init_definition;
350 }
346 }
351 if (!defstring) {
347 if (!defstring) {
352 defstring = content.definition;
348 defstring = content.definition;
353 }
349 }
354
350
355 var docstring = content.call_docstring;
351 var docstring = content.call_docstring;
356 if (!docstring) {
352 if (!docstring) {
357 docstring = content.init_docstring;
353 docstring = content.init_docstring;
358 }
354 }
359 if (!docstring) {
355 if (!docstring) {
360 docstring = content.docstring;
356 docstring = content.docstring;
361 }
357 }
362
358
363 if (!docstring) {
359 if (!docstring) {
364 // For reals this time, no docstring
360 // For reals this time, no docstring
365 if (this._hide_if_no_docstring) {
361 if (this._hide_if_no_docstring) {
366 return;
362 return;
367 } else {
363 } else {
368 docstring = "<empty docstring>";
364 docstring = "<empty docstring>";
369 }
365 }
370 }
366 }
371
367
372 this._hidden = false;
368 this._hidden = false;
373 this.tooltip.fadeIn('fast');
369 this.tooltip.fadeIn('fast');
374 this.text.children().remove();
370 this.text.children().remove();
375
371
376 // Any HTML within the docstring is escaped by the fixConsole() method.
372 // Any HTML within the docstring is escaped by the fixConsole() method.
377 var pre = $('<pre/>').html(utils.fixConsole(docstring));
373 var pre = $('<pre/>').html(utils.fixConsole(docstring));
378 if (defstring) {
374 if (defstring) {
379 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
375 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
380 this.text.append(defstring_html);
376 this.text.append(defstring_html);
381 }
377 }
382 this.text.append(pre);
378 this.text.append(pre);
383 // keep scroll top to be sure to always see the first line
379 // keep scroll top to be sure to always see the first line
384 this.text.scrollTop(0);
380 this.text.scrollTop(0);
385 };
381 };
386
382
387 IPython.Tooltip = Tooltip;
383 IPython.Tooltip = Tooltip;
388
384
389 return IPython;
385 return IPython;
390
386
391 }(IPython));
387 }(IPython));
@@ -1,54 +1,62 b''
1 div.cell {
1 div.cell {
2 border: 1px solid transparent;
2 border: 1px solid transparent;
3 .vbox();
3 .vbox();
4
4
5 &.selected {
5 &.selected {
6 .corner-all;
6 .corner-all;
7 border : thin @border_color solid;
7 border : thin @border_color solid;
8 }
8 }
9
9
10 &.edit_mode {
10 &.edit_mode {
11 .corner-all;
11 .corner-all;
12 border : thin green solid;
12 border : thin green solid;
13 }
13 }
14 }
14 }
15
15
16 div.cell {
16 div.cell {
17 width: 100%;
17 width: 100%;
18 padding: 5px 5px 5px 0px;
18 padding: 5px 5px 5px 0px;
19 /* This acts as a spacer between cells, that is outside the border */
19 /* This acts as a spacer between cells, that is outside the border */
20 margin: 0px;
20 margin: 0px;
21 outline: none;
21 outline: none;
22 }
22 }
23
23
24 div.prompt {
24 div.prompt {
25 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
25 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
26 min-width: 11ex;
26 min-width: 11ex;
27 /* This padding is tuned to match the padding on the CodeMirror editor. */
27 /* This padding is tuned to match the padding on the CodeMirror editor. */
28 padding: @code_padding;
28 padding: @code_padding;
29 margin: 0px;
29 margin: 0px;
30 font-family: @monoFontFamily;
30 font-family: @monoFontFamily;
31 text-align: right;
31 text-align: right;
32 /* This has to match that of the the CodeMirror class line-height below */
32 /* This has to match that of the the CodeMirror class line-height below */
33 line-height: @code_line_height;
33 line-height: @code_line_height;
34 }
34 }
35
35
36 @media (max-width: 480px) {
37 // prompts are in the main column on small screens,
38 // so text should be left-aligned
39 div.prompt {
40 text-align: left;
41 }
42 }
43
36 div.inner_cell {
44 div.inner_cell {
37 .vbox();
45 .vbox();
38 .box-flex1();
46 .box-flex1();
39 }
47 }
40
48
41 /* input_area and input_prompt must match in top border and margin for alignment */
49 /* input_area and input_prompt must match in top border and margin for alignment */
42 div.input_area {
50 div.input_area {
43 border: 1px solid @light_border_color;
51 border: 1px solid @light_border_color;
44 .corner-all;
52 .corner-all;
45 background: @cell_background;
53 background: @cell_background;
46 }
54 }
47
55
48 /* This is needed so that empty prompt areas can collapse to zero height when there
56 /* This is needed so that empty prompt areas can collapse to zero height when there
49 is no content in the output_subarea and the prompt. The main purpose of this is
57 is no content in the output_subarea and the prompt. The main purpose of this is
50 to make sure that empty JavaScript output_subareas have no height. */
58 to make sure that empty JavaScript output_subareas have no height. */
51 div.prompt:empty {
59 div.prompt:empty {
52 padding-top: 0;
60 padding-top: 0;
53 padding-bottom: 0;
61 padding-bottom: 0;
54 }
62 }
@@ -1,40 +1,46 b''
1 div.code_cell {
1 div.code_cell {
2 }
2 }
3
3
4 /* any special styling for code cells that are currently running goes here */
4 /* any special styling for code cells that are currently running goes here */
5 div.code_cell.running {
5 div.code_cell.running {
6 }
6 }
7
7
8 div.input {
8 div.input {
9 page-break-inside: avoid;
9 page-break-inside: avoid;
10 .hbox();
10 .hbox();
11 }
11 }
12
12
13 @media (max-width: 480px) {
14 // move prompts above code on small screens
15 div.input {
16 .vbox();
17 }
18 }
19
13 /* input_area and input_prompt must match in top border and margin for alignment */
20 /* input_area and input_prompt must match in top border and margin for alignment */
14 div.input_prompt {
21 div.input_prompt {
15 color: navy;
22 color: navy;
16 border-top: 1px solid transparent;
23 border-top: 1px solid transparent;
17 }
24 }
18
25
19
20 // The styles related to div.highlight are for nbconvert HTML output only. This works
26 // The styles related to div.highlight are for nbconvert HTML output only. This works
21 // because the .highlight div isn't present in the live notebook. We could put this into
27 // because the .highlight div isn't present in the live notebook. We could put this into
22 // nbconvert, but it easily falls out of sync, can't use our less variables and doesn't
28 // nbconvert, but it easily falls out of sync, can't use our less variables and doesn't
23 // help the basic template when paired with our CSS.
29 // help the basic template when paired with our CSS.
24
30
25 div.input_area > div.highlight {
31 div.input_area > div.highlight {
26 margin: @code_padding;
32 margin: @code_padding;
27 border: none;
33 border: none;
28 padding: 0px;
34 padding: 0px;
29 background-color: transparent;
35 background-color: transparent;
30 }
36 }
31
37
32 div.input_area > div.highlight > pre {
38 div.input_area > div.highlight > pre {
33 margin: 0px;
39 margin: 0px;
34 border: 0px;
40 border: 0px;
35 padding: 0px;
41 padding: 0px;
36 background-color: transparent;
42 background-color: transparent;
37 font-size: @notebook_font_size;
43 font-size: @notebook_font_size;
38 line-height: @code_line_height;
44 line-height: @code_line_height;
39 }
45 }
40
46
@@ -1,69 +1,77 b''
1
1
2 body {
2 body {
3 background-color: @bodyBackground;
3 background-color: @bodyBackground;
4 }
4 }
5
5
6 body.notebook_app {
6 body.notebook_app {
7 overflow: hidden;
7 overflow: hidden;
8 }
8 }
9
9
10 @media (max-width: 767px) {
11 // remove bootstrap-responsive's body padding on small screens
12 body.notebook_app {
13 padding-left: 0px;
14 padding-right: 0px;
15 }
16 }
17
10 span#notebook_name {
18 span#notebook_name {
11 height: 1em;
19 height: 1em;
12 line-height: 1em;
20 line-height: 1em;
13 padding: 3px;
21 padding: 3px;
14 border: none;
22 border: none;
15 font-size: 146.5%;
23 font-size: 146.5%;
16 }
24 }
17
25
18 div#notebook_panel {
26 div#notebook_panel {
19 margin: 0px 0px 0px 0px;
27 margin: 0px 0px 0px 0px;
20 padding: 0px;
28 padding: 0px;
21 .box-shadow(0 -1px 10px rgba(0,0,0,.1));
29 .box-shadow(0 -1px 10px rgba(0,0,0,.1));
22 }
30 }
23 div#notebook {
31 div#notebook {
24 font-size: @notebook_font_size;
32 font-size: @notebook_font_size;
25 line-height: @notebook_line_height;
33 line-height: @notebook_line_height;
26 overflow-y: scroll;
34 overflow-y: scroll;
27 overflow-x: auto;
35 overflow-x: auto;
28 width: 100%;
36 width: 100%;
29 /* This spaces the cell away from the edge of the notebook area */
37 /* This spaces the cell away from the edge of the notebook area */
30 padding: 1em 0 1em 0;
38 padding: 1em 0 1em 0;
31 margin: 0px;
39 margin: 0px;
32 border-top: 1px solid @border_color;
40 border-top: 1px solid @border_color;
33 outline: none;
41 outline: none;
34 .border-box-sizing();
42 .border-box-sizing();
35 }
43 }
36
44
37 div.ui-widget-content {
45 div.ui-widget-content {
38 border: 1px solid @border_color;
46 border: 1px solid @border_color;
39 outline: none;
47 outline: none;
40 }
48 }
41
49
42 pre.dialog {
50 pre.dialog {
43 background-color: @cell_background;
51 background-color: @cell_background;
44 border: 1px solid #ddd;
52 border: 1px solid #ddd;
45 .corner-all;
53 .corner-all;
46 padding: 0.4em;
54 padding: 0.4em;
47 padding-left: 2em;
55 padding-left: 2em;
48 }
56 }
49
57
50 p.dialog {
58 p.dialog {
51 padding : 0.2em;
59 padding : 0.2em;
52 }
60 }
53
61
54 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
62 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
55 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
63 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
56 */
64 */
57 pre, code, kbd, samp { white-space: pre-wrap; }
65 pre, code, kbd, samp { white-space: pre-wrap; }
58
66
59 #fonttest {
67 #fonttest {
60 font-family: @monoFontFamily;
68 font-family: @monoFontFamily;
61 }
69 }
62
70
63 p {
71 p {
64 margin-bottom:0;
72 margin-bottom:0;
65 }
73 }
66
74
67 .end_space {
75 .end_space {
68 height: 200px;
76 height: 200px;
69 }
77 }
@@ -1,169 +1,176 b''
1 div.output_wrapper {
1 div.output_wrapper {
2 /* this position must be relative to enable descendents to be absolute within it */
2 /* this position must be relative to enable descendents to be absolute within it */
3 position: relative;
3 position: relative;
4 .vbox()
4 .vbox()
5 }
5 }
6
6
7 /* class for the output area when it should be height-limited */
7 /* class for the output area when it should be height-limited */
8 div.output_scroll {
8 div.output_scroll {
9 /* ideally, this would be max-height, but FF barfs all over that */
9 /* ideally, this would be max-height, but FF barfs all over that */
10 height: 24em;
10 height: 24em;
11 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
11 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
12 width: 100%;
12 width: 100%;
13
13
14 overflow: auto;
14 overflow: auto;
15 .corner-all;
15 .corner-all;
16 .box-shadow(inset 0 2px 8px rgba(0, 0, 0, .8));
16 .box-shadow(inset 0 2px 8px rgba(0, 0, 0, .8));
17 display: block;
17 display: block;
18 }
18 }
19
19
20 /* output div while it is collapsed */
20 /* output div while it is collapsed */
21 div.output_collapsed {
21 div.output_collapsed {
22 margin: 0px;
22 margin: 0px;
23 padding: 0px;
23 padding: 0px;
24 .vbox();
24 .vbox();
25 }
25 }
26
26
27 div.out_prompt_overlay {
27 div.out_prompt_overlay {
28 height: 100%;
28 height: 100%;
29 padding: 0px @code_padding;
29 padding: 0px @code_padding;
30 position: absolute;
30 position: absolute;
31 .corner-all;
31 .corner-all;
32 }
32 }
33
33
34 div.out_prompt_overlay:hover {
34 div.out_prompt_overlay:hover {
35 /* use inner shadow to get border that is computed the same on WebKit/FF */
35 /* use inner shadow to get border that is computed the same on WebKit/FF */
36 .box-shadow(inset 0 0 1px #000);
36 .box-shadow(inset 0 0 1px #000);
37 background: rgba(240, 240, 240, 0.5);
37 background: rgba(240, 240, 240, 0.5);
38 }
38 }
39
39
40 div.output_prompt {
40 div.output_prompt {
41 color: darkred;
41 color: darkred;
42 }
42 }
43
43
44 /* This class is the outer container of all output sections. */
44 /* This class is the outer container of all output sections. */
45 div.output_area {
45 div.output_area {
46 padding: 0px;
46 padding: 0px;
47 page-break-inside: avoid;
47 page-break-inside: avoid;
48 .hbox();
48 .hbox();
49
49
50 .MathJax_Display {
50 .MathJax_Display {
51 // Inside a CodeCell, elements are left justified
51 // Inside a CodeCell, elements are left justified
52 text-align: left !important;
52 text-align: left !important;
53 }
53 }
54
54
55 .rendered_html {
55 .rendered_html {
56 // Inside a CodeCell, elements are left justified
56 // Inside a CodeCell, elements are left justified
57 table {
57 table {
58 margin-left: 0;
58 margin-left: 0;
59 margin-right: 0;
59 margin-right: 0;
60 }
60 }
61
61
62 img {
62 img {
63 margin-left: 0;
63 margin-left: 0;
64 margin-right: 0;
64 margin-right: 0;
65 }
65 }
66 }
66 }
67 }
67 }
68
68
69 /* This is needed to protect the pre formating from global settings such
69 /* This is needed to protect the pre formating from global settings such
70 as that of bootstrap */
70 as that of bootstrap */
71 .output {
71 .output {
72 .vbox();
72 .vbox();
73 }
73 }
74
74
75 @media (max-width: 480px) {
76 // move prompts above output on small screens
77 div.output_area {
78 .vbox();
79 }
80 }
81
75 div.output_area pre {
82 div.output_area pre {
76 margin: 0;
83 margin: 0;
77 padding: 0;
84 padding: 0;
78 border: 0;
85 border: 0;
79 font-size: 100%;
86 font-size: 100%;
80 vertical-align: baseline;
87 vertical-align: baseline;
81 color: black;
88 color: black;
82 background-color: transparent;
89 background-color: transparent;
83 .border-radius(0);
90 .border-radius(0);
84 line-height: inherit;
91 line-height: inherit;
85 }
92 }
86
93
87 /* This class is for the output subarea inside the output_area and after
94 /* This class is for the output subarea inside the output_area and after
88 the prompt div. */
95 the prompt div. */
89 div.output_subarea {
96 div.output_subarea {
90 padding: @code_padding @code_padding 0.0em @code_padding;
97 padding: @code_padding @code_padding 0.0em @code_padding;
91 .box-flex1();
98 .box-flex1();
92 }
99 }
93
100
94 /* The rest of the output_* classes are for special styling of the different
101 /* The rest of the output_* classes are for special styling of the different
95 output types */
102 output types */
96
103
97 /* all text output has this class: */
104 /* all text output has this class: */
98 div.output_text {
105 div.output_text {
99 text-align: left;
106 text-align: left;
100 color: @textColor;
107 color: @textColor;
101 /* This has to match that of the the CodeMirror class line-height below */
108 /* This has to match that of the the CodeMirror class line-height below */
102 line-height: @code_line_height;
109 line-height: @code_line_height;
103 }
110 }
104
111
105 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
112 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
106 div.output_stream {
113 div.output_stream {
107 }
114 }
108
115
109 div.output_stdout {
116 div.output_stdout {
110 }
117 }
111
118
112 div.output_stderr {
119 div.output_stderr {
113 background: #fdd; /* very light red background for stderr */
120 background: #fdd; /* very light red background for stderr */
114 }
121 }
115
122
116 div.output_latex {
123 div.output_latex {
117 text-align: left;
124 text-align: left;
118 }
125 }
119
126
120 div.output_html {
127 div.output_html {
121 }
128 }
122
129
123 div.output_png {
130 div.output_png {
124 }
131 }
125
132
126 div.output_jpeg {
133 div.output_jpeg {
127 }
134 }
128
135
129 /* Empty output_javascript divs should have no height */
136 /* Empty output_javascript divs should have no height */
130 div.output_javascript:empty {
137 div.output_javascript:empty {
131 padding: 0;
138 padding: 0;
132 }
139 }
133
140
134 .js-error {
141 .js-error {
135 color: darkred;
142 color: darkred;
136 }
143 }
137
144
138 /* raw_input styles */
145 /* raw_input styles */
139
146
140 div.raw_input_container {
147 div.raw_input_container {
141 font-family: @monoFontFamily;
148 font-family: @monoFontFamily;
142 // for some reason, em padding doesn't compute the same for raw_input
149 // for some reason, em padding doesn't compute the same for raw_input
143 // that is not the first input, but px does
150 // that is not the first input, but px does
144 padding-top: 5px;
151 padding-top: 5px;
145 }
152 }
146
153
147 span.raw_input_prompt {
154 span.raw_input_prompt {
148 /* nothing needed here */
155 /* nothing needed here */
149 }
156 }
150
157
151 input.raw_input {
158 input.raw_input {
152 font-family: inherit;
159 font-family: inherit;
153 font-size: inherit;
160 font-size: inherit;
154 color: inherit;
161 color: inherit;
155 width: auto;
162 width: auto;
156 /* make sure input baseline aligns with prompt */
163 /* make sure input baseline aligns with prompt */
157 vertical-align: baseline;
164 vertical-align: baseline;
158 /* padding + margin = 0.5em between prompt and cursor */
165 /* padding + margin = 0.5em between prompt and cursor */
159 padding: 0em 0.25em;
166 padding: 0em 0.25em;
160 margin: 0em 0.25em;
167 margin: 0em 0.25em;
161 }
168 }
162
169
163 input.raw_input:focus {
170 input.raw_input:focus {
164 box-shadow: none;
171 box-shadow: none;
165 }
172 }
166
173
167 p.p-space {
174 p.p-space {
168 margin-bottom: 10px;
175 margin-bottom: 10px;
169 }
176 }
@@ -1,30 +1,36 b''
1 div.text_cell {
1 div.text_cell {
2 padding: 5px 5px 5px 0px;
2 padding: 5px 5px 5px 0px;
3 .hbox();
3 .hbox();
4 }
4 }
5 @media (max-width: 480px) {
6 // remove prompt indentation on small screens
7 div.text_cell > div.prompt {
8 display: none;
9 }
10 }
5
11
6 div.text_cell_render {
12 div.text_cell_render {
7 /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
13 /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
8 outline: none;
14 outline: none;
9 resize: none;
15 resize: none;
10 width: inherit;
16 width: inherit;
11 border-style: none;
17 border-style: none;
12 padding: 0.5em 0.5em 0.5em @code_padding;
18 padding: 0.5em 0.5em 0.5em @code_padding;
13 color: @textColor;
19 color: @textColor;
14 }
20 }
15
21
16 a.anchor-link:link {
22 a.anchor-link:link {
17 text-decoration: none;
23 text-decoration: none;
18 padding: 0px 20px;
24 padding: 0px 20px;
19 visibility: hidden;
25 visibility: hidden;
20 }
26 }
21
27
22 h1,h2,h3,h4,h5,h6 {
28 h1,h2,h3,h4,h5,h6 {
23 &:hover .anchor-link {
29 &:hover .anchor-link {
24 visibility: visible;
30 visibility: visible;
25 }
31 }
26 }
32 }
27
33
28 div.cell.text_cell.rendered {
34 div.cell.text_cell.rendered {
29 padding: 0px;
35 padding: 0px;
30 }
36 }
@@ -1,199 +1,199 b''
1 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
1 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
2 .clearfix:after{clear:both}
2 .clearfix:after{clear:both}
3 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
3 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
4 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
4 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
5 code{color:#000}
5 code{color:#000}
6 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
6 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
7 .corner-all{border-radius:4px}
7 .corner-all{border-radius:4px}
8 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
8 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
9 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
9 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
10 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
10 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
11 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
11 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
12 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
12 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
13 .hbox.box-flex0,.vbox.box-flex0,.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}
13 .hbox.box-flex0,.vbox.box-flex0,.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}
14 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
14 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
15 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
15 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
16 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
16 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
17 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
17 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
18 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
18 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
19 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
19 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
20 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
20 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
21 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
21 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
22 .hbox.align-start,.vbox.align-start,.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
22 .hbox.align-start,.vbox.align-start,.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
23 .hbox.align-end,.vbox.align-end,.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}
23 .hbox.align-end,.vbox.align-end,.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}
24 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
24 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
25 div.error{margin:2em;text-align:center}
25 div.error{margin:2em;text-align:center}
26 div.error>h1{font-size:500%;line-height:normal}
26 div.error>h1{font-size:500%;line-height:normal}
27 div.error>p{font-size:200%;line-height:normal}
27 div.error>p{font-size:200%;line-height:normal}
28 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
28 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
29 .center-nav{display:inline-block;margin-bottom:-4px}
29 .center-nav{display:inline-block;margin-bottom:-4px}
30 .alternate_upload{background-color:none;display:inline}
30 .alternate_upload{background-color:none;display:inline}
31 .alternate_upload.form{padding:0;margin:0}
31 .alternate_upload.form{padding:0;margin:0}
32 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
32 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
33 ul#tabs{margin-bottom:4px}
33 ul#tabs{margin-bottom:4px}
34 ul#tabs a{padding-top:4px;padding-bottom:4px}
34 ul#tabs a{padding-top:4px;padding-bottom:4px}
35 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
35 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
36 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
36 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
37 ul.breadcrumb span{color:#5e5e5e}
37 ul.breadcrumb span{color:#5e5e5e}
38 .list_toolbar{padding:4px 0 4px 0}
38 .list_toolbar{padding:4px 0 4px 0}
39 .list_toolbar [class*="span"]{min-height:26px}
39 .list_toolbar [class*="span"]{min-height:26px}
40 .list_header{font-weight:bold}
40 .list_header{font-weight:bold}
41 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
41 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
42 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
42 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
43 .list_container>div:last-child{border:none}
43 .list_container>div:last-child{border:none}
44 .list_item:hover .list_item{background-color:#ddd}
44 .list_item:hover .list_item{background-color:#ddd}
45 .list_item a{text-decoration:none}
45 .list_item a{text-decoration:none}
46 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
46 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
47 .item_name{line-height:22px;height:26px}
47 .item_name{line-height:22px;height:26px}
48 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
48 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
49 .item_buttons{line-height:1em}
49 .item_buttons{line-height:1em}
50 .toolbar_info{height:26px;line-height:26px}
50 .toolbar_info{height:26px;line-height:26px}
51 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
51 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
52 input.engine_num_input{width:60px}
52 input.engine_num_input{width:60px}
53 .highlight_text{color:#00f}
53 .highlight_text{color:#00f}
54 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
54 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
55 .ansibold{font-weight:bold}
55 .ansibold{font-weight:bold}
56 .ansiblack{color:#000}
56 .ansiblack{color:#000}
57 .ansired{color:#8b0000}
57 .ansired{color:#8b0000}
58 .ansigreen{color:#006400}
58 .ansigreen{color:#006400}
59 .ansiyellow{color:#a52a2a}
59 .ansiyellow{color:#a52a2a}
60 .ansiblue{color:#00008b}
60 .ansiblue{color:#00008b}
61 .ansipurple{color:#9400d3}
61 .ansipurple{color:#9400d3}
62 .ansicyan{color:#4682b4}
62 .ansicyan{color:#4682b4}
63 .ansigray{color:#808080}
63 .ansigray{color:#808080}
64 .ansibgblack{background-color:#000}
64 .ansibgblack{background-color:#000}
65 .ansibgred{background-color:#f00}
65 .ansibgred{background-color:#f00}
66 .ansibggreen{background-color:#008000}
66 .ansibggreen{background-color:#008000}
67 .ansibgyellow{background-color:#ff0}
67 .ansibgyellow{background-color:#ff0}
68 .ansibgblue{background-color:#00f}
68 .ansibgblue{background-color:#00f}
69 .ansibgpurple{background-color:#f0f}
69 .ansibgpurple{background-color:#f0f}
70 .ansibgcyan{background-color:#0ff}
70 .ansibgcyan{background-color:#0ff}
71 .ansibggray{background-color:#808080}
71 .ansibggray{background-color:#808080}
72 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
72 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
73 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
73 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
74 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
74 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
75 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}
75 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}
76 div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
76 @media (max-width:480px){div.prompt{text-align:left}}div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
77 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
77 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
78 div.prompt:empty{padding-top:0;padding-bottom:0}
78 div.prompt:empty{padding-top:0;padding-bottom:0}
79 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
79 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
80 div.input_prompt{color:#000080;border-top:1px solid transparent}
80 @media (max-width:480px){div.input{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.input_prompt{color:#000080;border-top:1px solid transparent}
81 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
81 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
82 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
82 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
83 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
83 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
84 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
84 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
85 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
85 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
86 .CodeMirror-linenumber{padding:0 8px 0 4px}
86 .CodeMirror-linenumber{padding:0 8px 0 4px}
87 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
87 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
88 .CodeMirror pre{padding:0;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
88 .CodeMirror pre{padding:0;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
89 pre code{display:block;padding:.5em}
89 pre code{display:block;padding:.5em}
90 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
90 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
91 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
91 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
92 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
92 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
93 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
93 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
94 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
94 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
95 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
95 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
96 .highlight-builtin,pre .built_in{color:#008000}
96 .highlight-builtin,pre .built_in{color:#008000}
97 pre .markdown .emphasis{font-style:italic}
97 pre .markdown .emphasis{font-style:italic}
98 pre .nginx .built_in{font-weight:normal}
98 pre .nginx .built_in{font-weight:normal}
99 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
99 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
100 .cm-s-ipython span.cm-variable{color:#000}
100 .cm-s-ipython span.cm-variable{color:#000}
101 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
101 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
102 .cm-s-ipython span.cm-number{color:#080}
102 .cm-s-ipython span.cm-number{color:#080}
103 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
103 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
104 .cm-s-ipython span.cm-string{color:#ba2121}
104 .cm-s-ipython span.cm-string{color:#ba2121}
105 .cm-s-ipython span.cm-builtin{color:#008000}
105 .cm-s-ipython span.cm-builtin{color:#008000}
106 .cm-s-ipython span.cm-error{color:#f00}
106 .cm-s-ipython span.cm-error{color:#f00}
107 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
107 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
108 .cm-s-ipython span.cm-meta{color:#a2f}
108 .cm-s-ipython span.cm-meta{color:#a2f}
109 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
109 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
110 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
110 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
111 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);display:block}
111 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);display:block}
112 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
112 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
113 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
113 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
114 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
114 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
115 div.output_prompt{color:#8b0000}
115 div.output_prompt{color:#8b0000}
116 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
116 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
117 div.output_area .rendered_html table{margin-left:0;margin-right:0}
117 div.output_area .rendered_html table{margin-left:0;margin-right:0}
118 div.output_area .rendered_html img{margin-left:0;margin-right:0}
118 div.output_area .rendered_html img{margin-left:0;margin-right:0}
119 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
119 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
120 div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
120 @media (max-width:480px){div.output_area{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
121 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
121 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
122 div.output_text{text-align:left;color:#000;line-height:1.21429em}
122 div.output_text{text-align:left;color:#000;line-height:1.21429em}
123 div.output_stderr{background:#fdd;}
123 div.output_stderr{background:#fdd;}
124 div.output_latex{text-align:left}
124 div.output_latex{text-align:left}
125 div.output_javascript:empty{padding:0}
125 div.output_javascript:empty{padding:0}
126 .js-error{color:#8b0000}
126 .js-error{color:#8b0000}
127 div.raw_input_container{font-family:monospace;padding-top:5px}
127 div.raw_input_container{font-family:monospace;padding-top:5px}
128 span.raw_input_prompt{}
128 span.raw_input_prompt{}
129 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
129 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
130 input.raw_input:focus{box-shadow:none}
130 input.raw_input:focus{box-shadow:none}
131 p.p-space{margin-bottom:10px}
131 p.p-space{margin-bottom:10px}
132 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
132 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
133 .rendered_html strong{font-weight:bold}
133 .rendered_html strong{font-weight:bold}
134 .rendered_html u{text-decoration:underline}
134 .rendered_html u{text-decoration:underline}
135 .rendered_html :link{text-decoration:underline}
135 .rendered_html :link{text-decoration:underline}
136 .rendered_html :visited{text-decoration:underline}
136 .rendered_html :visited{text-decoration:underline}
137 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
137 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
138 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
138 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
139 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
139 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
140 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
140 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
141 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
141 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
142 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
142 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
143 .rendered_html h1:first-child{margin-top:.538em}
143 .rendered_html h1:first-child{margin-top:.538em}
144 .rendered_html h2:first-child{margin-top:.636em}
144 .rendered_html h2:first-child{margin-top:.636em}
145 .rendered_html h3:first-child{margin-top:.777em}
145 .rendered_html h3:first-child{margin-top:.777em}
146 .rendered_html h4:first-child{margin-top:1em}
146 .rendered_html h4:first-child{margin-top:1em}
147 .rendered_html h5:first-child{margin-top:1em}
147 .rendered_html h5:first-child{margin-top:1em}
148 .rendered_html h6:first-child{margin-top:1em}
148 .rendered_html h6:first-child{margin-top:1em}
149 .rendered_html ul{list-style:disc;margin:0 2em}
149 .rendered_html ul{list-style:disc;margin:0 2em}
150 .rendered_html ul ul{list-style:square;margin:0 2em}
150 .rendered_html ul ul{list-style:square;margin:0 2em}
151 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
151 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
152 .rendered_html ol{list-style:decimal;margin:0 2em}
152 .rendered_html ol{list-style:decimal;margin:0 2em}
153 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
153 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
154 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
154 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
155 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
155 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
156 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
156 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
157 .rendered_html *+ul{margin-top:1em}
157 .rendered_html *+ul{margin-top:1em}
158 .rendered_html *+ol{margin-top:1em}
158 .rendered_html *+ol{margin-top:1em}
159 .rendered_html hr{color:#000;background-color:#000}
159 .rendered_html hr{color:#000;background-color:#000}
160 .rendered_html pre{margin:1em 2em}
160 .rendered_html pre{margin:1em 2em}
161 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
161 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
162 .rendered_html blockquote{margin:1em 2em}
162 .rendered_html blockquote{margin:1em 2em}
163 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
163 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
164 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
164 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
165 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
165 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
166 .rendered_html th{font-weight:bold}
166 .rendered_html th{font-weight:bold}
167 .rendered_html *+table{margin-top:1em}
167 .rendered_html *+table{margin-top:1em}
168 .rendered_html p{text-align:justify}
168 .rendered_html p{text-align:justify}
169 .rendered_html *+p{margin-top:1em}
169 .rendered_html *+p{margin-top:1em}
170 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
170 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
171 .rendered_html *+img{margin-top:1em}
171 .rendered_html *+img{margin-top:1em}
172 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
172 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
173 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
173 @media (max-width:480px){div.text_cell>div.prompt{display:none}}div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
174 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
174 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
175 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
175 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
176 div.cell.text_cell.rendered{padding:0}
176 div.cell.text_cell.rendered{padding:0}
177 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
177 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
178 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
178 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
179 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
179 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
180 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
180 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
181 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
181 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
182 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
182 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
183 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;margin-bottom:10px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
183 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;margin-bottom:10px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
184 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
184 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
185 .widget-text{width:350px;margin:0 !important}
185 .widget-text{width:350px;margin:0 !important}
186 .widget-listbox{width:364px;margin-bottom:0}
186 .widget-listbox{width:364px;margin-bottom:0}
187 .widget-numeric-text{width:150px;margin:0 !important}
187 .widget-numeric-text{width:150px;margin:0 !important}
188 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
188 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
189 .widget-combo-btn{min-width:138px;}
189 .widget-combo-btn{min-width:138px;}
190 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
190 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
191 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
191 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
192 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
192 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
193 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
193 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
194 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
194 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
195 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
195 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
196 .widget-modal-body{max-height:none !important}
196 .widget-modal-body{max-height:none !important}
197 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
197 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
198 .widget-radio-box{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:4px}
198 .widget-radio-box{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:4px}
199 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
199 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
@@ -1,1536 +1,1536 b''
1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
3 audio:not([controls]){display:none}
3 audio:not([controls]){display:none}
4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
6 a:hover,a:active{outline:0}
6 a:hover,a:active{outline:0}
7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}
7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}
8 sup{top:-0.5em}
8 sup{top:-0.5em}
9 sub{bottom:-0.25em}
9 sub{bottom:-0.25em}
10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}
10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}
11 #map_canvas img,.google-maps img{max-width:none}
11 #map_canvas img,.google-maps img{max-width:none}
12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}
12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}
13 button,input{*overflow:visible;line-height:normal}
13 button,input{*overflow:visible;line-height:normal}
14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}
16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}
17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}
17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}
18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
19 textarea{overflow:auto;vertical-align:top}
19 textarea{overflow:auto;vertical-align:top}
20 @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""} pre,blockquote{border:1px solid #999;page-break-inside:avoid} thead{display:table-header-group} tr,img{page-break-inside:avoid} img{max-width:100% !important} @page {margin:.5cm}p,h2,h3{orphans:3;widows:3} h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000;background-color:#fff}
20 @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""} pre,blockquote{border:1px solid #999;page-break-inside:avoid} thead{display:table-header-group} tr,img{page-break-inside:avoid} img{max-width:100% !important} @page {margin:.5cm}p,h2,h3{orphans:3;widows:3} h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000;background-color:#fff}
21 a{color:#08c;text-decoration:none}
21 a{color:#08c;text-decoration:none}
22 a:hover,a:focus{color:#005580;text-decoration:underline}
22 a:hover,a:focus{color:#005580;text-decoration:underline}
23 .img-rounded{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
23 .img-rounded{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
24 .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}
24 .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}
25 .img-circle{border-radius:500px;-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}
25 .img-circle{border-radius:500px;-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}
26 .row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0}
26 .row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0}
27 .row:after{clear:both}
27 .row:after{clear:both}
28 [class*="span"]{float:left;min-height:1px;margin-left:20px}
28 [class*="span"]{float:left;min-height:1px;margin-left:20px}
29 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
29 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
30 .span12{width:940px}
30 .span12{width:940px}
31 .span11{width:860px}
31 .span11{width:860px}
32 .span10{width:780px}
32 .span10{width:780px}
33 .span9{width:700px}
33 .span9{width:700px}
34 .span8{width:620px}
34 .span8{width:620px}
35 .span7{width:540px}
35 .span7{width:540px}
36 .span6{width:460px}
36 .span6{width:460px}
37 .span5{width:380px}
37 .span5{width:380px}
38 .span4{width:300px}
38 .span4{width:300px}
39 .span3{width:220px}
39 .span3{width:220px}
40 .span2{width:140px}
40 .span2{width:140px}
41 .span1{width:60px}
41 .span1{width:60px}
42 .offset12{margin-left:980px}
42 .offset12{margin-left:980px}
43 .offset11{margin-left:900px}
43 .offset11{margin-left:900px}
44 .offset10{margin-left:820px}
44 .offset10{margin-left:820px}
45 .offset9{margin-left:740px}
45 .offset9{margin-left:740px}
46 .offset8{margin-left:660px}
46 .offset8{margin-left:660px}
47 .offset7{margin-left:580px}
47 .offset7{margin-left:580px}
48 .offset6{margin-left:500px}
48 .offset6{margin-left:500px}
49 .offset5{margin-left:420px}
49 .offset5{margin-left:420px}
50 .offset4{margin-left:340px}
50 .offset4{margin-left:340px}
51 .offset3{margin-left:260px}
51 .offset3{margin-left:260px}
52 .offset2{margin-left:180px}
52 .offset2{margin-left:180px}
53 .offset1{margin-left:100px}
53 .offset1{margin-left:100px}
54 .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0}
54 .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0}
55 .row-fluid:after{clear:both}
55 .row-fluid:after{clear:both}
56 .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%}
56 .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%}
57 .row-fluid [class*="span"]:first-child{margin-left:0}
57 .row-fluid [class*="span"]:first-child{margin-left:0}
58 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}
58 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}
59 .row-fluid .span12{width:100%;*width:99.94680851063829%}
59 .row-fluid .span12{width:100%;*width:99.94680851063829%}
60 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}
60 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}
61 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}
61 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}
62 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}
62 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}
63 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}
63 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}
64 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}
64 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}
65 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}
65 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}
66 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}
66 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}
67 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}
67 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}
68 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}
68 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}
69 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}
69 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}
70 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}
70 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}
71 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}
71 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}
72 .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}
72 .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}
73 .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}
73 .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}
74 .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}
74 .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}
75 .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}
75 .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}
76 .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}
76 .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}
77 .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}
77 .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}
78 .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}
78 .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}
79 .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}
79 .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}
80 .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}
80 .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}
81 .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}
81 .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}
82 .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}
82 .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}
83 .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}
83 .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}
84 .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}
84 .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}
85 .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}
85 .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}
86 .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}
86 .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}
87 .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}
87 .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}
88 .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}
88 .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}
89 .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}
89 .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}
90 .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}
90 .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}
91 .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}
91 .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}
92 .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}
92 .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}
93 .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}
93 .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}
94 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}
94 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}
95 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none}
95 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none}
96 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}
96 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}
97 .container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:"";line-height:0}
97 .container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:"";line-height:0}
98 .container:after{clear:both}
98 .container:after{clear:both}
99 .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0}
99 .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0}
100 .container-fluid:after{clear:both}
100 .container-fluid:after{clear:both}
101 p{margin:0 0 10px}
101 p{margin:0 0 10px}
102 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px}
102 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px}
103 small{font-size:85%}
103 small{font-size:85%}
104 strong{font-weight:bold}
104 strong{font-weight:bold}
105 em{font-style:italic}
105 em{font-style:italic}
106 cite{font-style:normal}
106 cite{font-style:normal}
107 .muted{color:#999}
107 .muted{color:#999}
108 a.muted:hover,a.muted:focus{color:#808080}
108 a.muted:hover,a.muted:focus{color:#808080}
109 .text-warning{color:#c09853}
109 .text-warning{color:#c09853}
110 a.text-warning:hover,a.text-warning:focus{color:#a47e3c}
110 a.text-warning:hover,a.text-warning:focus{color:#a47e3c}
111 .text-error{color:#b94a48}
111 .text-error{color:#b94a48}
112 a.text-error:hover,a.text-error:focus{color:#953b39}
112 a.text-error:hover,a.text-error:focus{color:#953b39}
113 .text-info{color:#3a87ad}
113 .text-info{color:#3a87ad}
114 a.text-info:hover,a.text-info:focus{color:#2d6987}
114 a.text-info:hover,a.text-info:focus{color:#2d6987}
115 .text-success{color:#468847}
115 .text-success{color:#468847}
116 a.text-success:hover,a.text-success:focus{color:#356635}
116 a.text-success:hover,a.text-success:focus{color:#356635}
117 .text-left{text-align:left}
117 .text-left{text-align:left}
118 .text-right{text-align:right}
118 .text-right{text-align:right}
119 .text-center{text-align:center}
119 .text-center{text-align:center}
120 h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}
120 h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}
121 h1,h2,h3{line-height:40px}
121 h1,h2,h3{line-height:40px}
122 h1{font-size:35.75px}
122 h1{font-size:35.75px}
123 h2{font-size:29.25px}
123 h2{font-size:29.25px}
124 h3{font-size:22.75px}
124 h3{font-size:22.75px}
125 h4{font-size:16.25px}
125 h4{font-size:16.25px}
126 h5{font-size:13px}
126 h5{font-size:13px}
127 h6{font-size:11.049999999999999px}
127 h6{font-size:11.049999999999999px}
128 h1 small{font-size:22.75px}
128 h1 small{font-size:22.75px}
129 h2 small{font-size:16.25px}
129 h2 small{font-size:16.25px}
130 h3 small{font-size:13px}
130 h3 small{font-size:13px}
131 h4 small{font-size:13px}
131 h4 small{font-size:13px}
132 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}
132 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}
133 ul,ol{padding:0;margin:0 0 10px 25px}
133 ul,ol{padding:0;margin:0 0 10px 25px}
134 ul ul,ul ol,ol ol,ol ul{margin-bottom:0}
134 ul ul,ul ol,ol ol,ol ul{margin-bottom:0}
135 li{line-height:20px}
135 li{line-height:20px}
136 ul.unstyled,ol.unstyled{margin-left:0;list-style:none}
136 ul.unstyled,ol.unstyled{margin-left:0;list-style:none}
137 ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px}
137 ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px}
138 dl{margin-bottom:20px}
138 dl{margin-bottom:20px}
139 dt,dd{line-height:20px}
139 dt,dd{line-height:20px}
140 dt{font-weight:bold}
140 dt{font-weight:bold}
141 dd{margin-left:10px}
141 dd{margin-left:10px}
142 .dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0}
142 .dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0}
143 .dl-horizontal:after{clear:both}
143 .dl-horizontal:after{clear:both}
144 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
144 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
145 .dl-horizontal dd{margin-left:180px}
145 .dl-horizontal dd{margin-left:180px}
146 hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}
146 hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}
147 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}
147 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}
148 abbr.initialism{font-size:90%;text-transform:uppercase}
148 abbr.initialism{font-size:90%;text-transform:uppercase}
149 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16.25px;font-weight:300;line-height:1.25}
149 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16.25px;font-weight:300;line-height:1.25}
150 blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}
150 blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}
151 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}
151 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}
152 blockquote.pull-right small:before{content:''}
152 blockquote.pull-right small:before{content:''}
153 blockquote.pull-right small:after{content:'\00A0 \2014'}
153 blockquote.pull-right small:after{content:'\00A0 \2014'}
154 q:before,q:after,blockquote:before,blockquote:after{content:""}
154 q:before,q:after,blockquote:before,blockquote:after{content:""}
155 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}
155 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}
156 code,pre{padding:0 3px 2px;font-family:monospace;font-size:11px;color:#333;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
156 code,pre{padding:0 3px 2px;font-family:monospace;font-size:11px;color:#333;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
157 code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}
157 code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}
158 pre{display:block;padding:9.5px;margin:0 0 10px;font-size:12px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}
158 pre{display:block;padding:9.5px;margin:0 0 10px;font-size:12px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}
159 pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}
159 pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}
160 .pre-scrollable{max-height:340px;overflow-y:scroll}
160 .pre-scrollable{max-height:340px;overflow-y:scroll}
161 form{margin:0 0 20px}
161 form{margin:0 0 20px}
162 fieldset{padding:0;margin:0;border:0}
162 fieldset{padding:0;margin:0;border:0}
163 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}
163 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}
164 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px}
164 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px}
165 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}
165 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}
166 label{display:block;margin-bottom:5px}
166 label{display:block;margin-bottom:5px}
167 select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:13px;line-height:20px;color:#555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle}
167 select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:13px;line-height:20px;color:#555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle}
168 input,textarea,.uneditable-input{width:206px}
168 input,textarea,.uneditable-input{width:206px}
169 textarea{height:auto}
169 textarea{height:auto}
170 textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)}
170 textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)}
171 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal}
171 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal}
172 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}
172 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}
173 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}
173 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}
174 select{width:220px;border:1px solid #ccc;background-color:#fff}
174 select{width:220px;border:1px solid #ccc;background-color:#fff}
175 select[multiple],select[size]{height:auto}
175 select[multiple],select[size]{height:auto}
176 select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
176 select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
177 .uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);cursor:not-allowed}
177 .uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);cursor:not-allowed}
178 .uneditable-input{overflow:hidden;white-space:nowrap}
178 .uneditable-input{overflow:hidden;white-space:nowrap}
179 .uneditable-textarea{width:auto;height:auto}
179 .uneditable-textarea{width:auto;height:auto}
180 input:-moz-placeholder,textarea:-moz-placeholder{color:#999}
180 input:-moz-placeholder,textarea:-moz-placeholder{color:#999}
181 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}
181 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}
182 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}
182 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}
183 .radio,.checkbox{min-height:20px;padding-left:20px}
183 .radio,.checkbox{min-height:20px;padding-left:20px}
184 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}
184 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}
185 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}
185 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}
186 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}
186 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}
187 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}
187 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}
188 .input-mini{width:60px}
188 .input-mini{width:60px}
189 .input-small{width:90px}
189 .input-small{width:90px}
190 .input-medium{width:150px}
190 .input-medium{width:150px}
191 .input-large{width:210px}
191 .input-large{width:210px}
192 .input-xlarge{width:270px}
192 .input-xlarge{width:270px}
193 .input-xxlarge{width:530px}
193 .input-xxlarge{width:530px}
194 input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}
194 input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}
195 .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}
195 .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}
196 input,textarea,.uneditable-input{margin-left:0}
196 input,textarea,.uneditable-input{margin-left:0}
197 .controls-row [class*="span"]+[class*="span"]{margin-left:20px}
197 .controls-row [class*="span"]+[class*="span"]{margin-left:20px}
198 input.span12,textarea.span12,.uneditable-input.span12{width:926px}
198 input.span12,textarea.span12,.uneditable-input.span12{width:926px}
199 input.span11,textarea.span11,.uneditable-input.span11{width:846px}
199 input.span11,textarea.span11,.uneditable-input.span11{width:846px}
200 input.span10,textarea.span10,.uneditable-input.span10{width:766px}
200 input.span10,textarea.span10,.uneditable-input.span10{width:766px}
201 input.span9,textarea.span9,.uneditable-input.span9{width:686px}
201 input.span9,textarea.span9,.uneditable-input.span9{width:686px}
202 input.span8,textarea.span8,.uneditable-input.span8{width:606px}
202 input.span8,textarea.span8,.uneditable-input.span8{width:606px}
203 input.span7,textarea.span7,.uneditable-input.span7{width:526px}
203 input.span7,textarea.span7,.uneditable-input.span7{width:526px}
204 input.span6,textarea.span6,.uneditable-input.span6{width:446px}
204 input.span6,textarea.span6,.uneditable-input.span6{width:446px}
205 input.span5,textarea.span5,.uneditable-input.span5{width:366px}
205 input.span5,textarea.span5,.uneditable-input.span5{width:366px}
206 input.span4,textarea.span4,.uneditable-input.span4{width:286px}
206 input.span4,textarea.span4,.uneditable-input.span4{width:286px}
207 input.span3,textarea.span3,.uneditable-input.span3{width:206px}
207 input.span3,textarea.span3,.uneditable-input.span3{width:206px}
208 input.span2,textarea.span2,.uneditable-input.span2{width:126px}
208 input.span2,textarea.span2,.uneditable-input.span2{width:126px}
209 input.span1,textarea.span1,.uneditable-input.span1{width:46px}
209 input.span1,textarea.span1,.uneditable-input.span1{width:46px}
210 .controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0}
210 .controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0}
211 .controls-row:after{clear:both}
211 .controls-row:after{clear:both}
212 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}
212 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}
213 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}
213 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}
214 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}
214 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}
215 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}
215 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}
216 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}
216 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}
217 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}
217 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}
218 .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}
218 .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}
219 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}
219 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}
220 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}
220 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}
221 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}
221 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}
222 .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}
222 .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}
223 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}
223 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}
224 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}
224 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}
225 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}
225 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}
226 .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}
226 .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}
227 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}
227 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}
228 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}
228 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}
229 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}
229 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}
230 .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}
230 .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}
231 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}
231 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}
232 input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}
232 input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}
233 .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0}
233 .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0}
234 .form-actions:after{clear:both}
234 .form-actions:after{clear:both}
235 .help-block,.help-inline{color:#262626}
235 .help-block,.help-inline{color:#262626}
236 .help-block{display:block;margin-bottom:10px}
236 .help-block{display:block;margin-bottom:10px}
237 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px}
237 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px}
238 .input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:13px}
238 .input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:13px}
239 .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}
239 .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}
240 .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:13px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}
240 .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:13px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}
241 .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
241 .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
242 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}
242 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}
243 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px}
243 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px}
244 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
244 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
245 .input-append input,.input-append select,.input-append .uneditable-input{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
245 .input-append input,.input-append select,.input-append .uneditable-input{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
246 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}
246 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}
247 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
247 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
248 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
248 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
249 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
249 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
250 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
250 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
251 .input-prepend.input-append .btn-group:first-child{margin-left:0}
251 .input-prepend.input-append .btn-group:first-child{margin-left:0}
252 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
252 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
253 .form-search .input-append .search-query,.form-search .input-prepend .search-query{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
253 .form-search .input-append .search-query,.form-search .input-prepend .search-query{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
254 .form-search .input-append .search-query{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
254 .form-search .input-append .search-query{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
255 .form-search .input-append .btn{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
255 .form-search .input-append .btn{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
256 .form-search .input-prepend .search-query{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
256 .form-search .input-prepend .search-query{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
257 .form-search .input-prepend .btn{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
257 .form-search .input-prepend .btn{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
258 .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle}
258 .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle}
259 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}
259 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}
260 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}
260 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}
261 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}
261 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}
262 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}
262 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}
263 .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}
263 .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}
264 .control-group{margin-bottom:10px}
264 .control-group{margin-bottom:10px}
265 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}
265 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}
266 .form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0}
266 .form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0}
267 .form-horizontal .control-group:after{clear:both}
267 .form-horizontal .control-group:after{clear:both}
268 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}
268 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}
269 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}
269 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}
270 .form-horizontal .help-block{margin-bottom:0}
270 .form-horizontal .help-block{margin-bottom:0}
271 .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}
271 .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}
272 .form-horizontal .form-actions{padding-left:180px}
272 .form-horizontal .form-actions{padding-left:180px}
273 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}
273 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}
274 .table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}
274 .table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}
275 .table th{font-weight:bold}
275 .table th{font-weight:bold}
276 .table thead th{vertical-align:bottom}
276 .table thead th{vertical-align:bottom}
277 .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}
277 .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}
278 .table tbody+tbody{border-top:2px solid #ddd}
278 .table tbody+tbody{border-top:2px solid #ddd}
279 .table .table{background-color:#fff}
279 .table .table{background-color:#fff}
280 .table-condensed th,.table-condensed td{padding:4px 5px}
280 .table-condensed th,.table-condensed td{padding:4px 5px}
281 .table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}
281 .table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}
282 .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}
282 .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}
283 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
283 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
284 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
284 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
285 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
285 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
286 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
286 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
287 .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0}
287 .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0}
288 .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0}
288 .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0}
289 .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
289 .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
290 .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
290 .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
291 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
291 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
292 .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}
292 .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}
293 table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}
293 table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}
294 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0}
294 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0}
295 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0}
295 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0}
296 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0}
296 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0}
297 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0}
297 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0}
298 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0}
298 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0}
299 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0}
299 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0}
300 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0}
300 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0}
301 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0}
301 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0}
302 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0}
302 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0}
303 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0}
303 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0}
304 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0}
304 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0}
305 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0}
305 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0}
306 .table tbody tr.success>td{background-color:#dff0d8}
306 .table tbody tr.success>td{background-color:#dff0d8}
307 .table tbody tr.error>td{background-color:#f2dede}
307 .table tbody tr.error>td{background-color:#f2dede}
308 .table tbody tr.warning>td{background-color:#fcf8e3}
308 .table tbody tr.warning>td{background-color:#fcf8e3}
309 .table tbody tr.info>td{background-color:#d9edf7}
309 .table tbody tr.info>td{background-color:#d9edf7}
310 .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}
310 .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}
311 .table-hover tbody tr.error:hover>td{background-color:#ebcccc}
311 .table-hover tbody tr.error:hover>td{background-color:#ebcccc}
312 .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}
312 .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}
313 .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}
313 .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}
314 [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px}
314 [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px}
315 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}
315 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}
316 .icon-glass{background-position:0 0}
316 .icon-glass{background-position:0 0}
317 .icon-music{background-position:-24px 0}
317 .icon-music{background-position:-24px 0}
318 .icon-search{background-position:-48px 0}
318 .icon-search{background-position:-48px 0}
319 .icon-envelope{background-position:-72px 0}
319 .icon-envelope{background-position:-72px 0}
320 .icon-heart{background-position:-96px 0}
320 .icon-heart{background-position:-96px 0}
321 .icon-star{background-position:-120px 0}
321 .icon-star{background-position:-120px 0}
322 .icon-star-empty{background-position:-144px 0}
322 .icon-star-empty{background-position:-144px 0}
323 .icon-user{background-position:-168px 0}
323 .icon-user{background-position:-168px 0}
324 .icon-film{background-position:-192px 0}
324 .icon-film{background-position:-192px 0}
325 .icon-th-large{background-position:-216px 0}
325 .icon-th-large{background-position:-216px 0}
326 .icon-th{background-position:-240px 0}
326 .icon-th{background-position:-240px 0}
327 .icon-th-list{background-position:-264px 0}
327 .icon-th-list{background-position:-264px 0}
328 .icon-ok{background-position:-288px 0}
328 .icon-ok{background-position:-288px 0}
329 .icon-remove{background-position:-312px 0}
329 .icon-remove{background-position:-312px 0}
330 .icon-zoom-in{background-position:-336px 0}
330 .icon-zoom-in{background-position:-336px 0}
331 .icon-zoom-out{background-position:-360px 0}
331 .icon-zoom-out{background-position:-360px 0}
332 .icon-off{background-position:-384px 0}
332 .icon-off{background-position:-384px 0}
333 .icon-signal{background-position:-408px 0}
333 .icon-signal{background-position:-408px 0}
334 .icon-cog{background-position:-432px 0}
334 .icon-cog{background-position:-432px 0}
335 .icon-trash{background-position:-456px 0}
335 .icon-trash{background-position:-456px 0}
336 .icon-home{background-position:0 -24px}
336 .icon-home{background-position:0 -24px}
337 .icon-file{background-position:-24px -24px}
337 .icon-file{background-position:-24px -24px}
338 .icon-time{background-position:-48px -24px}
338 .icon-time{background-position:-48px -24px}
339 .icon-road{background-position:-72px -24px}
339 .icon-road{background-position:-72px -24px}
340 .icon-download-alt{background-position:-96px -24px}
340 .icon-download-alt{background-position:-96px -24px}
341 .icon-download{background-position:-120px -24px}
341 .icon-download{background-position:-120px -24px}
342 .icon-upload{background-position:-144px -24px}
342 .icon-upload{background-position:-144px -24px}
343 .icon-inbox{background-position:-168px -24px}
343 .icon-inbox{background-position:-168px -24px}
344 .icon-play-circle{background-position:-192px -24px}
344 .icon-play-circle{background-position:-192px -24px}
345 .icon-repeat{background-position:-216px -24px}
345 .icon-repeat{background-position:-216px -24px}
346 .icon-refresh{background-position:-240px -24px}
346 .icon-refresh{background-position:-240px -24px}
347 .icon-list-alt{background-position:-264px -24px}
347 .icon-list-alt{background-position:-264px -24px}
348 .icon-lock{background-position:-287px -24px}
348 .icon-lock{background-position:-287px -24px}
349 .icon-flag{background-position:-312px -24px}
349 .icon-flag{background-position:-312px -24px}
350 .icon-headphones{background-position:-336px -24px}
350 .icon-headphones{background-position:-336px -24px}
351 .icon-volume-off{background-position:-360px -24px}
351 .icon-volume-off{background-position:-360px -24px}
352 .icon-volume-down{background-position:-384px -24px}
352 .icon-volume-down{background-position:-384px -24px}
353 .icon-volume-up{background-position:-408px -24px}
353 .icon-volume-up{background-position:-408px -24px}
354 .icon-qrcode{background-position:-432px -24px}
354 .icon-qrcode{background-position:-432px -24px}
355 .icon-barcode{background-position:-456px -24px}
355 .icon-barcode{background-position:-456px -24px}
356 .icon-tag{background-position:0 -48px}
356 .icon-tag{background-position:0 -48px}
357 .icon-tags{background-position:-25px -48px}
357 .icon-tags{background-position:-25px -48px}
358 .icon-book{background-position:-48px -48px}
358 .icon-book{background-position:-48px -48px}
359 .icon-bookmark{background-position:-72px -48px}
359 .icon-bookmark{background-position:-72px -48px}
360 .icon-print{background-position:-96px -48px}
360 .icon-print{background-position:-96px -48px}
361 .icon-camera{background-position:-120px -48px}
361 .icon-camera{background-position:-120px -48px}
362 .icon-font{background-position:-144px -48px}
362 .icon-font{background-position:-144px -48px}
363 .icon-bold{background-position:-167px -48px}
363 .icon-bold{background-position:-167px -48px}
364 .icon-italic{background-position:-192px -48px}
364 .icon-italic{background-position:-192px -48px}
365 .icon-text-height{background-position:-216px -48px}
365 .icon-text-height{background-position:-216px -48px}
366 .icon-text-width{background-position:-240px -48px}
366 .icon-text-width{background-position:-240px -48px}
367 .icon-align-left{background-position:-264px -48px}
367 .icon-align-left{background-position:-264px -48px}
368 .icon-align-center{background-position:-288px -48px}
368 .icon-align-center{background-position:-288px -48px}
369 .icon-align-right{background-position:-312px -48px}
369 .icon-align-right{background-position:-312px -48px}
370 .icon-align-justify{background-position:-336px -48px}
370 .icon-align-justify{background-position:-336px -48px}
371 .icon-list{background-position:-360px -48px}
371 .icon-list{background-position:-360px -48px}
372 .icon-indent-left{background-position:-384px -48px}
372 .icon-indent-left{background-position:-384px -48px}
373 .icon-indent-right{background-position:-408px -48px}
373 .icon-indent-right{background-position:-408px -48px}
374 .icon-facetime-video{background-position:-432px -48px}
374 .icon-facetime-video{background-position:-432px -48px}
375 .icon-picture{background-position:-456px -48px}
375 .icon-picture{background-position:-456px -48px}
376 .icon-pencil{background-position:0 -72px}
376 .icon-pencil{background-position:0 -72px}
377 .icon-map-marker{background-position:-24px -72px}
377 .icon-map-marker{background-position:-24px -72px}
378 .icon-adjust{background-position:-48px -72px}
378 .icon-adjust{background-position:-48px -72px}
379 .icon-tint{background-position:-72px -72px}
379 .icon-tint{background-position:-72px -72px}
380 .icon-edit{background-position:-96px -72px}
380 .icon-edit{background-position:-96px -72px}
381 .icon-share{background-position:-120px -72px}
381 .icon-share{background-position:-120px -72px}
382 .icon-check{background-position:-144px -72px}
382 .icon-check{background-position:-144px -72px}
383 .icon-move{background-position:-168px -72px}
383 .icon-move{background-position:-168px -72px}
384 .icon-step-backward{background-position:-192px -72px}
384 .icon-step-backward{background-position:-192px -72px}
385 .icon-fast-backward{background-position:-216px -72px}
385 .icon-fast-backward{background-position:-216px -72px}
386 .icon-backward{background-position:-240px -72px}
386 .icon-backward{background-position:-240px -72px}
387 .icon-play{background-position:-264px -72px}
387 .icon-play{background-position:-264px -72px}
388 .icon-pause{background-position:-288px -72px}
388 .icon-pause{background-position:-288px -72px}
389 .icon-stop{background-position:-312px -72px}
389 .icon-stop{background-position:-312px -72px}
390 .icon-forward{background-position:-336px -72px}
390 .icon-forward{background-position:-336px -72px}
391 .icon-fast-forward{background-position:-360px -72px}
391 .icon-fast-forward{background-position:-360px -72px}
392 .icon-step-forward{background-position:-384px -72px}
392 .icon-step-forward{background-position:-384px -72px}
393 .icon-eject{background-position:-408px -72px}
393 .icon-eject{background-position:-408px -72px}
394 .icon-chevron-left{background-position:-432px -72px}
394 .icon-chevron-left{background-position:-432px -72px}
395 .icon-chevron-right{background-position:-456px -72px}
395 .icon-chevron-right{background-position:-456px -72px}
396 .icon-plus-sign{background-position:0 -96px}
396 .icon-plus-sign{background-position:0 -96px}
397 .icon-minus-sign{background-position:-24px -96px}
397 .icon-minus-sign{background-position:-24px -96px}
398 .icon-remove-sign{background-position:-48px -96px}
398 .icon-remove-sign{background-position:-48px -96px}
399 .icon-ok-sign{background-position:-72px -96px}
399 .icon-ok-sign{background-position:-72px -96px}
400 .icon-question-sign{background-position:-96px -96px}
400 .icon-question-sign{background-position:-96px -96px}
401 .icon-info-sign{background-position:-120px -96px}
401 .icon-info-sign{background-position:-120px -96px}
402 .icon-screenshot{background-position:-144px -96px}
402 .icon-screenshot{background-position:-144px -96px}
403 .icon-remove-circle{background-position:-168px -96px}
403 .icon-remove-circle{background-position:-168px -96px}
404 .icon-ok-circle{background-position:-192px -96px}
404 .icon-ok-circle{background-position:-192px -96px}
405 .icon-ban-circle{background-position:-216px -96px}
405 .icon-ban-circle{background-position:-216px -96px}
406 .icon-arrow-left{background-position:-240px -96px}
406 .icon-arrow-left{background-position:-240px -96px}
407 .icon-arrow-right{background-position:-264px -96px}
407 .icon-arrow-right{background-position:-264px -96px}
408 .icon-arrow-up{background-position:-289px -96px}
408 .icon-arrow-up{background-position:-289px -96px}
409 .icon-arrow-down{background-position:-312px -96px}
409 .icon-arrow-down{background-position:-312px -96px}
410 .icon-share-alt{background-position:-336px -96px}
410 .icon-share-alt{background-position:-336px -96px}
411 .icon-resize-full{background-position:-360px -96px}
411 .icon-resize-full{background-position:-360px -96px}
412 .icon-resize-small{background-position:-384px -96px}
412 .icon-resize-small{background-position:-384px -96px}
413 .icon-plus{background-position:-408px -96px}
413 .icon-plus{background-position:-408px -96px}
414 .icon-minus{background-position:-433px -96px}
414 .icon-minus{background-position:-433px -96px}
415 .icon-asterisk{background-position:-456px -96px}
415 .icon-asterisk{background-position:-456px -96px}
416 .icon-exclamation-sign{background-position:0 -120px}
416 .icon-exclamation-sign{background-position:0 -120px}
417 .icon-gift{background-position:-24px -120px}
417 .icon-gift{background-position:-24px -120px}
418 .icon-leaf{background-position:-48px -120px}
418 .icon-leaf{background-position:-48px -120px}
419 .icon-fire{background-position:-72px -120px}
419 .icon-fire{background-position:-72px -120px}
420 .icon-eye-open{background-position:-96px -120px}
420 .icon-eye-open{background-position:-96px -120px}
421 .icon-eye-close{background-position:-120px -120px}
421 .icon-eye-close{background-position:-120px -120px}
422 .icon-warning-sign{background-position:-144px -120px}
422 .icon-warning-sign{background-position:-144px -120px}
423 .icon-plane{background-position:-168px -120px}
423 .icon-plane{background-position:-168px -120px}
424 .icon-calendar{background-position:-192px -120px}
424 .icon-calendar{background-position:-192px -120px}
425 .icon-random{background-position:-216px -120px;width:16px}
425 .icon-random{background-position:-216px -120px;width:16px}
426 .icon-comment{background-position:-240px -120px}
426 .icon-comment{background-position:-240px -120px}
427 .icon-magnet{background-position:-264px -120px}
427 .icon-magnet{background-position:-264px -120px}
428 .icon-chevron-up{background-position:-288px -120px}
428 .icon-chevron-up{background-position:-288px -120px}
429 .icon-chevron-down{background-position:-313px -119px}
429 .icon-chevron-down{background-position:-313px -119px}
430 .icon-retweet{background-position:-336px -120px}
430 .icon-retweet{background-position:-336px -120px}
431 .icon-shopping-cart{background-position:-360px -120px}
431 .icon-shopping-cart{background-position:-360px -120px}
432 .icon-folder-close{background-position:-384px -120px;width:16px}
432 .icon-folder-close{background-position:-384px -120px;width:16px}
433 .icon-folder-open{background-position:-408px -120px;width:16px}
433 .icon-folder-open{background-position:-408px -120px;width:16px}
434 .icon-resize-vertical{background-position:-432px -119px}
434 .icon-resize-vertical{background-position:-432px -119px}
435 .icon-resize-horizontal{background-position:-456px -118px}
435 .icon-resize-horizontal{background-position:-456px -118px}
436 .icon-hdd{background-position:0 -144px}
436 .icon-hdd{background-position:0 -144px}
437 .icon-bullhorn{background-position:-24px -144px}
437 .icon-bullhorn{background-position:-24px -144px}
438 .icon-bell{background-position:-48px -144px}
438 .icon-bell{background-position:-48px -144px}
439 .icon-certificate{background-position:-72px -144px}
439 .icon-certificate{background-position:-72px -144px}
440 .icon-thumbs-up{background-position:-96px -144px}
440 .icon-thumbs-up{background-position:-96px -144px}
441 .icon-thumbs-down{background-position:-120px -144px}
441 .icon-thumbs-down{background-position:-120px -144px}
442 .icon-hand-right{background-position:-144px -144px}
442 .icon-hand-right{background-position:-144px -144px}
443 .icon-hand-left{background-position:-168px -144px}
443 .icon-hand-left{background-position:-168px -144px}
444 .icon-hand-up{background-position:-192px -144px}
444 .icon-hand-up{background-position:-192px -144px}
445 .icon-hand-down{background-position:-216px -144px}
445 .icon-hand-down{background-position:-216px -144px}
446 .icon-circle-arrow-right{background-position:-240px -144px}
446 .icon-circle-arrow-right{background-position:-240px -144px}
447 .icon-circle-arrow-left{background-position:-264px -144px}
447 .icon-circle-arrow-left{background-position:-264px -144px}
448 .icon-circle-arrow-up{background-position:-288px -144px}
448 .icon-circle-arrow-up{background-position:-288px -144px}
449 .icon-circle-arrow-down{background-position:-312px -144px}
449 .icon-circle-arrow-down{background-position:-312px -144px}
450 .icon-globe{background-position:-336px -144px}
450 .icon-globe{background-position:-336px -144px}
451 .icon-wrench{background-position:-360px -144px}
451 .icon-wrench{background-position:-360px -144px}
452 .icon-tasks{background-position:-384px -144px}
452 .icon-tasks{background-position:-384px -144px}
453 .icon-filter{background-position:-408px -144px}
453 .icon-filter{background-position:-408px -144px}
454 .icon-briefcase{background-position:-432px -144px}
454 .icon-briefcase{background-position:-432px -144px}
455 .icon-fullscreen{background-position:-456px -144px}
455 .icon-fullscreen{background-position:-456px -144px}
456 .dropup,.dropdown{position:relative}
456 .dropup,.dropdown{position:relative}
457 .dropdown-toggle{*margin-bottom:-3px}
457 .dropdown-toggle{*margin-bottom:-3px}
458 .dropdown-toggle:active,.open .dropdown-toggle{outline:0}
458 .dropdown-toggle:active,.open .dropdown-toggle{outline:0}
459 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}
459 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}
460 .dropdown .caret{margin-top:8px;margin-left:2px}
460 .dropdown .caret{margin-top:8px;margin-left:2px}
461 .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
461 .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
462 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
462 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
463 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}
463 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}
464 .dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
464 .dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
465 .dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
465 .dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
466 .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
466 .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
467 .dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default}
467 .dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default}
468 .open{*z-index:1000}.open>.dropdown-menu{display:block}
468 .open{*z-index:1000}.open>.dropdown-menu{display:block}
469 .dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}
469 .dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}
470 .pull-right>.dropdown-menu{right:0;left:auto}
470 .pull-right>.dropdown-menu{right:0;left:auto}
471 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}
471 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}
472 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}
472 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}
473 .dropdown-submenu{position:relative}
473 .dropdown-submenu{position:relative}
474 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px 6px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}
474 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px 6px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}
475 .dropdown-submenu:hover>.dropdown-menu{display:block}
475 .dropdown-submenu:hover>.dropdown-menu{display:block}
476 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:5px 5px 5px 0;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}
476 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:5px 5px 5px 0;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}
477 .dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}
477 .dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}
478 .dropdown-submenu:hover>a:after{border-left-color:#fff}
478 .dropdown-submenu:hover>a:after{border-left-color:#fff}
479 .dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
479 .dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
480 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}
480 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}
481 .typeahead{z-index:1051;margin-top:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
481 .typeahead{z-index:1051;margin-top:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
482 .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}
482 .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}
483 .well-large{padding:24px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
483 .well-large{padding:24px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
484 .well-small{padding:9px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
484 .well-small{padding:9px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
485 .fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}
485 .fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}
486 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}
486 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}
487 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}
487 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}
488 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}
488 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}
489 .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:13px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #fff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #fff, #e6e6e6);background-image:-o-linear-gradient(top, #fff, #e6e6e6);background-image:linear-gradient(to bottom, #fff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}
489 .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:13px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #fff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #fff, #e6e6e6);background-image:-o-linear-gradient(top, #fff, #e6e6e6);background-image:linear-gradient(to bottom, #fff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}
490 .btn:active,.btn.active{background-color:#ccc \9}
490 .btn:active,.btn.active{background-color:#ccc \9}
491 .btn:first-child{*margin-left:0}
491 .btn:first-child{*margin-left:0}
492 .btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}
492 .btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}
493 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
493 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
494 .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
494 .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
495 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
495 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
496 .btn-large{padding:11px 19px;font-size:16.25px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
496 .btn-large{padding:11px 19px;font-size:16.25px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
497 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}
497 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}
498 .btn-small{padding:2px 10px;font-size:11.049999999999999px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
498 .btn-small{padding:2px 10px;font-size:11.049999999999999px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
499 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}
499 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}
500 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}
500 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}
501 .btn-mini{padding:0 6px;font-size:9.75px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
501 .btn-mini{padding:0 6px;font-size:9.75px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
502 .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
502 .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
503 .btn-block+.btn-block{margin-top:5px}
503 .btn-block+.btn-block{margin-top:5px}
504 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}
504 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}
505 .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}
505 .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}
506 .btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}
506 .btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}
507 .btn-primary:active,.btn-primary.active{background-color:#039 \9}
507 .btn-primary:active,.btn-primary.active{background-color:#039 \9}
508 .btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}
508 .btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}
509 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9}
509 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9}
510 .btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}
510 .btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}
511 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9}
511 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9}
512 .btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}
512 .btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}
513 .btn-success:active,.btn-success.active{background-color:#408140 \9}
513 .btn-success:active,.btn-success.active{background-color:#408140 \9}
514 .btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}
514 .btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}
515 .btn-info:active,.btn-info.active{background-color:#24748c \9}
515 .btn-info:active,.btn-info.active{background-color:#24748c \9}
516 .btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444, #222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#222));background-image:-webkit-linear-gradient(top, #444, #222);background-image:-o-linear-gradient(top, #444, #222);background-image:linear-gradient(to bottom, #444, #222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}
516 .btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444, #222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#222));background-image:-webkit-linear-gradient(top, #444, #222);background-image:-o-linear-gradient(top, #444, #222);background-image:linear-gradient(to bottom, #444, #222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}
517 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}
517 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}
518 button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}
518 button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}
519 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}
519 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}
520 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}
520 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}
521 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}
521 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}
522 .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
522 .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
523 .btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
523 .btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
524 .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}
524 .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}
525 .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}
525 .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}
526 .btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em}.btn-group:first-child{*margin-left:0}
526 .btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em}.btn-group:first-child{*margin-left:0}
527 .btn-group+.btn-group{margin-left:5px}
527 .btn-group+.btn-group{margin-left:5px}
528 .btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}
528 .btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}
529 .btn-group>.btn{position:relative;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
529 .btn-group>.btn{position:relative;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
530 .btn-group>.btn+.btn{margin-left:-1px}
530 .btn-group>.btn+.btn{margin-left:-1px}
531 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px}
531 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px}
532 .btn-group>.btn-mini{font-size:9.75px}
532 .btn-group>.btn-mini{font-size:9.75px}
533 .btn-group>.btn-small{font-size:11.049999999999999px}
533 .btn-group>.btn-small{font-size:11.049999999999999px}
534 .btn-group>.btn-large{font-size:16.25px}
534 .btn-group>.btn-large{font-size:16.25px}
535 .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
535 .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
536 .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
536 .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
537 .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
537 .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
538 .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
538 .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
539 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}
539 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}
540 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}
540 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}
541 .btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px}
541 .btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px}
542 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px}
542 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px}
543 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}
543 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}
544 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px}
544 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px}
545 .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
545 .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
546 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}
546 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}
547 .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}
547 .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}
548 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}
548 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}
549 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}
549 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}
550 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}
550 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}
551 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}
551 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}
552 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}
552 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}
553 .btn .caret{margin-top:8px;margin-left:0}
553 .btn .caret{margin-top:8px;margin-left:0}
554 .btn-large .caret{margin-top:6px}
554 .btn-large .caret{margin-top:6px}
555 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}
555 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}
556 .btn-mini .caret,.btn-small .caret{margin-top:8px}
556 .btn-mini .caret,.btn-small .caret{margin-top:8px}
557 .dropup .btn-large .caret{border-bottom-width:5px}
557 .dropup .btn-large .caret{border-bottom-width:5px}
558 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}
558 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}
559 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}
559 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}
560 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
560 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
561 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}
561 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}
562 .btn-group-vertical>.btn:first-child{border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}
562 .btn-group-vertical>.btn:first-child{border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}
563 .btn-group-vertical>.btn:last-child{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}
563 .btn-group-vertical>.btn:last-child{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}
564 .btn-group-vertical>.btn-large:first-child{border-radius:6px 6px 0 0;-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}
564 .btn-group-vertical>.btn-large:first-child{border-radius:6px 6px 0 0;-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}
565 .btn-group-vertical>.btn-large:last-child{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
565 .btn-group-vertical>.btn-large:last-child{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
566 .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
566 .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
567 .alert,.alert h4{color:#c09853}
567 .alert,.alert h4{color:#c09853}
568 .alert h4{margin:0}
568 .alert h4{margin:0}
569 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}
569 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}
570 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}
570 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}
571 .alert-success h4{color:#468847}
571 .alert-success h4{color:#468847}
572 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}
572 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}
573 .alert-danger h4,.alert-error h4{color:#b94a48}
573 .alert-danger h4,.alert-error h4{color:#b94a48}
574 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}
574 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}
575 .alert-info h4{color:#3a87ad}
575 .alert-info h4{color:#3a87ad}
576 .alert-block{padding-top:14px;padding-bottom:14px}
576 .alert-block{padding-top:14px;padding-bottom:14px}
577 .alert-block>p,.alert-block>ul{margin-bottom:0}
577 .alert-block>p,.alert-block>ul{margin-bottom:0}
578 .alert-block p+p{margin-top:5px}
578 .alert-block p+p{margin-top:5px}
579 .nav{margin-left:0;margin-bottom:20px;list-style:none}
579 .nav{margin-left:0;margin-bottom:20px;list-style:none}
580 .nav>li>a{display:block}
580 .nav>li>a{display:block}
581 .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
581 .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
582 .nav>li>a>img{max-width:none}
582 .nav>li>a>img{max-width:none}
583 .nav>.pull-right{float:right}
583 .nav>.pull-right{float:right}
584 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}
584 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}
585 .nav li+.nav-header{margin-top:9px}
585 .nav li+.nav-header{margin-top:9px}
586 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}
586 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}
587 .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}
587 .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}
588 .nav-list>li>a{padding:3px 15px}
588 .nav-list>li>a{padding:3px 15px}
589 .nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}
589 .nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}
590 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}
590 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}
591 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
591 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
592 .nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0}
592 .nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0}
593 .nav-tabs:after,.nav-pills:after{clear:both}
593 .nav-tabs:after,.nav-pills:after{clear:both}
594 .nav-tabs>li,.nav-pills>li{float:left}
594 .nav-tabs>li,.nav-pills>li{float:left}
595 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}
595 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}
596 .nav-tabs{border-bottom:1px solid #ddd}
596 .nav-tabs{border-bottom:1px solid #ddd}
597 .nav-tabs>li{margin-bottom:-1px}
597 .nav-tabs>li{margin-bottom:-1px}
598 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}
598 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}
599 .nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
599 .nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
600 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
600 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
601 .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}
601 .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}
602 .nav-stacked>li{float:none}
602 .nav-stacked>li{float:none}
603 .nav-stacked>li>a{margin-right:0}
603 .nav-stacked>li>a{margin-right:0}
604 .nav-tabs.nav-stacked{border-bottom:0}
604 .nav-tabs.nav-stacked{border-bottom:0}
605 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
605 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
606 .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
606 .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
607 .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
607 .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
608 .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2}
608 .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2}
609 .nav-pills.nav-stacked>li>a{margin-bottom:3px}
609 .nav-pills.nav-stacked>li>a{margin-bottom:3px}
610 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}
610 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}
611 .nav-tabs .dropdown-menu{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
611 .nav-tabs .dropdown-menu{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
612 .nav-pills .dropdown-menu{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
612 .nav-pills .dropdown-menu{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
613 .nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}
613 .nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}
614 .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}
614 .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}
615 .nav-tabs .dropdown-toggle .caret{margin-top:8px}
615 .nav-tabs .dropdown-toggle .caret{margin-top:8px}
616 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
616 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
617 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
617 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
618 .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}
618 .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}
619 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}
619 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}
620 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}
620 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}
621 .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}
621 .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}
622 .tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0}
622 .tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0}
623 .tabbable:after{clear:both}
623 .tabbable:after{clear:both}
624 .tab-content{overflow:auto}
624 .tab-content{overflow:auto}
625 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}
625 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}
626 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
626 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
627 .tab-content>.active,.pill-content>.active{display:block}
627 .tab-content>.active,.pill-content>.active{display:block}
628 .tabs-below>.nav-tabs{border-top:1px solid #ddd}
628 .tabs-below>.nav-tabs{border-top:1px solid #ddd}
629 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}
629 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}
630 .tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd}
630 .tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd}
631 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}
631 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}
632 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}
632 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}
633 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}
633 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}
634 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}
634 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}
635 .tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
635 .tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
636 .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}
636 .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}
637 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}
637 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}
638 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}
638 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}
639 .tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
639 .tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
640 .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}
640 .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}
641 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}
641 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}
642 .nav>.disabled>a{color:#999}
642 .nav>.disabled>a{color:#999}
643 .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default}
643 .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default}
644 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2}
644 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2}
645 .navbar-inner{min-height:36px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #fff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #fff, #f2f2f2);background-image:-o-linear-gradient(top, #fff, #f2f2f2);background-image:linear-gradient(to bottom, #fff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);*zoom:1}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0}
645 .navbar-inner{min-height:36px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #fff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #fff, #f2f2f2);background-image:-o-linear-gradient(top, #fff, #f2f2f2);background-image:linear-gradient(to bottom, #fff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);*zoom:1}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0}
646 .navbar-inner:after{clear:both}
646 .navbar-inner:after{clear:both}
647 .navbar .container{width:auto}
647 .navbar .container{width:auto}
648 .nav-collapse.collapse{height:auto;overflow:visible}
648 .nav-collapse.collapse{height:auto;overflow:visible}
649 .navbar .brand{float:left;display:block;padding:8px 20px 8px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}
649 .navbar .brand{float:left;display:block;padding:8px 20px 8px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}
650 .navbar-text{margin-bottom:0;line-height:36px;color:#777}
650 .navbar-text{margin-bottom:0;line-height:36px;color:#777}
651 .navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}
651 .navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}
652 .navbar .divider-vertical{height:36px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}
652 .navbar .divider-vertical{height:36px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}
653 .navbar .btn,.navbar .btn-group{margin-top:3px}
653 .navbar .btn,.navbar .btn-group{margin-top:3px}
654 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}
654 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}
655 .navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0}
655 .navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0}
656 .navbar-form:after{clear:both}
656 .navbar-form:after{clear:both}
657 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:3px}
657 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:3px}
658 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}
658 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}
659 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}
659 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}
660 .navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}
660 .navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}
661 .navbar-search{position:relative;float:left;margin-top:3px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
661 .navbar-search{position:relative;float:left;margin-top:3px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
662 .navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
662 .navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
663 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}
663 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}
664 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}
664 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}
665 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}
665 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}
666 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
666 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
667 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
667 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
668 .navbar-fixed-top{top:0}
668 .navbar-fixed-top{top:0}
669 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1)}
669 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1)}
670 .navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1)}
670 .navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1)}
671 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}
671 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}
672 .navbar .nav.pull-right{float:right;margin-right:0}
672 .navbar .nav.pull-right{float:right;margin-right:0}
673 .navbar .nav>li{float:left}
673 .navbar .nav>li{float:left}
674 .navbar .nav>li>a{float:none;padding:8px 15px 8px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}
674 .navbar .nav>li>a{float:none;padding:8px 15px 8px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}
675 .navbar .nav .dropdown-toggle .caret{margin-top:8px}
675 .navbar .nav .dropdown-toggle .caret{margin-top:8px}
676 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}
676 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}
677 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}
677 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}
678 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}
678 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}
679 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}
679 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}
680 .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}
680 .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}
681 .btn-navbar .icon-bar+.icon-bar{margin-top:3px}
681 .btn-navbar .icon-bar+.icon-bar{margin-top:3px}
682 .navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:9px}
682 .navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:9px}
683 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}
683 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}
684 .navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);border-bottom:0;bottom:-7px;top:auto}
684 .navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);border-bottom:0;bottom:-7px;top:auto}
685 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}
685 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}
686 .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}
686 .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}
687 .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555}
687 .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555}
688 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}
688 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}
689 .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
689 .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
690 .navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px}
690 .navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px}
691 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px}
691 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px}
692 .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
692 .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
693 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222, #111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222), to(#111));background-image:-webkit-linear-gradient(top, #222, #111);background-image:-o-linear-gradient(top, #222, #111);background-image:linear-gradient(to bottom, #222, #111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525}
693 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222, #111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222), to(#111));background-image:-webkit-linear-gradient(top, #222, #111);background-image:-o-linear-gradient(top, #222, #111);background-image:linear-gradient(to bottom, #222, #111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525}
694 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}
694 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}
695 .navbar-inverse .brand{color:#999}
695 .navbar-inverse .brand{color:#999}
696 .navbar-inverse .navbar-text{color:#999}
696 .navbar-inverse .navbar-text{color:#999}
697 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}
697 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}
698 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}
698 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}
699 .navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}
699 .navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}
700 .navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}
700 .navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}
701 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111;color:#fff}
701 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111;color:#fff}
702 .navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}
702 .navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}
703 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}
703 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}
704 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
704 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
705 .navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}
705 .navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}
706 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}
706 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}
707 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}
707 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}
708 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15);outline:0}
708 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15);outline:0}
709 .navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}
709 .navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}
710 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}
710 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}
711 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #fff}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}
711 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #fff}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}
712 .breadcrumb>.active{color:#999}
712 .breadcrumb>.active{color:#999}
713 .pagination{margin:20px 0}
713 .pagination{margin:20px 0}
714 .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}
714 .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}
715 .pagination ul>li{display:inline}
715 .pagination ul>li{display:inline}
716 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}
716 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}
717 .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}
717 .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}
718 .pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}
718 .pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}
719 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;background-color:transparent;cursor:default}
719 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;background-color:transparent;cursor:default}
720 .pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
720 .pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
721 .pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
721 .pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
722 .pagination-centered{text-align:center}
722 .pagination-centered{text-align:center}
723 .pagination-right{text-align:right}
723 .pagination-right{text-align:right}
724 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px}
724 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px}
725 .pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
725 .pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
726 .pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
726 .pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
727 .pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px}
727 .pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px}
728 .pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px}
728 .pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px}
729 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px}
729 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px}
730 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px}
730 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px}
731 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1}.pager:before,.pager:after{display:table;content:"";line-height:0}
731 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1}.pager:before,.pager:after{display:table;content:"";line-height:0}
732 .pager:after{clear:both}
732 .pager:after{clear:both}
733 .pager li{display:inline}
733 .pager li{display:inline}
734 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
734 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
735 .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}
735 .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}
736 .pager .next>a,.pager .next>span{float:right}
736 .pager .next>a,.pager .next>span{float:right}
737 .pager .previous>a,.pager .previous>span{float:left}
737 .pager .previous>a,.pager .previous>span{float:left}
738 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}
738 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}
739 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}
739 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}
740 .modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}
740 .modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}
741 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%}
741 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%}
742 .modal.fade.in{top:10%}
742 .modal.fade.in{top:10%}
743 .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}
743 .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}
744 .modal-header h3{margin:0;line-height:30px}
744 .modal-header h3{margin:0;line-height:30px}
745 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px}
745 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px}
746 .modal-form{margin-bottom:0}
746 .modal-form{margin-bottom:0}
747 .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff;*zoom:1}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0}
747 .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff;*zoom:1}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0}
748 .modal-footer:after{clear:both}
748 .modal-footer:after{clear:both}
749 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}
749 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}
750 .modal-footer .btn-group .btn+.btn{margin-left:-1px}
750 .modal-footer .btn-group .btn+.btn{margin-left:-1px}
751 .modal-footer .btn-block+.btn-block{margin-left:0}
751 .modal-footer .btn-block+.btn-block{margin-left:0}
752 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}
752 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}
753 .tooltip.top{margin-top:-3px;padding:5px 0}
753 .tooltip.top{margin-top:-3px;padding:5px 0}
754 .tooltip.right{margin-left:3px;padding:0 5px}
754 .tooltip.right{margin-left:3px;padding:0 5px}
755 .tooltip.bottom{margin-top:3px;padding:5px 0}
755 .tooltip.bottom{margin-top:3px;padding:5px 0}
756 .tooltip.left{margin-left:-3px;padding:0 5px}
756 .tooltip.left{margin-left:-3px;padding:0 5px}
757 .tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
757 .tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
758 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}
758 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}
759 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}
759 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}
760 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}
760 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}
761 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}
761 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}
762 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}
762 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}
763 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}
763 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}
764 .popover.right{margin-left:10px}
764 .popover.right{margin-left:10px}
765 .popover.bottom{margin-top:10px}
765 .popover.bottom{margin-top:10px}
766 .popover.left{margin-left:-10px}
766 .popover.left{margin-left:-10px}
767 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}
767 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}
768 .popover-content{padding:9px 14px}
768 .popover-content{padding:9px 14px}
769 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}
769 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}
770 .popover .arrow{border-width:11px}
770 .popover .arrow{border-width:11px}
771 .popover .arrow:after{border-width:10px;content:""}
771 .popover .arrow:after{border-width:10px;content:""}
772 .popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}
772 .popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}
773 .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}
773 .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}
774 .popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}
774 .popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}
775 .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}
775 .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}
776 .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0}
776 .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0}
777 .thumbnails:after{clear:both}
777 .thumbnails:after{clear:both}
778 .row-fluid .thumbnails{margin-left:0}
778 .row-fluid .thumbnails{margin-left:0}
779 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}
779 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}
780 .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
780 .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
781 a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}
781 a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}
782 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}
782 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}
783 .thumbnail .caption{padding:9px;color:#555}
783 .thumbnail .caption{padding:9px;color:#555}
784 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1}
784 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1}
785 .media,.media .media{margin-top:15px}
785 .media,.media .media{margin-top:15px}
786 .media:first-child{margin-top:0}
786 .media:first-child{margin-top:0}
787 .media-object{display:block}
787 .media-object{display:block}
788 .media-heading{margin:0 0 5px}
788 .media-heading{margin:0 0 5px}
789 .media>.pull-left{margin-right:10px}
789 .media>.pull-left{margin-right:10px}
790 .media>.pull-right{margin-left:10px}
790 .media>.pull-right{margin-left:10px}
791 .media-list{margin-left:0;list-style:none}
791 .media-list{margin-left:0;list-style:none}
792 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#999}
792 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#999}
793 .label{border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
793 .label{border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
794 .badge{padding-left:9px;padding-right:9px;border-radius:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}
794 .badge{padding-left:9px;padding-right:9px;border-radius:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}
795 .label:empty,.badge:empty{display:none}
795 .label:empty,.badge:empty{display:none}
796 a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
796 a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
797 .label-important,.badge-important{background-color:#b94a48}
797 .label-important,.badge-important{background-color:#b94a48}
798 .label-important[href],.badge-important[href]{background-color:#953b39}
798 .label-important[href],.badge-important[href]{background-color:#953b39}
799 .label-warning,.badge-warning{background-color:#f89406}
799 .label-warning,.badge-warning{background-color:#f89406}
800 .label-warning[href],.badge-warning[href]{background-color:#c67605}
800 .label-warning[href],.badge-warning[href]{background-color:#c67605}
801 .label-success,.badge-success{background-color:#468847}
801 .label-success,.badge-success{background-color:#468847}
802 .label-success[href],.badge-success[href]{background-color:#356635}
802 .label-success[href],.badge-success[href]{background-color:#356635}
803 .label-info,.badge-info{background-color:#3a87ad}
803 .label-info,.badge-info{background-color:#3a87ad}
804 .label-info[href],.badge-info[href]{background-color:#2d6987}
804 .label-info[href],.badge-info[href]{background-color:#2d6987}
805 .label-inverse,.badge-inverse{background-color:#333}
805 .label-inverse,.badge-inverse{background-color:#333}
806 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}
806 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}
807 .btn .label,.btn .badge{position:relative;top:-1px}
807 .btn .label,.btn .badge{position:relative;top:-1px}
808 .btn-mini .label,.btn-mini .badge{top:0}
808 .btn-mini .label,.btn-mini .badge{top:0}
809 @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0} to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
809 @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0} to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
810 .progress .bar{width:0;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}
810 .progress .bar{width:0;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}
811 .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)}
811 .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)}
812 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}
812 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}
813 .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}
813 .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}
814 .progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0)}
814 .progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0)}
815 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
815 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
816 .progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0)}
816 .progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0)}
817 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
817 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
818 .progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0)}
818 .progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0)}
819 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
819 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
820 .progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0)}
820 .progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0)}
821 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
821 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
822 .accordion{margin-bottom:20px}
822 .accordion{margin-bottom:20px}
823 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
823 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
824 .accordion-heading{border-bottom:0}
824 .accordion-heading{border-bottom:0}
825 .accordion-heading .accordion-toggle{display:block;padding:8px 15px}
825 .accordion-heading .accordion-toggle{display:block;padding:8px 15px}
826 .accordion-toggle{cursor:pointer}
826 .accordion-toggle{cursor:pointer}
827 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}
827 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}
828 .carousel{position:relative;margin-bottom:20px;line-height:1}
828 .carousel{position:relative;margin-bottom:20px;line-height:1}
829 .carousel-inner{overflow:hidden;width:100%;position:relative}
829 .carousel-inner{overflow:hidden;width:100%;position:relative}
830 .carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}
830 .carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}
831 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}
831 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}
832 .carousel-inner>.active{left:0}
832 .carousel-inner>.active{left:0}
833 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}
833 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}
834 .carousel-inner>.next{left:100%}
834 .carousel-inner>.next{left:100%}
835 .carousel-inner>.prev{left:-100%}
835 .carousel-inner>.prev{left:-100%}
836 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}
836 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}
837 .carousel-inner>.active.left{left:-100%}
837 .carousel-inner>.active.left{left:-100%}
838 .carousel-inner>.active.right{left:100%}
838 .carousel-inner>.active.right{left:100%}
839 .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{left:auto;right:15px}
839 .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{left:auto;right:15px}
840 .carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}
840 .carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}
841 .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}
841 .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}
842 .carousel-indicators .active{background-color:#fff}
842 .carousel-indicators .active{background-color:#fff}
843 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}
843 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}
844 .carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}
844 .carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}
845 .carousel-caption h4{margin:0 0 5px}
845 .carousel-caption h4{margin:0 0 5px}
846 .carousel-caption p{margin-bottom:0}
846 .carousel-caption p{margin-bottom:0}
847 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px}
847 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px}
848 .hero-unit li{line-height:30px}
848 .hero-unit li{line-height:30px}
849 .pull-right{float:right}
849 .pull-right{float:right}
850 .pull-left{float:left}
850 .pull-left{float:left}
851 .hide{display:none}
851 .hide{display:none}
852 .show{display:block}
852 .show{display:block}
853 .invisible{visibility:hidden}
853 .invisible{visibility:hidden}
854 .affix{position:fixed}
854 .affix{position:fixed}
855 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
855 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
856 .clearfix:after{clear:both}
856 .clearfix:after{clear:both}
857 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
857 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
858 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
858 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
859 @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}
859 @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}
860 .visible-phone{display:none !important}
860 .visible-phone{display:none !important}
861 .visible-tablet{display:none !important}
861 .visible-tablet{display:none !important}
862 .hidden-desktop{display:none !important}
862 .hidden-desktop{display:none !important}
863 .visible-desktop{display:inherit !important}
863 .visible-desktop{display:inherit !important}
864 @media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-tablet{display:inherit !important} .hidden-tablet{display:none !important}}@media (max-width:767px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-phone{display:inherit !important} .hidden-phone{display:none !important}}.visible-print{display:none !important}
864 @media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-tablet{display:inherit !important} .hidden-tablet{display:none !important}}@media (max-width:767px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-phone{display:inherit !important} .hidden-phone{display:none !important}}.visible-print{display:none !important}
865 @media print{.visible-print{display:inherit !important} .hidden-print{display:none !important}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:30px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px} .span12{width:1170px} .span11{width:1070px} .span10{width:970px} .span9{width:870px} .span8{width:770px} .span7{width:670px} .span6{width:570px} .span5{width:470px} .span4{width:370px} .span3{width:270px} .span2{width:170px} .span1{width:70px} .offset12{margin-left:1230px} .offset11{margin-left:1130px} .offset10{margin-left:1030px} .offset9{margin-left:930px} .offset8{margin-left:830px} .offset7{margin-left:730px} .offset6{margin-left:630px} .offset5{margin-left:530px} .offset4{margin-left:430px} .offset3{margin-left:330px} .offset2{margin-left:230px} .offset1{margin-left:130px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:30px} input.span12,textarea.span12,.uneditable-input.span12{width:1156px} input.span11,textarea.span11,.uneditable-input.span11{width:1056px} input.span10,textarea.span10,.uneditable-input.span10{width:956px} input.span9,textarea.span9,.uneditable-input.span9{width:856px} input.span8,textarea.span8,.uneditable-input.span8{width:756px} input.span7,textarea.span7,.uneditable-input.span7{width:656px} input.span6,textarea.span6,.uneditable-input.span6{width:556px} input.span5,textarea.span5,.uneditable-input.span5{width:456px} input.span4,textarea.span4,.uneditable-input.span4{width:356px} input.span3,textarea.span3,.uneditable-input.span3{width:256px} input.span2,textarea.span2,.uneditable-input.span2{width:156px} input.span1,textarea.span1,.uneditable-input.span1{width:56px} .thumbnails{margin-left:-30px} .thumbnails>li{margin-left:30px} .row-fluid .thumbnails{margin-left:0}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:20px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px} .span12{width:724px} .span11{width:662px} .span10{width:600px} .span9{width:538px} .span8{width:476px} .span7{width:414px} .span6{width:352px} .span5{width:290px} .span4{width:228px} .span3{width:166px} .span2{width:104px} .span1{width:42px} .offset12{margin-left:764px} .offset11{margin-left:702px} .offset10{margin-left:640px} .offset9{margin-left:578px} .offset8{margin-left:516px} .offset7{margin-left:454px} .offset6{margin-left:392px} .offset5{margin-left:330px} .offset4{margin-left:268px} .offset3{margin-left:206px} .offset2{margin-left:144px} .offset1{margin-left:82px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:20px} input.span12,textarea.span12,.uneditable-input.span12{width:710px} input.span11,textarea.span11,.uneditable-input.span11{width:648px} input.span10,textarea.span10,.uneditable-input.span10{width:586px} input.span9,textarea.span9,.uneditable-input.span9{width:524px} input.span8,textarea.span8,.uneditable-input.span8{width:462px} input.span7,textarea.span7,.uneditable-input.span7{width:400px} input.span6,textarea.span6,.uneditable-input.span6{width:338px} input.span5,textarea.span5,.uneditable-input.span5{width:276px} input.span4,textarea.span4,.uneditable-input.span4{width:214px} input.span3,textarea.span3,.uneditable-input.span3{width:152px} input.span2,textarea.span2,.uneditable-input.span2{width:90px} input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media (max-width:767px){body{padding-left:20px;padding-right:20px} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px} .container-fluid{padding:0} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left} .dl-horizontal dd{margin-left:0} .container{width:auto} .row-fluid{width:100%} .row,.thumbnails{margin-left:0} .thumbnails>li{float:none;margin-left:0} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .row-fluid [class*="offset"]:first-child{margin-left:0} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto} .controls-row [class*="span"]+[class*="span"]{margin-left:0} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0}.modal.fade{top:-100px} .modal.fade.in{top:20px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0)} .page-header h1 small{display:block;line-height:20px} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left} .form-horizontal .controls{margin-left:0} .form-horizontal .control-list{padding-top:0} .form-horizontal .form-actions{padding-left:10px;padding-right:10px} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px} .media-object{margin-right:0;margin-left:0} .modal{top:10px;left:10px;right:10px} .modal-header .close{padding:10px;margin:-10px} .carousel-caption{position:static}}@media (max-width:979px){body{padding-top:0} .navbar-fixed-top,.navbar-fixed-bottom{position:static} .navbar-fixed-top{margin-bottom:20px} .navbar-fixed-bottom{margin-top:20px} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px} .navbar .container{width:auto;padding:0} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px} .nav-collapse{clear:both} .nav-collapse .nav{float:none;margin:0 0 10px} .nav-collapse .nav>li{float:none} .nav-collapse .nav>li>a{margin-bottom:2px} .nav-collapse .nav>.divider-vertical{display:none} .nav-collapse .nav .nav-header{color:#777;text-shadow:none} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111} .nav-collapse.in .btn-group{margin-top:5px;padding:0} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} .nav-collapse .open>.dropdown-menu{display:block} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none} .nav-collapse .dropdown-menu .divider{display:none} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0} .navbar .btn-navbar{display:block} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px}}@media (min-width:979px + 1){.nav-collapse.collapse{height:auto !important;overflow:visible !important}}@font-face{font-family:'FontAwesome';src:url('../components/font-awesome/font/fontawesome-webfont.eot?v=3.2.1');src:url('../components/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../components/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../components/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../components/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}
865 @media print{.visible-print{display:inherit !important} .hidden-print{display:none !important}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:30px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px} .span12{width:1170px} .span11{width:1070px} .span10{width:970px} .span9{width:870px} .span8{width:770px} .span7{width:670px} .span6{width:570px} .span5{width:470px} .span4{width:370px} .span3{width:270px} .span2{width:170px} .span1{width:70px} .offset12{margin-left:1230px} .offset11{margin-left:1130px} .offset10{margin-left:1030px} .offset9{margin-left:930px} .offset8{margin-left:830px} .offset7{margin-left:730px} .offset6{margin-left:630px} .offset5{margin-left:530px} .offset4{margin-left:430px} .offset3{margin-left:330px} .offset2{margin-left:230px} .offset1{margin-left:130px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:30px} input.span12,textarea.span12,.uneditable-input.span12{width:1156px} input.span11,textarea.span11,.uneditable-input.span11{width:1056px} input.span10,textarea.span10,.uneditable-input.span10{width:956px} input.span9,textarea.span9,.uneditable-input.span9{width:856px} input.span8,textarea.span8,.uneditable-input.span8{width:756px} input.span7,textarea.span7,.uneditable-input.span7{width:656px} input.span6,textarea.span6,.uneditable-input.span6{width:556px} input.span5,textarea.span5,.uneditable-input.span5{width:456px} input.span4,textarea.span4,.uneditable-input.span4{width:356px} input.span3,textarea.span3,.uneditable-input.span3{width:256px} input.span2,textarea.span2,.uneditable-input.span2{width:156px} input.span1,textarea.span1,.uneditable-input.span1{width:56px} .thumbnails{margin-left:-30px} .thumbnails>li{margin-left:30px} .row-fluid .thumbnails{margin-left:0}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:20px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px} .span12{width:724px} .span11{width:662px} .span10{width:600px} .span9{width:538px} .span8{width:476px} .span7{width:414px} .span6{width:352px} .span5{width:290px} .span4{width:228px} .span3{width:166px} .span2{width:104px} .span1{width:42px} .offset12{margin-left:764px} .offset11{margin-left:702px} .offset10{margin-left:640px} .offset9{margin-left:578px} .offset8{margin-left:516px} .offset7{margin-left:454px} .offset6{margin-left:392px} .offset5{margin-left:330px} .offset4{margin-left:268px} .offset3{margin-left:206px} .offset2{margin-left:144px} .offset1{margin-left:82px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:20px} input.span12,textarea.span12,.uneditable-input.span12{width:710px} input.span11,textarea.span11,.uneditable-input.span11{width:648px} input.span10,textarea.span10,.uneditable-input.span10{width:586px} input.span9,textarea.span9,.uneditable-input.span9{width:524px} input.span8,textarea.span8,.uneditable-input.span8{width:462px} input.span7,textarea.span7,.uneditable-input.span7{width:400px} input.span6,textarea.span6,.uneditable-input.span6{width:338px} input.span5,textarea.span5,.uneditable-input.span5{width:276px} input.span4,textarea.span4,.uneditable-input.span4{width:214px} input.span3,textarea.span3,.uneditable-input.span3{width:152px} input.span2,textarea.span2,.uneditable-input.span2{width:90px} input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media (max-width:767px){body{padding-left:20px;padding-right:20px} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px} .container-fluid{padding:0} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left} .dl-horizontal dd{margin-left:0} .container{width:auto} .row-fluid{width:100%} .row,.thumbnails{margin-left:0} .thumbnails>li{float:none;margin-left:0} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .row-fluid [class*="offset"]:first-child{margin-left:0} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto} .controls-row [class*="span"]+[class*="span"]{margin-left:0} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0}.modal.fade{top:-100px} .modal.fade.in{top:20px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0)} .page-header h1 small{display:block;line-height:20px} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left} .form-horizontal .controls{margin-left:0} .form-horizontal .control-list{padding-top:0} .form-horizontal .form-actions{padding-left:10px;padding-right:10px} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px} .media-object{margin-right:0;margin-left:0} .modal{top:10px;left:10px;right:10px} .modal-header .close{padding:10px;margin:-10px} .carousel-caption{position:static}}@media (max-width:979px){body{padding-top:0} .navbar-fixed-top,.navbar-fixed-bottom{position:static} .navbar-fixed-top{margin-bottom:20px} .navbar-fixed-bottom{margin-top:20px} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px} .navbar .container{width:auto;padding:0} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px} .nav-collapse{clear:both} .nav-collapse .nav{float:none;margin:0 0 10px} .nav-collapse .nav>li{float:none} .nav-collapse .nav>li>a{margin-bottom:2px} .nav-collapse .nav>.divider-vertical{display:none} .nav-collapse .nav .nav-header{color:#777;text-shadow:none} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111} .nav-collapse.in .btn-group{margin-top:5px;padding:0} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} .nav-collapse .open>.dropdown-menu{display:block} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none} .nav-collapse .dropdown-menu .divider{display:none} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0} .navbar .btn-navbar{display:block} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px}}@media (min-width:979px + 1){.nav-collapse.collapse{height:auto !important;overflow:visible !important}}@font-face{font-family:'FontAwesome';src:url('../components/font-awesome/font/fontawesome-webfont.eot?v=3.2.1');src:url('../components/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../components/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../components/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../components/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}
866 [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}
866 [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}
867 .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}
867 .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}
868 a [class^="icon-"],a [class*=" icon-"]{display:inline}
868 a [class^="icon-"],a [class*=" icon-"]{display:inline}
869 [class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}
869 [class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}
870 .icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}
870 .icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}
871 .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}
871 .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}
872 [class^="icon-"].hide,[class*=" icon-"].hide{display:none}
872 [class^="icon-"].hide,[class*=" icon-"].hide{display:none}
873 .icon-muted{color:#eee}
873 .icon-muted{color:#eee}
874 .icon-light{color:#fff}
874 .icon-light{color:#fff}
875 .icon-dark{color:#333}
875 .icon-dark{color:#333}
876 .icon-border{border:solid 1px #eee;padding:.2em .25em .15em;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
876 .icon-border{border:solid 1px #eee;padding:.2em .25em .15em;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
877 .icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
877 .icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
878 .icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
878 .icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
879 .icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
879 .icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
880 .icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;border-radius:7px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}
880 .icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;border-radius:7px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}
881 .pull-right{float:right}
881 .pull-right{float:right}
882 .pull-left{float:left}
882 .pull-left{float:left}
883 [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}
883 [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}
884 [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}
884 [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}
885 [class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}
885 [class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}
886 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}
886 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}
887 .btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}
887 .btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}
888 .btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}
888 .btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}
889 .nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}
889 .nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}
890 .btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}
890 .btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}
891 .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}
891 .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}
892 .btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}
892 .btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}
893 .btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}
893 .btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}
894 .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}
894 .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}
895 .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}
895 .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}
896 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}
896 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}
897 .icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}
897 .icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}
898 .icon-stack .icon-stack-base{font-size:2em;*line-height:1em}
898 .icon-stack .icon-stack-base{font-size:2em;*line-height:1em}
899 .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}
899 .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}
900 a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}
900 a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}
901 @-moz-keyframes spin{0%{-moz-transform:rotate(0deg)} 100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)} 100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)} 100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)} 100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)} 100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}
901 @-moz-keyframes spin{0%{-moz-transform:rotate(0deg)} 100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)} 100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)} 100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)} 100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)} 100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}
902 .icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}
902 .icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}
903 .icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}
903 .icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}
904 .icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}
904 .icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}
905 .icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}
905 .icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}
906 a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}
906 a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}
907 .icon-glass:before{content:"\f000"}
907 .icon-glass:before{content:"\f000"}
908 .icon-music:before{content:"\f001"}
908 .icon-music:before{content:"\f001"}
909 .icon-search:before{content:"\f002"}
909 .icon-search:before{content:"\f002"}
910 .icon-envelope-alt:before{content:"\f003"}
910 .icon-envelope-alt:before{content:"\f003"}
911 .icon-heart:before{content:"\f004"}
911 .icon-heart:before{content:"\f004"}
912 .icon-star:before{content:"\f005"}
912 .icon-star:before{content:"\f005"}
913 .icon-star-empty:before{content:"\f006"}
913 .icon-star-empty:before{content:"\f006"}
914 .icon-user:before{content:"\f007"}
914 .icon-user:before{content:"\f007"}
915 .icon-film:before{content:"\f008"}
915 .icon-film:before{content:"\f008"}
916 .icon-th-large:before{content:"\f009"}
916 .icon-th-large:before{content:"\f009"}
917 .icon-th:before{content:"\f00a"}
917 .icon-th:before{content:"\f00a"}
918 .icon-th-list:before{content:"\f00b"}
918 .icon-th-list:before{content:"\f00b"}
919 .icon-ok:before{content:"\f00c"}
919 .icon-ok:before{content:"\f00c"}
920 .icon-remove:before{content:"\f00d"}
920 .icon-remove:before{content:"\f00d"}
921 .icon-zoom-in:before{content:"\f00e"}
921 .icon-zoom-in:before{content:"\f00e"}
922 .icon-zoom-out:before{content:"\f010"}
922 .icon-zoom-out:before{content:"\f010"}
923 .icon-power-off:before,.icon-off:before{content:"\f011"}
923 .icon-power-off:before,.icon-off:before{content:"\f011"}
924 .icon-signal:before{content:"\f012"}
924 .icon-signal:before{content:"\f012"}
925 .icon-gear:before,.icon-cog:before{content:"\f013"}
925 .icon-gear:before,.icon-cog:before{content:"\f013"}
926 .icon-trash:before{content:"\f014"}
926 .icon-trash:before{content:"\f014"}
927 .icon-home:before{content:"\f015"}
927 .icon-home:before{content:"\f015"}
928 .icon-file-alt:before{content:"\f016"}
928 .icon-file-alt:before{content:"\f016"}
929 .icon-time:before{content:"\f017"}
929 .icon-time:before{content:"\f017"}
930 .icon-road:before{content:"\f018"}
930 .icon-road:before{content:"\f018"}
931 .icon-download-alt:before{content:"\f019"}
931 .icon-download-alt:before{content:"\f019"}
932 .icon-download:before{content:"\f01a"}
932 .icon-download:before{content:"\f01a"}
933 .icon-upload:before{content:"\f01b"}
933 .icon-upload:before{content:"\f01b"}
934 .icon-inbox:before{content:"\f01c"}
934 .icon-inbox:before{content:"\f01c"}
935 .icon-play-circle:before{content:"\f01d"}
935 .icon-play-circle:before{content:"\f01d"}
936 .icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}
936 .icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}
937 .icon-refresh:before{content:"\f021"}
937 .icon-refresh:before{content:"\f021"}
938 .icon-list-alt:before{content:"\f022"}
938 .icon-list-alt:before{content:"\f022"}
939 .icon-lock:before{content:"\f023"}
939 .icon-lock:before{content:"\f023"}
940 .icon-flag:before{content:"\f024"}
940 .icon-flag:before{content:"\f024"}
941 .icon-headphones:before{content:"\f025"}
941 .icon-headphones:before{content:"\f025"}
942 .icon-volume-off:before{content:"\f026"}
942 .icon-volume-off:before{content:"\f026"}
943 .icon-volume-down:before{content:"\f027"}
943 .icon-volume-down:before{content:"\f027"}
944 .icon-volume-up:before{content:"\f028"}
944 .icon-volume-up:before{content:"\f028"}
945 .icon-qrcode:before{content:"\f029"}
945 .icon-qrcode:before{content:"\f029"}
946 .icon-barcode:before{content:"\f02a"}
946 .icon-barcode:before{content:"\f02a"}
947 .icon-tag:before{content:"\f02b"}
947 .icon-tag:before{content:"\f02b"}
948 .icon-tags:before{content:"\f02c"}
948 .icon-tags:before{content:"\f02c"}
949 .icon-book:before{content:"\f02d"}
949 .icon-book:before{content:"\f02d"}
950 .icon-bookmark:before{content:"\f02e"}
950 .icon-bookmark:before{content:"\f02e"}
951 .icon-print:before{content:"\f02f"}
951 .icon-print:before{content:"\f02f"}
952 .icon-camera:before{content:"\f030"}
952 .icon-camera:before{content:"\f030"}
953 .icon-font:before{content:"\f031"}
953 .icon-font:before{content:"\f031"}
954 .icon-bold:before{content:"\f032"}
954 .icon-bold:before{content:"\f032"}
955 .icon-italic:before{content:"\f033"}
955 .icon-italic:before{content:"\f033"}
956 .icon-text-height:before{content:"\f034"}
956 .icon-text-height:before{content:"\f034"}
957 .icon-text-width:before{content:"\f035"}
957 .icon-text-width:before{content:"\f035"}
958 .icon-align-left:before{content:"\f036"}
958 .icon-align-left:before{content:"\f036"}
959 .icon-align-center:before{content:"\f037"}
959 .icon-align-center:before{content:"\f037"}
960 .icon-align-right:before{content:"\f038"}
960 .icon-align-right:before{content:"\f038"}
961 .icon-align-justify:before{content:"\f039"}
961 .icon-align-justify:before{content:"\f039"}
962 .icon-list:before{content:"\f03a"}
962 .icon-list:before{content:"\f03a"}
963 .icon-indent-left:before{content:"\f03b"}
963 .icon-indent-left:before{content:"\f03b"}
964 .icon-indent-right:before{content:"\f03c"}
964 .icon-indent-right:before{content:"\f03c"}
965 .icon-facetime-video:before{content:"\f03d"}
965 .icon-facetime-video:before{content:"\f03d"}
966 .icon-picture:before{content:"\f03e"}
966 .icon-picture:before{content:"\f03e"}
967 .icon-pencil:before{content:"\f040"}
967 .icon-pencil:before{content:"\f040"}
968 .icon-map-marker:before{content:"\f041"}
968 .icon-map-marker:before{content:"\f041"}
969 .icon-adjust:before{content:"\f042"}
969 .icon-adjust:before{content:"\f042"}
970 .icon-tint:before{content:"\f043"}
970 .icon-tint:before{content:"\f043"}
971 .icon-edit:before{content:"\f044"}
971 .icon-edit:before{content:"\f044"}
972 .icon-share:before{content:"\f045"}
972 .icon-share:before{content:"\f045"}
973 .icon-check:before{content:"\f046"}
973 .icon-check:before{content:"\f046"}
974 .icon-move:before{content:"\f047"}
974 .icon-move:before{content:"\f047"}
975 .icon-step-backward:before{content:"\f048"}
975 .icon-step-backward:before{content:"\f048"}
976 .icon-fast-backward:before{content:"\f049"}
976 .icon-fast-backward:before{content:"\f049"}
977 .icon-backward:before{content:"\f04a"}
977 .icon-backward:before{content:"\f04a"}
978 .icon-play:before{content:"\f04b"}
978 .icon-play:before{content:"\f04b"}
979 .icon-pause:before{content:"\f04c"}
979 .icon-pause:before{content:"\f04c"}
980 .icon-stop:before{content:"\f04d"}
980 .icon-stop:before{content:"\f04d"}
981 .icon-forward:before{content:"\f04e"}
981 .icon-forward:before{content:"\f04e"}
982 .icon-fast-forward:before{content:"\f050"}
982 .icon-fast-forward:before{content:"\f050"}
983 .icon-step-forward:before{content:"\f051"}
983 .icon-step-forward:before{content:"\f051"}
984 .icon-eject:before{content:"\f052"}
984 .icon-eject:before{content:"\f052"}
985 .icon-chevron-left:before{content:"\f053"}
985 .icon-chevron-left:before{content:"\f053"}
986 .icon-chevron-right:before{content:"\f054"}
986 .icon-chevron-right:before{content:"\f054"}
987 .icon-plus-sign:before{content:"\f055"}
987 .icon-plus-sign:before{content:"\f055"}
988 .icon-minus-sign:before{content:"\f056"}
988 .icon-minus-sign:before{content:"\f056"}
989 .icon-remove-sign:before{content:"\f057"}
989 .icon-remove-sign:before{content:"\f057"}
990 .icon-ok-sign:before{content:"\f058"}
990 .icon-ok-sign:before{content:"\f058"}
991 .icon-question-sign:before{content:"\f059"}
991 .icon-question-sign:before{content:"\f059"}
992 .icon-info-sign:before{content:"\f05a"}
992 .icon-info-sign:before{content:"\f05a"}
993 .icon-screenshot:before{content:"\f05b"}
993 .icon-screenshot:before{content:"\f05b"}
994 .icon-remove-circle:before{content:"\f05c"}
994 .icon-remove-circle:before{content:"\f05c"}
995 .icon-ok-circle:before{content:"\f05d"}
995 .icon-ok-circle:before{content:"\f05d"}
996 .icon-ban-circle:before{content:"\f05e"}
996 .icon-ban-circle:before{content:"\f05e"}
997 .icon-arrow-left:before{content:"\f060"}
997 .icon-arrow-left:before{content:"\f060"}
998 .icon-arrow-right:before{content:"\f061"}
998 .icon-arrow-right:before{content:"\f061"}
999 .icon-arrow-up:before{content:"\f062"}
999 .icon-arrow-up:before{content:"\f062"}
1000 .icon-arrow-down:before{content:"\f063"}
1000 .icon-arrow-down:before{content:"\f063"}
1001 .icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}
1001 .icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}
1002 .icon-resize-full:before{content:"\f065"}
1002 .icon-resize-full:before{content:"\f065"}
1003 .icon-resize-small:before{content:"\f066"}
1003 .icon-resize-small:before{content:"\f066"}
1004 .icon-plus:before{content:"\f067"}
1004 .icon-plus:before{content:"\f067"}
1005 .icon-minus:before{content:"\f068"}
1005 .icon-minus:before{content:"\f068"}
1006 .icon-asterisk:before{content:"\f069"}
1006 .icon-asterisk:before{content:"\f069"}
1007 .icon-exclamation-sign:before{content:"\f06a"}
1007 .icon-exclamation-sign:before{content:"\f06a"}
1008 .icon-gift:before{content:"\f06b"}
1008 .icon-gift:before{content:"\f06b"}
1009 .icon-leaf:before{content:"\f06c"}
1009 .icon-leaf:before{content:"\f06c"}
1010 .icon-fire:before{content:"\f06d"}
1010 .icon-fire:before{content:"\f06d"}
1011 .icon-eye-open:before{content:"\f06e"}
1011 .icon-eye-open:before{content:"\f06e"}
1012 .icon-eye-close:before{content:"\f070"}
1012 .icon-eye-close:before{content:"\f070"}
1013 .icon-warning-sign:before{content:"\f071"}
1013 .icon-warning-sign:before{content:"\f071"}
1014 .icon-plane:before{content:"\f072"}
1014 .icon-plane:before{content:"\f072"}
1015 .icon-calendar:before{content:"\f073"}
1015 .icon-calendar:before{content:"\f073"}
1016 .icon-random:before{content:"\f074"}
1016 .icon-random:before{content:"\f074"}
1017 .icon-comment:before{content:"\f075"}
1017 .icon-comment:before{content:"\f075"}
1018 .icon-magnet:before{content:"\f076"}
1018 .icon-magnet:before{content:"\f076"}
1019 .icon-chevron-up:before{content:"\f077"}
1019 .icon-chevron-up:before{content:"\f077"}
1020 .icon-chevron-down:before{content:"\f078"}
1020 .icon-chevron-down:before{content:"\f078"}
1021 .icon-retweet:before{content:"\f079"}
1021 .icon-retweet:before{content:"\f079"}
1022 .icon-shopping-cart:before{content:"\f07a"}
1022 .icon-shopping-cart:before{content:"\f07a"}
1023 .icon-folder-close:before{content:"\f07b"}
1023 .icon-folder-close:before{content:"\f07b"}
1024 .icon-folder-open:before{content:"\f07c"}
1024 .icon-folder-open:before{content:"\f07c"}
1025 .icon-resize-vertical:before{content:"\f07d"}
1025 .icon-resize-vertical:before{content:"\f07d"}
1026 .icon-resize-horizontal:before{content:"\f07e"}
1026 .icon-resize-horizontal:before{content:"\f07e"}
1027 .icon-bar-chart:before{content:"\f080"}
1027 .icon-bar-chart:before{content:"\f080"}
1028 .icon-twitter-sign:before{content:"\f081"}
1028 .icon-twitter-sign:before{content:"\f081"}
1029 .icon-facebook-sign:before{content:"\f082"}
1029 .icon-facebook-sign:before{content:"\f082"}
1030 .icon-camera-retro:before{content:"\f083"}
1030 .icon-camera-retro:before{content:"\f083"}
1031 .icon-key:before{content:"\f084"}
1031 .icon-key:before{content:"\f084"}
1032 .icon-gears:before,.icon-cogs:before{content:"\f085"}
1032 .icon-gears:before,.icon-cogs:before{content:"\f085"}
1033 .icon-comments:before{content:"\f086"}
1033 .icon-comments:before{content:"\f086"}
1034 .icon-thumbs-up-alt:before{content:"\f087"}
1034 .icon-thumbs-up-alt:before{content:"\f087"}
1035 .icon-thumbs-down-alt:before{content:"\f088"}
1035 .icon-thumbs-down-alt:before{content:"\f088"}
1036 .icon-star-half:before{content:"\f089"}
1036 .icon-star-half:before{content:"\f089"}
1037 .icon-heart-empty:before{content:"\f08a"}
1037 .icon-heart-empty:before{content:"\f08a"}
1038 .icon-signout:before{content:"\f08b"}
1038 .icon-signout:before{content:"\f08b"}
1039 .icon-linkedin-sign:before{content:"\f08c"}
1039 .icon-linkedin-sign:before{content:"\f08c"}
1040 .icon-pushpin:before{content:"\f08d"}
1040 .icon-pushpin:before{content:"\f08d"}
1041 .icon-external-link:before{content:"\f08e"}
1041 .icon-external-link:before{content:"\f08e"}
1042 .icon-signin:before{content:"\f090"}
1042 .icon-signin:before{content:"\f090"}
1043 .icon-trophy:before{content:"\f091"}
1043 .icon-trophy:before{content:"\f091"}
1044 .icon-github-sign:before{content:"\f092"}
1044 .icon-github-sign:before{content:"\f092"}
1045 .icon-upload-alt:before{content:"\f093"}
1045 .icon-upload-alt:before{content:"\f093"}
1046 .icon-lemon:before{content:"\f094"}
1046 .icon-lemon:before{content:"\f094"}
1047 .icon-phone:before{content:"\f095"}
1047 .icon-phone:before{content:"\f095"}
1048 .icon-unchecked:before,.icon-check-empty:before{content:"\f096"}
1048 .icon-unchecked:before,.icon-check-empty:before{content:"\f096"}
1049 .icon-bookmark-empty:before{content:"\f097"}
1049 .icon-bookmark-empty:before{content:"\f097"}
1050 .icon-phone-sign:before{content:"\f098"}
1050 .icon-phone-sign:before{content:"\f098"}
1051 .icon-twitter:before{content:"\f099"}
1051 .icon-twitter:before{content:"\f099"}
1052 .icon-facebook:before{content:"\f09a"}
1052 .icon-facebook:before{content:"\f09a"}
1053 .icon-github:before{content:"\f09b"}
1053 .icon-github:before{content:"\f09b"}
1054 .icon-unlock:before{content:"\f09c"}
1054 .icon-unlock:before{content:"\f09c"}
1055 .icon-credit-card:before{content:"\f09d"}
1055 .icon-credit-card:before{content:"\f09d"}
1056 .icon-rss:before{content:"\f09e"}
1056 .icon-rss:before{content:"\f09e"}
1057 .icon-hdd:before{content:"\f0a0"}
1057 .icon-hdd:before{content:"\f0a0"}
1058 .icon-bullhorn:before{content:"\f0a1"}
1058 .icon-bullhorn:before{content:"\f0a1"}
1059 .icon-bell:before{content:"\f0a2"}
1059 .icon-bell:before{content:"\f0a2"}
1060 .icon-certificate:before{content:"\f0a3"}
1060 .icon-certificate:before{content:"\f0a3"}
1061 .icon-hand-right:before{content:"\f0a4"}
1061 .icon-hand-right:before{content:"\f0a4"}
1062 .icon-hand-left:before{content:"\f0a5"}
1062 .icon-hand-left:before{content:"\f0a5"}
1063 .icon-hand-up:before{content:"\f0a6"}
1063 .icon-hand-up:before{content:"\f0a6"}
1064 .icon-hand-down:before{content:"\f0a7"}
1064 .icon-hand-down:before{content:"\f0a7"}
1065 .icon-circle-arrow-left:before{content:"\f0a8"}
1065 .icon-circle-arrow-left:before{content:"\f0a8"}
1066 .icon-circle-arrow-right:before{content:"\f0a9"}
1066 .icon-circle-arrow-right:before{content:"\f0a9"}
1067 .icon-circle-arrow-up:before{content:"\f0aa"}
1067 .icon-circle-arrow-up:before{content:"\f0aa"}
1068 .icon-circle-arrow-down:before{content:"\f0ab"}
1068 .icon-circle-arrow-down:before{content:"\f0ab"}
1069 .icon-globe:before{content:"\f0ac"}
1069 .icon-globe:before{content:"\f0ac"}
1070 .icon-wrench:before{content:"\f0ad"}
1070 .icon-wrench:before{content:"\f0ad"}
1071 .icon-tasks:before{content:"\f0ae"}
1071 .icon-tasks:before{content:"\f0ae"}
1072 .icon-filter:before{content:"\f0b0"}
1072 .icon-filter:before{content:"\f0b0"}
1073 .icon-briefcase:before{content:"\f0b1"}
1073 .icon-briefcase:before{content:"\f0b1"}
1074 .icon-fullscreen:before{content:"\f0b2"}
1074 .icon-fullscreen:before{content:"\f0b2"}
1075 .icon-group:before{content:"\f0c0"}
1075 .icon-group:before{content:"\f0c0"}
1076 .icon-link:before{content:"\f0c1"}
1076 .icon-link:before{content:"\f0c1"}
1077 .icon-cloud:before{content:"\f0c2"}
1077 .icon-cloud:before{content:"\f0c2"}
1078 .icon-beaker:before{content:"\f0c3"}
1078 .icon-beaker:before{content:"\f0c3"}
1079 .icon-cut:before{content:"\f0c4"}
1079 .icon-cut:before{content:"\f0c4"}
1080 .icon-copy:before{content:"\f0c5"}
1080 .icon-copy:before{content:"\f0c5"}
1081 .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}
1081 .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}
1082 .icon-save:before{content:"\f0c7"}
1082 .icon-save:before{content:"\f0c7"}
1083 .icon-sign-blank:before{content:"\f0c8"}
1083 .icon-sign-blank:before{content:"\f0c8"}
1084 .icon-reorder:before{content:"\f0c9"}
1084 .icon-reorder:before{content:"\f0c9"}
1085 .icon-list-ul:before{content:"\f0ca"}
1085 .icon-list-ul:before{content:"\f0ca"}
1086 .icon-list-ol:before{content:"\f0cb"}
1086 .icon-list-ol:before{content:"\f0cb"}
1087 .icon-strikethrough:before{content:"\f0cc"}
1087 .icon-strikethrough:before{content:"\f0cc"}
1088 .icon-underline:before{content:"\f0cd"}
1088 .icon-underline:before{content:"\f0cd"}
1089 .icon-table:before{content:"\f0ce"}
1089 .icon-table:before{content:"\f0ce"}
1090 .icon-magic:before{content:"\f0d0"}
1090 .icon-magic:before{content:"\f0d0"}
1091 .icon-truck:before{content:"\f0d1"}
1091 .icon-truck:before{content:"\f0d1"}
1092 .icon-pinterest:before{content:"\f0d2"}
1092 .icon-pinterest:before{content:"\f0d2"}
1093 .icon-pinterest-sign:before{content:"\f0d3"}
1093 .icon-pinterest-sign:before{content:"\f0d3"}
1094 .icon-google-plus-sign:before{content:"\f0d4"}
1094 .icon-google-plus-sign:before{content:"\f0d4"}
1095 .icon-google-plus:before{content:"\f0d5"}
1095 .icon-google-plus:before{content:"\f0d5"}
1096 .icon-money:before{content:"\f0d6"}
1096 .icon-money:before{content:"\f0d6"}
1097 .icon-caret-down:before{content:"\f0d7"}
1097 .icon-caret-down:before{content:"\f0d7"}
1098 .icon-caret-up:before{content:"\f0d8"}
1098 .icon-caret-up:before{content:"\f0d8"}
1099 .icon-caret-left:before{content:"\f0d9"}
1099 .icon-caret-left:before{content:"\f0d9"}
1100 .icon-caret-right:before{content:"\f0da"}
1100 .icon-caret-right:before{content:"\f0da"}
1101 .icon-columns:before{content:"\f0db"}
1101 .icon-columns:before{content:"\f0db"}
1102 .icon-sort:before{content:"\f0dc"}
1102 .icon-sort:before{content:"\f0dc"}
1103 .icon-sort-down:before{content:"\f0dd"}
1103 .icon-sort-down:before{content:"\f0dd"}
1104 .icon-sort-up:before{content:"\f0de"}
1104 .icon-sort-up:before{content:"\f0de"}
1105 .icon-envelope:before{content:"\f0e0"}
1105 .icon-envelope:before{content:"\f0e0"}
1106 .icon-linkedin:before{content:"\f0e1"}
1106 .icon-linkedin:before{content:"\f0e1"}
1107 .icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}
1107 .icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}
1108 .icon-legal:before{content:"\f0e3"}
1108 .icon-legal:before{content:"\f0e3"}
1109 .icon-dashboard:before{content:"\f0e4"}
1109 .icon-dashboard:before{content:"\f0e4"}
1110 .icon-comment-alt:before{content:"\f0e5"}
1110 .icon-comment-alt:before{content:"\f0e5"}
1111 .icon-comments-alt:before{content:"\f0e6"}
1111 .icon-comments-alt:before{content:"\f0e6"}
1112 .icon-bolt:before{content:"\f0e7"}
1112 .icon-bolt:before{content:"\f0e7"}
1113 .icon-sitemap:before{content:"\f0e8"}
1113 .icon-sitemap:before{content:"\f0e8"}
1114 .icon-umbrella:before{content:"\f0e9"}
1114 .icon-umbrella:before{content:"\f0e9"}
1115 .icon-paste:before{content:"\f0ea"}
1115 .icon-paste:before{content:"\f0ea"}
1116 .icon-lightbulb:before{content:"\f0eb"}
1116 .icon-lightbulb:before{content:"\f0eb"}
1117 .icon-exchange:before{content:"\f0ec"}
1117 .icon-exchange:before{content:"\f0ec"}
1118 .icon-cloud-download:before{content:"\f0ed"}
1118 .icon-cloud-download:before{content:"\f0ed"}
1119 .icon-cloud-upload:before{content:"\f0ee"}
1119 .icon-cloud-upload:before{content:"\f0ee"}
1120 .icon-user-md:before{content:"\f0f0"}
1120 .icon-user-md:before{content:"\f0f0"}
1121 .icon-stethoscope:before{content:"\f0f1"}
1121 .icon-stethoscope:before{content:"\f0f1"}
1122 .icon-suitcase:before{content:"\f0f2"}
1122 .icon-suitcase:before{content:"\f0f2"}
1123 .icon-bell-alt:before{content:"\f0f3"}
1123 .icon-bell-alt:before{content:"\f0f3"}
1124 .icon-coffee:before{content:"\f0f4"}
1124 .icon-coffee:before{content:"\f0f4"}
1125 .icon-food:before{content:"\f0f5"}
1125 .icon-food:before{content:"\f0f5"}
1126 .icon-file-text-alt:before{content:"\f0f6"}
1126 .icon-file-text-alt:before{content:"\f0f6"}
1127 .icon-building:before{content:"\f0f7"}
1127 .icon-building:before{content:"\f0f7"}
1128 .icon-hospital:before{content:"\f0f8"}
1128 .icon-hospital:before{content:"\f0f8"}
1129 .icon-ambulance:before{content:"\f0f9"}
1129 .icon-ambulance:before{content:"\f0f9"}
1130 .icon-medkit:before{content:"\f0fa"}
1130 .icon-medkit:before{content:"\f0fa"}
1131 .icon-fighter-jet:before{content:"\f0fb"}
1131 .icon-fighter-jet:before{content:"\f0fb"}
1132 .icon-beer:before{content:"\f0fc"}
1132 .icon-beer:before{content:"\f0fc"}
1133 .icon-h-sign:before{content:"\f0fd"}
1133 .icon-h-sign:before{content:"\f0fd"}
1134 .icon-plus-sign-alt:before{content:"\f0fe"}
1134 .icon-plus-sign-alt:before{content:"\f0fe"}
1135 .icon-double-angle-left:before{content:"\f100"}
1135 .icon-double-angle-left:before{content:"\f100"}
1136 .icon-double-angle-right:before{content:"\f101"}
1136 .icon-double-angle-right:before{content:"\f101"}
1137 .icon-double-angle-up:before{content:"\f102"}
1137 .icon-double-angle-up:before{content:"\f102"}
1138 .icon-double-angle-down:before{content:"\f103"}
1138 .icon-double-angle-down:before{content:"\f103"}
1139 .icon-angle-left:before{content:"\f104"}
1139 .icon-angle-left:before{content:"\f104"}
1140 .icon-angle-right:before{content:"\f105"}
1140 .icon-angle-right:before{content:"\f105"}
1141 .icon-angle-up:before{content:"\f106"}
1141 .icon-angle-up:before{content:"\f106"}
1142 .icon-angle-down:before{content:"\f107"}
1142 .icon-angle-down:before{content:"\f107"}
1143 .icon-desktop:before{content:"\f108"}
1143 .icon-desktop:before{content:"\f108"}
1144 .icon-laptop:before{content:"\f109"}
1144 .icon-laptop:before{content:"\f109"}
1145 .icon-tablet:before{content:"\f10a"}
1145 .icon-tablet:before{content:"\f10a"}
1146 .icon-mobile-phone:before{content:"\f10b"}
1146 .icon-mobile-phone:before{content:"\f10b"}
1147 .icon-circle-blank:before{content:"\f10c"}
1147 .icon-circle-blank:before{content:"\f10c"}
1148 .icon-quote-left:before{content:"\f10d"}
1148 .icon-quote-left:before{content:"\f10d"}
1149 .icon-quote-right:before{content:"\f10e"}
1149 .icon-quote-right:before{content:"\f10e"}
1150 .icon-spinner:before{content:"\f110"}
1150 .icon-spinner:before{content:"\f110"}
1151 .icon-circle:before{content:"\f111"}
1151 .icon-circle:before{content:"\f111"}
1152 .icon-mail-reply:before,.icon-reply:before{content:"\f112"}
1152 .icon-mail-reply:before,.icon-reply:before{content:"\f112"}
1153 .icon-github-alt:before{content:"\f113"}
1153 .icon-github-alt:before{content:"\f113"}
1154 .icon-folder-close-alt:before{content:"\f114"}
1154 .icon-folder-close-alt:before{content:"\f114"}
1155 .icon-folder-open-alt:before{content:"\f115"}
1155 .icon-folder-open-alt:before{content:"\f115"}
1156 .icon-expand-alt:before{content:"\f116"}
1156 .icon-expand-alt:before{content:"\f116"}
1157 .icon-collapse-alt:before{content:"\f117"}
1157 .icon-collapse-alt:before{content:"\f117"}
1158 .icon-smile:before{content:"\f118"}
1158 .icon-smile:before{content:"\f118"}
1159 .icon-frown:before{content:"\f119"}
1159 .icon-frown:before{content:"\f119"}
1160 .icon-meh:before{content:"\f11a"}
1160 .icon-meh:before{content:"\f11a"}
1161 .icon-gamepad:before{content:"\f11b"}
1161 .icon-gamepad:before{content:"\f11b"}
1162 .icon-keyboard:before{content:"\f11c"}
1162 .icon-keyboard:before{content:"\f11c"}
1163 .icon-flag-alt:before{content:"\f11d"}
1163 .icon-flag-alt:before{content:"\f11d"}
1164 .icon-flag-checkered:before{content:"\f11e"}
1164 .icon-flag-checkered:before{content:"\f11e"}
1165 .icon-terminal:before{content:"\f120"}
1165 .icon-terminal:before{content:"\f120"}
1166 .icon-code:before{content:"\f121"}
1166 .icon-code:before{content:"\f121"}
1167 .icon-reply-all:before{content:"\f122"}
1167 .icon-reply-all:before{content:"\f122"}
1168 .icon-mail-reply-all:before{content:"\f122"}
1168 .icon-mail-reply-all:before{content:"\f122"}
1169 .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}
1169 .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}
1170 .icon-location-arrow:before{content:"\f124"}
1170 .icon-location-arrow:before{content:"\f124"}
1171 .icon-crop:before{content:"\f125"}
1171 .icon-crop:before{content:"\f125"}
1172 .icon-code-fork:before{content:"\f126"}
1172 .icon-code-fork:before{content:"\f126"}
1173 .icon-unlink:before{content:"\f127"}
1173 .icon-unlink:before{content:"\f127"}
1174 .icon-question:before{content:"\f128"}
1174 .icon-question:before{content:"\f128"}
1175 .icon-info:before{content:"\f129"}
1175 .icon-info:before{content:"\f129"}
1176 .icon-exclamation:before{content:"\f12a"}
1176 .icon-exclamation:before{content:"\f12a"}
1177 .icon-superscript:before{content:"\f12b"}
1177 .icon-superscript:before{content:"\f12b"}
1178 .icon-subscript:before{content:"\f12c"}
1178 .icon-subscript:before{content:"\f12c"}
1179 .icon-eraser:before{content:"\f12d"}
1179 .icon-eraser:before{content:"\f12d"}
1180 .icon-puzzle-piece:before{content:"\f12e"}
1180 .icon-puzzle-piece:before{content:"\f12e"}
1181 .icon-microphone:before{content:"\f130"}
1181 .icon-microphone:before{content:"\f130"}
1182 .icon-microphone-off:before{content:"\f131"}
1182 .icon-microphone-off:before{content:"\f131"}
1183 .icon-shield:before{content:"\f132"}
1183 .icon-shield:before{content:"\f132"}
1184 .icon-calendar-empty:before{content:"\f133"}
1184 .icon-calendar-empty:before{content:"\f133"}
1185 .icon-fire-extinguisher:before{content:"\f134"}
1185 .icon-fire-extinguisher:before{content:"\f134"}
1186 .icon-rocket:before{content:"\f135"}
1186 .icon-rocket:before{content:"\f135"}
1187 .icon-maxcdn:before{content:"\f136"}
1187 .icon-maxcdn:before{content:"\f136"}
1188 .icon-chevron-sign-left:before{content:"\f137"}
1188 .icon-chevron-sign-left:before{content:"\f137"}
1189 .icon-chevron-sign-right:before{content:"\f138"}
1189 .icon-chevron-sign-right:before{content:"\f138"}
1190 .icon-chevron-sign-up:before{content:"\f139"}
1190 .icon-chevron-sign-up:before{content:"\f139"}
1191 .icon-chevron-sign-down:before{content:"\f13a"}
1191 .icon-chevron-sign-down:before{content:"\f13a"}
1192 .icon-html5:before{content:"\f13b"}
1192 .icon-html5:before{content:"\f13b"}
1193 .icon-css3:before{content:"\f13c"}
1193 .icon-css3:before{content:"\f13c"}
1194 .icon-anchor:before{content:"\f13d"}
1194 .icon-anchor:before{content:"\f13d"}
1195 .icon-unlock-alt:before{content:"\f13e"}
1195 .icon-unlock-alt:before{content:"\f13e"}
1196 .icon-bullseye:before{content:"\f140"}
1196 .icon-bullseye:before{content:"\f140"}
1197 .icon-ellipsis-horizontal:before{content:"\f141"}
1197 .icon-ellipsis-horizontal:before{content:"\f141"}
1198 .icon-ellipsis-vertical:before{content:"\f142"}
1198 .icon-ellipsis-vertical:before{content:"\f142"}
1199 .icon-rss-sign:before{content:"\f143"}
1199 .icon-rss-sign:before{content:"\f143"}
1200 .icon-play-sign:before{content:"\f144"}
1200 .icon-play-sign:before{content:"\f144"}
1201 .icon-ticket:before{content:"\f145"}
1201 .icon-ticket:before{content:"\f145"}
1202 .icon-minus-sign-alt:before{content:"\f146"}
1202 .icon-minus-sign-alt:before{content:"\f146"}
1203 .icon-check-minus:before{content:"\f147"}
1203 .icon-check-minus:before{content:"\f147"}
1204 .icon-level-up:before{content:"\f148"}
1204 .icon-level-up:before{content:"\f148"}
1205 .icon-level-down:before{content:"\f149"}
1205 .icon-level-down:before{content:"\f149"}
1206 .icon-check-sign:before{content:"\f14a"}
1206 .icon-check-sign:before{content:"\f14a"}
1207 .icon-edit-sign:before{content:"\f14b"}
1207 .icon-edit-sign:before{content:"\f14b"}
1208 .icon-external-link-sign:before{content:"\f14c"}
1208 .icon-external-link-sign:before{content:"\f14c"}
1209 .icon-share-sign:before{content:"\f14d"}
1209 .icon-share-sign:before{content:"\f14d"}
1210 .icon-compass:before{content:"\f14e"}
1210 .icon-compass:before{content:"\f14e"}
1211 .icon-collapse:before{content:"\f150"}
1211 .icon-collapse:before{content:"\f150"}
1212 .icon-collapse-top:before{content:"\f151"}
1212 .icon-collapse-top:before{content:"\f151"}
1213 .icon-expand:before{content:"\f152"}
1213 .icon-expand:before{content:"\f152"}
1214 .icon-euro:before,.icon-eur:before{content:"\f153"}
1214 .icon-euro:before,.icon-eur:before{content:"\f153"}
1215 .icon-gbp:before{content:"\f154"}
1215 .icon-gbp:before{content:"\f154"}
1216 .icon-dollar:before,.icon-usd:before{content:"\f155"}
1216 .icon-dollar:before,.icon-usd:before{content:"\f155"}
1217 .icon-rupee:before,.icon-inr:before{content:"\f156"}
1217 .icon-rupee:before,.icon-inr:before{content:"\f156"}
1218 .icon-yen:before,.icon-jpy:before{content:"\f157"}
1218 .icon-yen:before,.icon-jpy:before{content:"\f157"}
1219 .icon-renminbi:before,.icon-cny:before{content:"\f158"}
1219 .icon-renminbi:before,.icon-cny:before{content:"\f158"}
1220 .icon-won:before,.icon-krw:before{content:"\f159"}
1220 .icon-won:before,.icon-krw:before{content:"\f159"}
1221 .icon-bitcoin:before,.icon-btc:before{content:"\f15a"}
1221 .icon-bitcoin:before,.icon-btc:before{content:"\f15a"}
1222 .icon-file:before{content:"\f15b"}
1222 .icon-file:before{content:"\f15b"}
1223 .icon-file-text:before{content:"\f15c"}
1223 .icon-file-text:before{content:"\f15c"}
1224 .icon-sort-by-alphabet:before{content:"\f15d"}
1224 .icon-sort-by-alphabet:before{content:"\f15d"}
1225 .icon-sort-by-alphabet-alt:before{content:"\f15e"}
1225 .icon-sort-by-alphabet-alt:before{content:"\f15e"}
1226 .icon-sort-by-attributes:before{content:"\f160"}
1226 .icon-sort-by-attributes:before{content:"\f160"}
1227 .icon-sort-by-attributes-alt:before{content:"\f161"}
1227 .icon-sort-by-attributes-alt:before{content:"\f161"}
1228 .icon-sort-by-order:before{content:"\f162"}
1228 .icon-sort-by-order:before{content:"\f162"}
1229 .icon-sort-by-order-alt:before{content:"\f163"}
1229 .icon-sort-by-order-alt:before{content:"\f163"}
1230 .icon-thumbs-up:before{content:"\f164"}
1230 .icon-thumbs-up:before{content:"\f164"}
1231 .icon-thumbs-down:before{content:"\f165"}
1231 .icon-thumbs-down:before{content:"\f165"}
1232 .icon-youtube-sign:before{content:"\f166"}
1232 .icon-youtube-sign:before{content:"\f166"}
1233 .icon-youtube:before{content:"\f167"}
1233 .icon-youtube:before{content:"\f167"}
1234 .icon-xing:before{content:"\f168"}
1234 .icon-xing:before{content:"\f168"}
1235 .icon-xing-sign:before{content:"\f169"}
1235 .icon-xing-sign:before{content:"\f169"}
1236 .icon-youtube-play:before{content:"\f16a"}
1236 .icon-youtube-play:before{content:"\f16a"}
1237 .icon-dropbox:before{content:"\f16b"}
1237 .icon-dropbox:before{content:"\f16b"}
1238 .icon-stackexchange:before{content:"\f16c"}
1238 .icon-stackexchange:before{content:"\f16c"}
1239 .icon-instagram:before{content:"\f16d"}
1239 .icon-instagram:before{content:"\f16d"}
1240 .icon-flickr:before{content:"\f16e"}
1240 .icon-flickr:before{content:"\f16e"}
1241 .icon-adn:before{content:"\f170"}
1241 .icon-adn:before{content:"\f170"}
1242 .icon-bitbucket:before{content:"\f171"}
1242 .icon-bitbucket:before{content:"\f171"}
1243 .icon-bitbucket-sign:before{content:"\f172"}
1243 .icon-bitbucket-sign:before{content:"\f172"}
1244 .icon-tumblr:before{content:"\f173"}
1244 .icon-tumblr:before{content:"\f173"}
1245 .icon-tumblr-sign:before{content:"\f174"}
1245 .icon-tumblr-sign:before{content:"\f174"}
1246 .icon-long-arrow-down:before{content:"\f175"}
1246 .icon-long-arrow-down:before{content:"\f175"}
1247 .icon-long-arrow-up:before{content:"\f176"}
1247 .icon-long-arrow-up:before{content:"\f176"}
1248 .icon-long-arrow-left:before{content:"\f177"}
1248 .icon-long-arrow-left:before{content:"\f177"}
1249 .icon-long-arrow-right:before{content:"\f178"}
1249 .icon-long-arrow-right:before{content:"\f178"}
1250 .icon-apple:before{content:"\f179"}
1250 .icon-apple:before{content:"\f179"}
1251 .icon-windows:before{content:"\f17a"}
1251 .icon-windows:before{content:"\f17a"}
1252 .icon-android:before{content:"\f17b"}
1252 .icon-android:before{content:"\f17b"}
1253 .icon-linux:before{content:"\f17c"}
1253 .icon-linux:before{content:"\f17c"}
1254 .icon-dribbble:before{content:"\f17d"}
1254 .icon-dribbble:before{content:"\f17d"}
1255 .icon-skype:before{content:"\f17e"}
1255 .icon-skype:before{content:"\f17e"}
1256 .icon-foursquare:before{content:"\f180"}
1256 .icon-foursquare:before{content:"\f180"}
1257 .icon-trello:before{content:"\f181"}
1257 .icon-trello:before{content:"\f181"}
1258 .icon-female:before{content:"\f182"}
1258 .icon-female:before{content:"\f182"}
1259 .icon-male:before{content:"\f183"}
1259 .icon-male:before{content:"\f183"}
1260 .icon-gittip:before{content:"\f184"}
1260 .icon-gittip:before{content:"\f184"}
1261 .icon-sun:before{content:"\f185"}
1261 .icon-sun:before{content:"\f185"}
1262 .icon-moon:before{content:"\f186"}
1262 .icon-moon:before{content:"\f186"}
1263 .icon-archive:before{content:"\f187"}
1263 .icon-archive:before{content:"\f187"}
1264 .icon-bug:before{content:"\f188"}
1264 .icon-bug:before{content:"\f188"}
1265 .icon-vk:before{content:"\f189"}
1265 .icon-vk:before{content:"\f189"}
1266 .icon-weibo:before{content:"\f18a"}
1266 .icon-weibo:before{content:"\f18a"}
1267 .icon-renren:before{content:"\f18b"}
1267 .icon-renren:before{content:"\f18b"}
1268 code{color:#000}
1268 code{color:#000}
1269 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1269 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1270 .corner-all{border-radius:4px}
1270 .corner-all{border-radius:4px}
1271 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1271 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1272 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1272 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1273 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1273 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1274 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1274 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1275 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1275 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1276 .hbox.box-flex0,.vbox.box-flex0,.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}
1276 .hbox.box-flex0,.vbox.box-flex0,.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}
1277 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1277 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1278 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1278 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1279 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1279 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1280 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
1280 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
1281 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
1281 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
1282 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
1282 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
1283 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
1283 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
1284 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
1284 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
1285 .hbox.align-start,.vbox.align-start,.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1285 .hbox.align-start,.vbox.align-start,.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1286 .hbox.align-end,.vbox.align-end,.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}
1286 .hbox.align-end,.vbox.align-end,.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}
1287 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
1287 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
1288 div.error{margin:2em;text-align:center}
1288 div.error{margin:2em;text-align:center}
1289 div.error>h1{font-size:500%;line-height:normal}
1289 div.error>h1{font-size:500%;line-height:normal}
1290 div.error>p{font-size:200%;line-height:normal}
1290 div.error>p{font-size:200%;line-height:normal}
1291 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
1291 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
1292 body{background-color:#fff;position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}
1292 body{background-color:#fff;position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}
1293 div#header{display:none}
1293 div#header{display:none}
1294 #ipython_notebook{padding-left:16px}
1294 #ipython_notebook{padding-left:16px}
1295 #noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:#f00;font-weight:bold}
1295 #noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:#f00;font-weight:bold}
1296 #ipython_notebook img{font-family:Verdana,"Helvetica Neue",Arial,Helvetica,Geneva,sans-serif;height:24px;text-decoration:none;color:#000}
1296 #ipython_notebook img{font-family:Verdana,"Helvetica Neue",Arial,Helvetica,Geneva,sans-serif;height:24px;text-decoration:none;color:#000}
1297 #site{width:100%;display:none}
1297 #site{width:100%;display:none}
1298 .ui-button .ui-button-text{padding:.2em .8em;font-size:77%}
1298 .ui-button .ui-button-text{padding:.2em .8em;font-size:77%}
1299 input.ui-button{padding:.3em .9em}
1299 input.ui-button{padding:.3em .9em}
1300 .navbar span{margin-top:3px}
1300 .navbar span{margin-top:3px}
1301 span#login_widget{float:right}
1301 span#login_widget{float:right}
1302 .nav-header{text-transform:none}
1302 .nav-header{text-transform:none}
1303 .navbar-nobg{background-color:transparent;background-image:none}
1303 .navbar-nobg{background-color:transparent;background-image:none}
1304 #header>span{margin-top:10px}
1304 #header>span{margin-top:10px}
1305 .modal-body{max-height:500px}
1305 .modal-body{max-height:500px}
1306 @media (min-width:768px){.modal{width:700px;margin-left:-350px}}.center-nav{display:inline-block;margin-bottom:-4px}
1306 @media (min-width:768px){.modal{width:700px;margin-left:-350px}}.center-nav{display:inline-block;margin-bottom:-4px}
1307 .alternate_upload{background-color:none;display:inline}
1307 .alternate_upload{background-color:none;display:inline}
1308 .alternate_upload.form{padding:0;margin:0}
1308 .alternate_upload.form{padding:0;margin:0}
1309 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
1309 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
1310 ul#tabs{margin-bottom:4px}
1310 ul#tabs{margin-bottom:4px}
1311 ul#tabs a{padding-top:4px;padding-bottom:4px}
1311 ul#tabs a{padding-top:4px;padding-bottom:4px}
1312 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
1312 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
1313 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
1313 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
1314 ul.breadcrumb span{color:#5e5e5e}
1314 ul.breadcrumb span{color:#5e5e5e}
1315 .list_toolbar{padding:4px 0 4px 0}
1315 .list_toolbar{padding:4px 0 4px 0}
1316 .list_toolbar [class*="span"]{min-height:26px}
1316 .list_toolbar [class*="span"]{min-height:26px}
1317 .list_header{font-weight:bold}
1317 .list_header{font-weight:bold}
1318 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
1318 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
1319 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
1319 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
1320 .list_container>div:last-child{border:none}
1320 .list_container>div:last-child{border:none}
1321 .list_item:hover .list_item{background-color:#ddd}
1321 .list_item:hover .list_item{background-color:#ddd}
1322 .list_item a{text-decoration:none}
1322 .list_item a{text-decoration:none}
1323 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
1323 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
1324 .item_name{line-height:22px;height:26px}
1324 .item_name{line-height:22px;height:26px}
1325 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
1325 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
1326 .item_buttons{line-height:1em}
1326 .item_buttons{line-height:1em}
1327 .toolbar_info{height:26px;line-height:26px}
1327 .toolbar_info{height:26px;line-height:26px}
1328 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
1328 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
1329 input.engine_num_input{width:60px}
1329 input.engine_num_input{width:60px}
1330 .highlight_text{color:#00f}
1330 .highlight_text{color:#00f}
1331 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
1331 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
1332 .ansibold{font-weight:bold}
1332 .ansibold{font-weight:bold}
1333 .ansiblack{color:#000}
1333 .ansiblack{color:#000}
1334 .ansired{color:#8b0000}
1334 .ansired{color:#8b0000}
1335 .ansigreen{color:#006400}
1335 .ansigreen{color:#006400}
1336 .ansiyellow{color:#a52a2a}
1336 .ansiyellow{color:#a52a2a}
1337 .ansiblue{color:#00008b}
1337 .ansiblue{color:#00008b}
1338 .ansipurple{color:#9400d3}
1338 .ansipurple{color:#9400d3}
1339 .ansicyan{color:#4682b4}
1339 .ansicyan{color:#4682b4}
1340 .ansigray{color:#808080}
1340 .ansigray{color:#808080}
1341 .ansibgblack{background-color:#000}
1341 .ansibgblack{background-color:#000}
1342 .ansibgred{background-color:#f00}
1342 .ansibgred{background-color:#f00}
1343 .ansibggreen{background-color:#008000}
1343 .ansibggreen{background-color:#008000}
1344 .ansibgyellow{background-color:#ff0}
1344 .ansibgyellow{background-color:#ff0}
1345 .ansibgblue{background-color:#00f}
1345 .ansibgblue{background-color:#00f}
1346 .ansibgpurple{background-color:#f0f}
1346 .ansibgpurple{background-color:#f0f}
1347 .ansibgcyan{background-color:#0ff}
1347 .ansibgcyan{background-color:#0ff}
1348 .ansibggray{background-color:#808080}
1348 .ansibggray{background-color:#808080}
1349 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
1349 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
1350 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
1350 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
1351 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
1351 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
1352 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}
1352 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}
1353 div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1353 @media (max-width:480px){div.prompt{text-align:left}}div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1354 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1354 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1355 div.prompt:empty{padding-top:0;padding-bottom:0}
1355 div.prompt:empty{padding-top:0;padding-bottom:0}
1356 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1356 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1357 div.input_prompt{color:#000080;border-top:1px solid transparent}
1357 @media (max-width:480px){div.input{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.input_prompt{color:#000080;border-top:1px solid transparent}
1358 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
1358 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
1359 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
1359 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
1360 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
1360 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
1361 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
1361 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
1362 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
1362 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
1363 .CodeMirror-linenumber{padding:0 8px 0 4px}
1363 .CodeMirror-linenumber{padding:0 8px 0 4px}
1364 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
1364 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
1365 .CodeMirror pre{padding:0;border:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
1365 .CodeMirror pre{padding:0;border:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
1366 pre code{display:block;padding:.5em}
1366 pre code{display:block;padding:.5em}
1367 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
1367 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
1368 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
1368 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
1369 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
1369 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
1370 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
1370 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
1371 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
1371 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
1372 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
1372 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
1373 .highlight-builtin,pre .built_in{color:#008000}
1373 .highlight-builtin,pre .built_in{color:#008000}
1374 pre .markdown .emphasis{font-style:italic}
1374 pre .markdown .emphasis{font-style:italic}
1375 pre .nginx .built_in{font-weight:normal}
1375 pre .nginx .built_in{font-weight:normal}
1376 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
1376 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
1377 .cm-s-ipython span.cm-variable{color:#000}
1377 .cm-s-ipython span.cm-variable{color:#000}
1378 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
1378 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
1379 .cm-s-ipython span.cm-number{color:#080}
1379 .cm-s-ipython span.cm-number{color:#080}
1380 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
1380 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
1381 .cm-s-ipython span.cm-string{color:#ba2121}
1381 .cm-s-ipython span.cm-string{color:#ba2121}
1382 .cm-s-ipython span.cm-builtin{color:#008000}
1382 .cm-s-ipython span.cm-builtin{color:#008000}
1383 .cm-s-ipython span.cm-error{color:#f00}
1383 .cm-s-ipython span.cm-error{color:#f00}
1384 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
1384 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
1385 .cm-s-ipython span.cm-meta{color:#a2f}
1385 .cm-s-ipython span.cm-meta{color:#a2f}
1386 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
1386 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
1387 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1387 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1388 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);display:block}
1388 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);display:block}
1389 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1389 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1390 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
1390 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
1391 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
1391 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
1392 div.output_prompt{color:#8b0000}
1392 div.output_prompt{color:#8b0000}
1393 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
1393 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
1394 div.output_area .rendered_html table{margin-left:0;margin-right:0}
1394 div.output_area .rendered_html table{margin-left:0;margin-right:0}
1395 div.output_area .rendered_html img{margin-left:0;margin-right:0}
1395 div.output_area .rendered_html img{margin-left:0;margin-right:0}
1396 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1396 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1397 div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
1397 @media (max-width:480px){div.output_area{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}}div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
1398 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1398 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1399 div.output_text{text-align:left;color:#000;line-height:1.21429em}
1399 div.output_text{text-align:left;color:#000;line-height:1.21429em}
1400 div.output_stderr{background:#fdd;}
1400 div.output_stderr{background:#fdd;}
1401 div.output_latex{text-align:left}
1401 div.output_latex{text-align:left}
1402 div.output_javascript:empty{padding:0}
1402 div.output_javascript:empty{padding:0}
1403 .js-error{color:#8b0000}
1403 .js-error{color:#8b0000}
1404 div.raw_input_container{font-family:monospace;padding-top:5px}
1404 div.raw_input_container{font-family:monospace;padding-top:5px}
1405 span.raw_input_prompt{}
1405 span.raw_input_prompt{}
1406 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
1406 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
1407 input.raw_input:focus{box-shadow:none}
1407 input.raw_input:focus{box-shadow:none}
1408 p.p-space{margin-bottom:10px}
1408 p.p-space{margin-bottom:10px}
1409 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
1409 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
1410 .rendered_html strong{font-weight:bold}
1410 .rendered_html strong{font-weight:bold}
1411 .rendered_html u{text-decoration:underline}
1411 .rendered_html u{text-decoration:underline}
1412 .rendered_html :link{text-decoration:underline}
1412 .rendered_html :link{text-decoration:underline}
1413 .rendered_html :visited{text-decoration:underline}
1413 .rendered_html :visited{text-decoration:underline}
1414 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
1414 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
1415 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
1415 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
1416 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
1416 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
1417 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
1417 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
1418 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1418 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1419 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1419 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1420 .rendered_html h1:first-child{margin-top:.538em}
1420 .rendered_html h1:first-child{margin-top:.538em}
1421 .rendered_html h2:first-child{margin-top:.636em}
1421 .rendered_html h2:first-child{margin-top:.636em}
1422 .rendered_html h3:first-child{margin-top:.777em}
1422 .rendered_html h3:first-child{margin-top:.777em}
1423 .rendered_html h4:first-child{margin-top:1em}
1423 .rendered_html h4:first-child{margin-top:1em}
1424 .rendered_html h5:first-child{margin-top:1em}
1424 .rendered_html h5:first-child{margin-top:1em}
1425 .rendered_html h6:first-child{margin-top:1em}
1425 .rendered_html h6:first-child{margin-top:1em}
1426 .rendered_html ul{list-style:disc;margin:0 2em}
1426 .rendered_html ul{list-style:disc;margin:0 2em}
1427 .rendered_html ul ul{list-style:square;margin:0 2em}
1427 .rendered_html ul ul{list-style:square;margin:0 2em}
1428 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
1428 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
1429 .rendered_html ol{list-style:decimal;margin:0 2em}
1429 .rendered_html ol{list-style:decimal;margin:0 2em}
1430 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
1430 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
1431 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
1431 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
1432 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
1432 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
1433 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
1433 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
1434 .rendered_html *+ul{margin-top:1em}
1434 .rendered_html *+ul{margin-top:1em}
1435 .rendered_html *+ol{margin-top:1em}
1435 .rendered_html *+ol{margin-top:1em}
1436 .rendered_html hr{color:#000;background-color:#000}
1436 .rendered_html hr{color:#000;background-color:#000}
1437 .rendered_html pre{margin:1em 2em}
1437 .rendered_html pre{margin:1em 2em}
1438 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
1438 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
1439 .rendered_html blockquote{margin:1em 2em}
1439 .rendered_html blockquote{margin:1em 2em}
1440 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
1440 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
1441 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
1441 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
1442 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
1442 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
1443 .rendered_html th{font-weight:bold}
1443 .rendered_html th{font-weight:bold}
1444 .rendered_html *+table{margin-top:1em}
1444 .rendered_html *+table{margin-top:1em}
1445 .rendered_html p{text-align:justify}
1445 .rendered_html p{text-align:justify}
1446 .rendered_html *+p{margin-top:1em}
1446 .rendered_html *+p{margin-top:1em}
1447 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
1447 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
1448 .rendered_html *+img{margin-top:1em}
1448 .rendered_html *+img{margin-top:1em}
1449 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1449 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1450 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
1450 @media (max-width:480px){div.text_cell>div.prompt{display:none}}div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
1451 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
1451 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
1452 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
1452 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
1453 div.cell.text_cell.rendered{padding:0}
1453 div.cell.text_cell.rendered{padding:0}
1454 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1454 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1455 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
1455 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
1456 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
1456 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
1457 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
1457 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
1458 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
1458 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
1459 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
1459 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
1460 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;margin-bottom:10px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
1460 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;margin-bottom:10px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
1461 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
1461 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
1462 .widget-text{width:350px;margin:0 !important}
1462 .widget-text{width:350px;margin:0 !important}
1463 .widget-listbox{width:364px;margin-bottom:0}
1463 .widget-listbox{width:364px;margin-bottom:0}
1464 .widget-numeric-text{width:150px;margin:0 !important}
1464 .widget-numeric-text{width:150px;margin:0 !important}
1465 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
1465 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
1466 .widget-combo-btn{min-width:138px;}
1466 .widget-combo-btn{min-width:138px;}
1467 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1467 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1468 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1468 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1469 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
1469 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
1470 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1470 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1471 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
1471 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
1472 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
1472 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
1473 .widget-modal-body{max-height:none !important}
1473 .widget-modal-body{max-height:none !important}
1474 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1474 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1475 .widget-radio-box{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:4px}
1475 .widget-radio-box{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:4px}
1476 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
1476 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
1477 body{background-color:#fff}
1477 body{background-color:#fff}
1478 body.notebook_app{overflow:hidden}
1478 body.notebook_app{overflow:hidden}
1479 span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%}
1479 @media (max-width:767px){body.notebook_app{padding-left:0;padding-right:0}}span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%}
1480 div#notebook_panel{margin:0 0 0 0;padding:0;-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}
1480 div#notebook_panel{margin:0 0 0 0;padding:0;-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}
1481 div#notebook{font-size:14px;line-height:20px;overflow-y:scroll;overflow-x:auto;width:100%;padding:1em 0 1em 0;margin:0;border-top:1px solid #ababab;outline:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1481 div#notebook{font-size:14px;line-height:20px;overflow-y:scroll;overflow-x:auto;width:100%;padding:1em 0 1em 0;margin:0;border-top:1px solid #ababab;outline:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1482 div.ui-widget-content{border:1px solid #ababab;outline:none}
1482 div.ui-widget-content{border:1px solid #ababab;outline:none}
1483 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:.4em;padding-left:2em}
1483 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:.4em;padding-left:2em}
1484 p.dialog{padding:.2em}
1484 p.dialog{padding:.2em}
1485 pre,code,kbd,samp{white-space:pre-wrap}
1485 pre,code,kbd,samp{white-space:pre-wrap}
1486 #fonttest{font-family:monospace}
1486 #fonttest{font-family:monospace}
1487 p{margin-bottom:0}
1487 p{margin-bottom:0}
1488 .end_space{height:200px}
1488 .end_space{height:200px}
1489 .celltoolbar{border:thin solid #cfcfcf;border-bottom:none;background:#eee;border-radius:3px 3px 0 0;width:100%;-webkit-box-pack:end;height:22px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1489 .celltoolbar{border:thin solid #cfcfcf;border-bottom:none;background:#eee;border-radius:3px 3px 0 0;width:100%;-webkit-box-pack:end;height:22px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1490 .ctb_hideshow{display:none;vertical-align:bottom;padding-right:2px}
1490 .ctb_hideshow{display:none;vertical-align:bottom;padding-right:2px}
1491 .celltoolbar>div{padding-top:0}
1491 .celltoolbar>div{padding-top:0}
1492 .ctb_global_show .ctb_show.ctb_hideshow{display:block}
1492 .ctb_global_show .ctb_show.ctb_hideshow{display:block}
1493 .ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input{border-top-right-radius:0;border-top-left-radius:0}
1493 .ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input{border-top-right-radius:0;border-top-left-radius:0}
1494 .celltoolbar .button_container select{margin:10px;margin-top:1px;margin-bottom:0;padding:0;font-size:87%;width:auto;display:inline-block;height:18px;line-height:18px;vertical-align:top}
1494 .celltoolbar .button_container select{margin:10px;margin-top:1px;margin-bottom:0;padding:0;font-size:87%;width:auto;display:inline-block;height:18px;line-height:18px;vertical-align:top}
1495 .celltoolbar label{display:inline-block;height:15px;line-height:15px;vertical-align:top}
1495 .celltoolbar label{display:inline-block;height:15px;line-height:15px;vertical-align:top}
1496 .celltoolbar label span{font-size:85%}
1496 .celltoolbar label span{font-size:85%}
1497 .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px}
1497 .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px}
1498 .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px}
1498 .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px}
1499 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:4px;-webkit-box-shadow:0 6px 10px -1px #adadad;-moz-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad}
1499 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:4px;-webkit-box-shadow:0 6px 10px -1px #adadad;-moz-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad}
1500 .completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000;width:auto}
1500 .completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000;width:auto}
1501 .completions select option.context{color:#0064cd}
1501 .completions select option.context{color:#0064cd}
1502 #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px}
1502 #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px}
1503 #menubar .navbar{margin-bottom:8px}
1503 #menubar .navbar{margin-bottom:8px}
1504 .nav-wrapper{border-bottom:1px solid #d4d4d4}
1504 .nav-wrapper{border-bottom:1px solid #d4d4d4}
1505 #menubar li.dropdown{line-height:12px}
1505 #menubar li.dropdown{line-height:12px}
1506 i.menu-icon{padding-top:4px}
1506 i.menu-icon{padding-top:4px}
1507 ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}
1507 ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}
1508 #notification_area{z-index:10}
1508 #notification_area{z-index:10}
1509 .indicator_area{color:#777;padding:4px 3px;margin:0;width:11px;z-index:10;text-align:center}
1509 .indicator_area{color:#777;padding:4px 3px;margin:0;width:11px;z-index:10;text-align:center}
1510 #kernel_indicator{margin-right:-16px}
1510 #kernel_indicator{margin-right:-16px}
1511 .edit_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f040"}
1511 .edit_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f040"}
1512 .command_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:' '}
1512 .command_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:' '}
1513 .kernel_idle_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f10c"}
1513 .kernel_idle_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f10c"}
1514 .kernel_busy_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111"}
1514 .kernel_busy_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111"}
1515 .notification_widget{color:#777;padding:1px 12px;margin:2px 4px;z-index:10;border:1px solid #ccc;border-radius:4px;background:rgba(240,240,240,0.5)}.notification_widget.span{padding-right:2px}
1515 .notification_widget{color:#777;padding:1px 12px;margin:2px 4px;z-index:10;border:1px solid #ccc;border-radius:4px;background:rgba(240,240,240,0.5)}.notification_widget.span{padding-right:2px}
1516 div#pager_splitter{height:8px}
1516 div#pager_splitter{height:8px}
1517 #pager-container{position:relative;padding:15px 0}
1517 #pager-container{position:relative;padding:15px 0}
1518 div#pager{font-size:14px;line-height:20px;overflow:auto;display:none}div#pager pre{font-size:13px;line-height:1.21429em;color:#000;background-color:#f7f7f7;padding:.4em}
1518 div#pager{font-size:14px;line-height:20px;overflow:auto;display:none}div#pager pre{font-size:13px;line-height:1.21429em;color:#000;background-color:#f7f7f7;padding:.4em}
1519 .quickhelp{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1519 .quickhelp{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1520 .shortcut_key{display:inline-block;width:20ex;text-align:right;font-family:monospace}
1520 .shortcut_key{display:inline-block;width:20ex;text-align:right;font-family:monospace}
1521 .shortcut_descr{display:inline-block;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1521 .shortcut_descr{display:inline-block;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1522 span#save_widget{padding:0 5px;margin-top:12px}
1522 span#save_widget{padding:0 5px;margin-top:12px}
1523 span#checkpoint_status,span#autosave_status{font-size:small}
1523 span#checkpoint_status,span#autosave_status{font-size:small}
1524 @media (max-width:767px){span#save_widget{font-size:small} span#checkpoint_status,span#autosave_status{font-size:x-small}}@media (max-width:767px){span#checkpoint_status,span#autosave_status{display:none}}@media (min-width:768px) and (max-width:979px){span#checkpoint_status{display:none} span#autosave_status{font-size:x-small}}.toolbar{padding:0 10px;margin-top:-5px}.toolbar select,.toolbar label{width:auto;height:26px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:0;padding-top:3px}
1524 @media (max-width:767px){span#save_widget{font-size:small} span#checkpoint_status,span#autosave_status{font-size:x-small}}@media (max-width:767px){span#checkpoint_status,span#autosave_status{display:none}}@media (min-width:768px) and (max-width:979px){span#checkpoint_status{display:none} span#autosave_status{font-size:x-small}}.toolbar{padding:0 10px;margin-top:-5px}.toolbar select,.toolbar label{width:auto;height:26px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:0;padding-top:3px}
1525 .toolbar .btn{padding:2px 8px}
1525 .toolbar .btn{padding:2px 8px}
1526 .toolbar .btn-group{margin-top:0}
1526 .toolbar .btn-group{margin-top:0}
1527 .toolbar-inner{border:none !important;-webkit-box-shadow:none !important;-moz-box-shadow:none !important;box-shadow:none !important}
1527 .toolbar-inner{border:none !important;-webkit-box-shadow:none !important;-moz-box-shadow:none !important;box-shadow:none !important}
1528 #maintoolbar{margin-bottom:0}
1528 #maintoolbar{margin-bottom:0}
1529 @-moz-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-webkit-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-moz-keyframes fadeIn{from{opacity:0} to{opacity:1}}@-webkit-keyframes fadeIn{from{opacity:0} to{opacity:1}}.bigtooltip{overflow:auto;height:200px;-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms}
1529 @-moz-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-webkit-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-moz-keyframes fadeIn{from{opacity:0} to{opacity:1}}@-webkit-keyframes fadeIn{from{opacity:0} to{opacity:1}}.bigtooltip{overflow:auto;height:200px;-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms}
1530 .smalltooltip{-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms;text-overflow:ellipsis;overflow:hidden;height:80px}
1530 .smalltooltip{-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms;text-overflow:ellipsis;overflow:hidden;height:80px}
1531 .tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}
1531 .tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}
1532 .tooltiptext{padding-right:30px}
1532 .tooltiptext{padding-right:30px}
1533 .ipython_tooltip{max-width:700px;-webkit-animation:fadeOut 400ms;-moz-animation:fadeOut 400ms;animation:fadeOut 400ms;-webkit-animation:fadeIn 400ms;-moz-animation:fadeIn 400ms;animation:fadeIn 400ms;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:#ababab 1px solid;outline:none;padding:3px;margin:0;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:4px;position:absolute;z-index:2}.ipython_tooltip a{float:right}
1533 .ipython_tooltip{max-width:700px;-webkit-animation:fadeOut 400ms;-moz-animation:fadeOut 400ms;animation:fadeOut 400ms;-webkit-animation:fadeIn 400ms;-moz-animation:fadeIn 400ms;animation:fadeIn 400ms;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:#ababab 1px solid;outline:none;padding:3px;margin:0;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:4px;position:absolute;z-index:2}.ipython_tooltip a{float:right}
1534 .ipython_tooltip .tooltiptext pre{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;font-size:100%;background-color:#f7f7f7}
1534 .ipython_tooltip .tooltiptext pre{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;font-size:100%;background-color:#f7f7f7}
1535 .pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}
1535 .pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}
1536 .pretooltiparrow:before{background-color:#f7f7f7;border:1px #ababab solid;z-index:11;content:"";position:absolute;left:15px;top:10px;width:25px;height:25px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg)}
1536 .pretooltiparrow:before{background-color:#f7f7f7;border:1px #ababab solid;z-index:11;content:"";position:absolute;left:15px;top:10px;width:25px;height:25px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg)}
@@ -1,362 +1,362 b''
1 {% extends "page.html" %}
1 {% extends "page.html" %}
2
2
3 {% block stylesheet %}
3 {% block stylesheet %}
4
4
5 {% if mathjax_url %}
5 {% if mathjax_url %}
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
7 {% endif %}
7 {% endif %}
8 <script type="text/javascript">
8 <script type="text/javascript">
9 // MathJax disabled, set as null to distingish from *missing* MathJax,
9 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 // where it will be undefined, and should prompt a dialog later.
10 // where it will be undefined, and should prompt a dialog later.
11 window.mathjax_url = "{{mathjax_url}}";
11 window.mathjax_url = "{{mathjax_url}}";
12 </script>
12 </script>
13
13
14 <link rel="stylesheet" href="{{ static_url("components/bootstrap-tour/build/css/bootstrap-tour.min.css") }}" type="text/css" />
14 <link rel="stylesheet" href="{{ static_url("components/bootstrap-tour/build/css/bootstrap-tour.min.css") }}" type="text/css" />
15 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
15 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
16
16
17 {{super()}}
17 {{super()}}
18
18
19 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
19 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
20
20
21 {% endblock %}
21 {% endblock %}
22
22
23 {% block params %}
23 {% block params %}
24
24
25 data-project="{{project}}"
25 data-project="{{project}}"
26 data-base-url="{{base_url}}"
26 data-base-url="{{base_url}}"
27 data-notebook-name="{{notebook_name}}"
27 data-notebook-name="{{notebook_name}}"
28 data-notebook-path="{{notebook_path}}"
28 data-notebook-path="{{notebook_path}}"
29 class="notebook_app"
29 class="notebook_app"
30
30
31 {% endblock %}
31 {% endblock %}
32
32
33
33
34 {% block header %}
34 {% block header %}
35
35
36 <span id="save_widget" class="nav pull-left">
36 <span id="save_widget" class="nav pull-left">
37 <span id="notebook_name"></span>
37 <span id="notebook_name"></span>
38 <span id="checkpoint_status"></span>
38 <span id="checkpoint_status"></span>
39 <span id="autosave_status"></span>
39 <span id="autosave_status"></span>
40 </span>
40 </span>
41
41
42 {% endblock %}
42 {% endblock %}
43
43
44
44
45 {% block site %}
45 {% block site %}
46
46
47 <div id="menubar-container" class="container">
47 <div id="menubar-container" class="container">
48 <div id="menubar">
48 <div id="menubar">
49 <div class="navbar">
49 <div class="navbar">
50 <div class="navbar-inner">
50 <div class="navbar-inner">
51 <div class="container">
51 <div class="container">
52 <ul id="menus" class="nav">
52 <ul id="menus" class="nav">
53 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
53 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
54 <ul id="file_menu" class="dropdown-menu">
54 <ul id="file_menu" class="dropdown-menu">
55 <li id="new_notebook"
55 <li id="new_notebook"
56 title="Make a new notebook (Opens a new window)">
56 title="Make a new notebook (Opens a new window)">
57 <a href="#">New</a></li>
57 <a href="#">New</a></li>
58 <li id="open_notebook"
58 <li id="open_notebook"
59 title="Opens a new window with the Dashboard view">
59 title="Opens a new window with the Dashboard view">
60 <a href="#">Open...</a></li>
60 <a href="#">Open...</a></li>
61 <!-- <hr/> -->
61 <!-- <hr/> -->
62 <li class="divider"></li>
62 <li class="divider"></li>
63 <li id="copy_notebook"
63 <li id="copy_notebook"
64 title="Open a copy of this notebook's contents and start a new kernel">
64 title="Open a copy of this notebook's contents and start a new kernel">
65 <a href="#">Make a Copy...</a></li>
65 <a href="#">Make a Copy...</a></li>
66 <li id="rename_notebook"><a href="#">Rename...</a></li>
66 <li id="rename_notebook"><a href="#">Rename...</a></li>
67 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
67 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
68 <!-- <hr/> -->
68 <!-- <hr/> -->
69 <li class="divider"></li>
69 <li class="divider"></li>
70 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
70 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
71 <ul class="dropdown-menu">
71 <ul class="dropdown-menu">
72 <li><a href="#"></a></li>
72 <li><a href="#"></a></li>
73 <li><a href="#"></a></li>
73 <li><a href="#"></a></li>
74 <li><a href="#"></a></li>
74 <li><a href="#"></a></li>
75 <li><a href="#"></a></li>
75 <li><a href="#"></a></li>
76 <li><a href="#"></a></li>
76 <li><a href="#"></a></li>
77 </ul>
77 </ul>
78 </li>
78 </li>
79 <li class="divider"></li>
79 <li class="divider"></li>
80 <li id="print_preview"><a href="#">Print Preview</a></li>
80 <li id="print_preview"><a href="#">Print Preview</a></li>
81 <li class="dropdown-submenu"><a href="#">Download as</a>
81 <li class="dropdown-submenu"><a href="#">Download as</a>
82 <ul class="dropdown-menu">
82 <ul class="dropdown-menu">
83 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
83 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
84 <li id="download_py"><a href="#">Python (.py)</a></li>
84 <li id="download_py"><a href="#">Python (.py)</a></li>
85 <li id="download_html"><a href="#">HTML (.html)</a></li>
85 <li id="download_html"><a href="#">HTML (.html)</a></li>
86 <li id="download_rst"><a href="#">reST (.rst)</a></li>
86 <li id="download_rst"><a href="#">reST (.rst)</a></li>
87 </ul>
87 </ul>
88 </li>
88 </li>
89 <li class="divider"></li>
89 <li class="divider"></li>
90 <li id="trust_notebook"
90 <li id="trust_notebook"
91 title="Trust the output of this notebook">
91 title="Trust the output of this notebook">
92 <a href="#" >Trust Notebook</a></li>
92 <a href="#" >Trust Notebook</a></li>
93 <li class="divider"></li>
93 <li class="divider"></li>
94 <li id="kill_and_exit"
94 <li id="kill_and_exit"
95 title="Shutdown this notebook's kernel, and close this window">
95 title="Shutdown this notebook's kernel, and close this window">
96 <a href="#" >Close and halt</a></li>
96 <a href="#" >Close and halt</a></li>
97 </ul>
97 </ul>
98 </li>
98 </li>
99 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
99 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
100 <ul id="edit_menu" class="dropdown-menu">
100 <ul id="edit_menu" class="dropdown-menu">
101 <li id="cut_cell"><a href="#">Cut Cell</a></li>
101 <li id="cut_cell"><a href="#">Cut Cell</a></li>
102 <li id="copy_cell"><a href="#">Copy Cell</a></li>
102 <li id="copy_cell"><a href="#">Copy Cell</a></li>
103 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
103 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
104 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
104 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
105 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
105 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
106 <li id="delete_cell"><a href="#">Delete Cell</a></li>
106 <li id="delete_cell"><a href="#">Delete Cell</a></li>
107 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
107 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
108 <li class="divider"></li>
108 <li class="divider"></li>
109 <li id="split_cell"><a href="#">Split Cell</a></li>
109 <li id="split_cell"><a href="#">Split Cell</a></li>
110 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
110 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
111 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
111 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
112 <li class="divider"></li>
112 <li class="divider"></li>
113 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
113 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
114 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
114 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
115 <li class="divider"></li>
115 <li class="divider"></li>
116 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
116 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
117 </ul>
117 </ul>
118 </li>
118 </li>
119 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
119 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
120 <ul id="view_menu" class="dropdown-menu">
120 <ul id="view_menu" class="dropdown-menu">
121 <li id="toggle_header"
121 <li id="toggle_header"
122 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
122 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
123 <a href="#">Toggle Header</a></li>
123 <a href="#">Toggle Header</a></li>
124 <li id="toggle_toolbar"
124 <li id="toggle_toolbar"
125 title="Show/Hide the action icons (below menu bar)">
125 title="Show/Hide the action icons (below menu bar)">
126 <a href="#">Toggle Toolbar</a></li>
126 <a href="#">Toggle Toolbar</a></li>
127 </ul>
127 </ul>
128 </li>
128 </li>
129 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
129 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
130 <ul id="insert_menu" class="dropdown-menu">
130 <ul id="insert_menu" class="dropdown-menu">
131 <li id="insert_cell_above"
131 <li id="insert_cell_above"
132 title="Insert an empty Code cell above the currently active cell">
132 title="Insert an empty Code cell above the currently active cell">
133 <a href="#">Insert Cell Above</a></li>
133 <a href="#">Insert Cell Above</a></li>
134 <li id="insert_cell_below"
134 <li id="insert_cell_below"
135 title="Insert an empty Code cell below the currently active cell">
135 title="Insert an empty Code cell below the currently active cell">
136 <a href="#">Insert Cell Below</a></li>
136 <a href="#">Insert Cell Below</a></li>
137 </ul>
137 </ul>
138 </li>
138 </li>
139 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
139 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
140 <ul id="cell_menu" class="dropdown-menu">
140 <ul id="cell_menu" class="dropdown-menu">
141 <li id="run_cell" title="Run this cell, and move cursor to the next one">
141 <li id="run_cell" title="Run this cell, and move cursor to the next one">
142 <a href="#">Run</a></li>
142 <a href="#">Run</a></li>
143 <li id="run_cell_select_below" title="Run this cell, select below">
143 <li id="run_cell_select_below" title="Run this cell, select below">
144 <a href="#">Run and Select Below</a></li>
144 <a href="#">Run and Select Below</a></li>
145 <li id="run_cell_insert_below" title="Run this cell, insert below">
145 <li id="run_cell_insert_below" title="Run this cell, insert below">
146 <a href="#">Run and Insert Below</a></li>
146 <a href="#">Run and Insert Below</a></li>
147 <li id="run_all_cells" title="Run all cells in the notebook">
147 <li id="run_all_cells" title="Run all cells in the notebook">
148 <a href="#">Run All</a></li>
148 <a href="#">Run All</a></li>
149 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
149 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
150 <a href="#">Run All Above</a></li>
150 <a href="#">Run All Above</a></li>
151 <li id="run_all_cells_below" title="Run this cell and all cells below it">
151 <li id="run_all_cells_below" title="Run this cell and all cells below it">
152 <a href="#">Run All Below</a></li>
152 <a href="#">Run All Below</a></li>
153 <li class="divider"></li>
153 <li class="divider"></li>
154 <li id="change_cell_type" class="dropdown-submenu"
154 <li id="change_cell_type" class="dropdown-submenu"
155 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
155 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
156 <a href="#">Cell Type</a>
156 <a href="#">Cell Type</a>
157 <ul class="dropdown-menu">
157 <ul class="dropdown-menu">
158 <li id="to_code"
158 <li id="to_code"
159 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
159 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
160 <a href="#">Code</a></li>
160 <a href="#">Code</a></li>
161 <li id="to_markdown"
161 <li id="to_markdown"
162 title="Contents will be rendered as HTML and serve as explanatory text">
162 title="Contents will be rendered as HTML and serve as explanatory text">
163 <a href="#">Markdown</a></li>
163 <a href="#">Markdown</a></li>
164 <li id="to_raw"
164 <li id="to_raw"
165 title="Contents will pass through nbconvert unmodified">
165 title="Contents will pass through nbconvert unmodified">
166 <a href="#">Raw NBConvert</a></li>
166 <a href="#">Raw NBConvert</a></li>
167 <li id="to_heading1"><a href="#">Heading 1</a></li>
167 <li id="to_heading1"><a href="#">Heading 1</a></li>
168 <li id="to_heading2"><a href="#">Heading 2</a></li>
168 <li id="to_heading2"><a href="#">Heading 2</a></li>
169 <li id="to_heading3"><a href="#">Heading 3</a></li>
169 <li id="to_heading3"><a href="#">Heading 3</a></li>
170 <li id="to_heading4"><a href="#">Heading 4</a></li>
170 <li id="to_heading4"><a href="#">Heading 4</a></li>
171 <li id="to_heading5"><a href="#">Heading 5</a></li>
171 <li id="to_heading5"><a href="#">Heading 5</a></li>
172 <li id="to_heading6"><a href="#">Heading 6</a></li>
172 <li id="to_heading6"><a href="#">Heading 6</a></li>
173 </ul>
173 </ul>
174 </li>
174 </li>
175 <li class="divider"></li>
175 <li class="divider"></li>
176 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
176 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
177 <ul class="dropdown-menu">
177 <ul class="dropdown-menu">
178 <li id="toggle_current_output"
178 <li id="toggle_current_output"
179 title="Hide/Show the output of the current cell">
179 title="Hide/Show the output of the current cell">
180 <a href="#">Toggle</a>
180 <a href="#">Toggle</a>
181 </li>
181 </li>
182 <li id="toggle_current_output_scroll"
182 <li id="toggle_current_output_scroll"
183 title="Scroll the output of the current cell">
183 title="Scroll the output of the current cell">
184 <a href="#">Toggle Scrolling</a>
184 <a href="#">Toggle Scrolling</a>
185 </li>
185 </li>
186 <li id="clear_current_output"
186 <li id="clear_current_output"
187 title="Clear the output of the current cell">
187 title="Clear the output of the current cell">
188 <a href="#">Clear</a>
188 <a href="#">Clear</a>
189 </li>
189 </li>
190 </ul>
190 </ul>
191 </li>
191 </li>
192 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
192 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
193 <ul class="dropdown-menu">
193 <ul class="dropdown-menu">
194 <li id="toggle_all_output"
194 <li id="toggle_all_output"
195 title="Hide/Show the output of all cells">
195 title="Hide/Show the output of all cells">
196 <a href="#">Toggle</a>
196 <a href="#">Toggle</a>
197 </li>
197 </li>
198 <li id="toggle_all_output_scroll"
198 <li id="toggle_all_output_scroll"
199 title="Scroll the output of all cells">
199 title="Scroll the output of all cells">
200 <a href="#">Toggle Scrolling</a>
200 <a href="#">Toggle Scrolling</a>
201 </li>
201 </li>
202 <li id="clear_all_output"
202 <li id="clear_all_output"
203 title="Clear the output of all cells">
203 title="Clear the output of all cells">
204 <a href="#">Clear</a>
204 <a href="#">Clear</a>
205 </li>
205 </li>
206 </ul>
206 </ul>
207 </li>
207 </li>
208 </ul>
208 </ul>
209 </li>
209 </li>
210 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
210 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
211 <ul id="kernel_menu" class="dropdown-menu">
211 <ul id="kernel_menu" class="dropdown-menu">
212 <li id="int_kernel"
212 <li id="int_kernel"
213 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
213 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
214 <a href="#">Interrupt</a></li>
214 <a href="#">Interrupt</a></li>
215 <li id="restart_kernel"
215 <li id="restart_kernel"
216 title="Restart the Kernel">
216 title="Restart the Kernel">
217 <a href="#">Restart</a></li>
217 <a href="#">Restart</a></li>
218 </ul>
218 </ul>
219 </li>
219 </li>
220 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
220 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
221 <ul id="help_menu" class="dropdown-menu">
221 <ul id="help_menu" class="dropdown-menu">
222 <li id="notebook_tour" title="A quick tour of the notebook user interface"><a href="#">User Interface Tour</a></li>
222 <li id="notebook_tour" title="A quick tour of the notebook user interface"><a href="#">User Interface Tour</a></li>
223 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
223 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
224 <li class="divider"></li>
224 <li class="divider"></li>
225 {% set
225 {% set
226 sections = (
226 sections = (
227 (
227 (
228 ("http://ipython.org/documentation.html","IPython Help",True),
228 ("http://ipython.org/documentation.html","IPython Help",True),
229 ("http://nbviewer.ipython.org/github/ipython/ipython/tree/master/examples/notebooks/", "Notebook Examples", True),
229 ("http://nbviewer.ipython.org/github/ipython/ipython/tree/master/examples/notebooks/", "Notebook Examples", True),
230 ("http://ipython.org/ipython-doc/stable/interactive/notebook.html","Notebook Help",True),
230 ("http://ipython.org/ipython-doc/2/notebook/notebook.html","Notebook Help",True),
231 ("http://ipython.org/ipython-doc/dev/interactive/cm_keyboard.html","Editor Shortcuts",True),
231 ("http://ipython.org/ipython-doc/2/notebook/cm_keyboard.html","Editor Shortcuts",True),
232 ),(
232 ),(
233 ("http://docs.python.org","Python",True),
233 ("http://docs.python.org","Python",True),
234 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
234 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
235 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
235 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
236 ("http://matplotlib.org/contents.html","Matplotlib",True),
236 ("http://matplotlib.org/contents.html","Matplotlib",True),
237 ("http://docs.sympy.org/dev/index.html","SymPy",True),
237 ("http://docs.sympy.org/latest/index.html","SymPy",True),
238 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
238 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
239 )
239 )
240 )
240 )
241 %}
241 %}
242
242
243 {% for helplinks in sections %}
243 {% for helplinks in sections %}
244 {% for link in helplinks %}
244 {% for link in helplinks %}
245 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
245 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
246 {{'<i class="icon-external-link menu-icon pull-right"></i>' if link[2]}}
246 {{'<i class="icon-external-link menu-icon pull-right"></i>' if link[2]}}
247 {{link[1]}}
247 {{link[1]}}
248 </a></li>
248 </a></li>
249 {% endfor %}
249 {% endfor %}
250 {% if not loop.last %}
250 {% if not loop.last %}
251 <li class="divider"></li>
251 <li class="divider"></li>
252 {% endif %}
252 {% endif %}
253 {% endfor %}
253 {% endfor %}
254 </li>
254 </li>
255 </ul>
255 </ul>
256 </li>
256 </li>
257 </ul>
257 </ul>
258 <div id="kernel_indicator" class="indicator_area pull-right">
258 <div id="kernel_indicator" class="indicator_area pull-right">
259 <i id="kernel_indicator_icon"></i>
259 <i id="kernel_indicator_icon"></i>
260 </div>
260 </div>
261 <div id="modal_indicator" class="indicator_area pull-right">
261 <div id="modal_indicator" class="indicator_area pull-right">
262 <i id="modal_indicator_icon"></i>
262 <i id="modal_indicator_icon"></i>
263 </div>
263 </div>
264 <div id="notification_area"></div>
264 <div id="notification_area"></div>
265 </div>
265 </div>
266 </div>
266 </div>
267 </div>
267 </div>
268 </div>
268 </div>
269 <div id="maintoolbar" class="navbar">
269 <div id="maintoolbar" class="navbar">
270 <div class="toolbar-inner navbar-inner navbar-nobg">
270 <div class="toolbar-inner navbar-inner navbar-nobg">
271 <div id="maintoolbar-container" class="container"></div>
271 <div id="maintoolbar-container" class="container"></div>
272 </div>
272 </div>
273 </div>
273 </div>
274 </div>
274 </div>
275
275
276 <div id="ipython-main-app">
276 <div id="ipython-main-app">
277
277
278 <div id="notebook_panel">
278 <div id="notebook_panel">
279 <div id="notebook"></div>
279 <div id="notebook"></div>
280 <div id="pager_splitter"></div>
280 <div id="pager_splitter"></div>
281 <div id="pager">
281 <div id="pager">
282 <div id='pager_button_area'>
282 <div id='pager_button_area'>
283 </div>
283 </div>
284 <div id="pager-container" class="container"></div>
284 <div id="pager-container" class="container"></div>
285 </div>
285 </div>
286 </div>
286 </div>
287
287
288 </div>
288 </div>
289 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
289 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
290
290
291
291
292 {% endblock %}
292 {% endblock %}
293
293
294
294
295 {% block script %}
295 {% block script %}
296
296
297 {{super()}}
297 {{super()}}
298
298
299 <script src="{{ static_url("components/google-caja/html-css-sanitizer-minified.js") }}" charset="utf-8"></script>
299 <script src="{{ static_url("components/google-caja/html-css-sanitizer-minified.js") }}" charset="utf-8"></script>
300 <script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
300 <script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
301 <script type="text/javascript">
301 <script type="text/javascript">
302 CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js", include_version=False) }}";
302 CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js", include_version=False) }}";
303 </script>
303 </script>
304 <script src="{{ static_url("components/codemirror/addon/mode/loadmode.js") }}" charset="utf-8"></script>
304 <script src="{{ static_url("components/codemirror/addon/mode/loadmode.js") }}" charset="utf-8"></script>
305 <script src="{{ static_url("components/codemirror/addon/mode/multiplex.js") }}" charset="utf-8"></script>
305 <script src="{{ static_url("components/codemirror/addon/mode/multiplex.js") }}" charset="utf-8"></script>
306 <script src="{{ static_url("components/codemirror/addon/mode/overlay.js") }}" charset="utf-8"></script>
306 <script src="{{ static_url("components/codemirror/addon/mode/overlay.js") }}" charset="utf-8"></script>
307 <script src="{{ static_url("components/codemirror/addon/edit/matchbrackets.js") }}" charset="utf-8"></script>
307 <script src="{{ static_url("components/codemirror/addon/edit/matchbrackets.js") }}" charset="utf-8"></script>
308 <script src="{{ static_url("components/codemirror/addon/edit/closebrackets.js") }}" charset="utf-8"></script>
308 <script src="{{ static_url("components/codemirror/addon/edit/closebrackets.js") }}" charset="utf-8"></script>
309 <script src="{{ static_url("components/codemirror/addon/comment/comment.js") }}" charset="utf-8"></script>
309 <script src="{{ static_url("components/codemirror/addon/comment/comment.js") }}" charset="utf-8"></script>
310 <script src="{{ static_url("components/codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
310 <script src="{{ static_url("components/codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
311 <script src="{{ static_url("components/codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
311 <script src="{{ static_url("components/codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
312 <script src="{{ static_url("components/codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
312 <script src="{{ static_url("components/codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
313 <script src="{{ static_url("components/codemirror/mode/css/css.js") }}" charset="utf-8"></script>
313 <script src="{{ static_url("components/codemirror/mode/css/css.js") }}" charset="utf-8"></script>
314 <script src="{{ static_url("components/codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
314 <script src="{{ static_url("components/codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
315 <script src="{{ static_url("components/codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
315 <script src="{{ static_url("components/codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
316 <script src="{{ static_url("components/codemirror/mode/gfm/gfm.js") }}" charset="utf-8"></script>
316 <script src="{{ static_url("components/codemirror/mode/gfm/gfm.js") }}" charset="utf-8"></script>
317 <script src="{{ static_url("components/codemirror/mode/python/python.js") }}" charset="utf-8"></script>
317 <script src="{{ static_url("components/codemirror/mode/python/python.js") }}" charset="utf-8"></script>
318 <script src="{{ static_url("notebook/js/codemirror-ipython.js") }}" charset="utf-8"></script>
318 <script src="{{ static_url("notebook/js/codemirror-ipython.js") }}" charset="utf-8"></script>
319
319
320 <script src="{{ static_url("components/highlight.js/build/highlight.pack.js") }}" charset="utf-8"></script>
320 <script src="{{ static_url("components/highlight.js/build/highlight.pack.js") }}" charset="utf-8"></script>
321
321
322 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
322 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
323
323
324 <script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
324 <script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
325 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
325 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
326 <script src="{{ static_url("base/js/keyboard.js") }}" type="text/javascript" charset="utf-8"></script>
326 <script src="{{ static_url("base/js/keyboard.js") }}" type="text/javascript" charset="utf-8"></script>
327 <script src="{{ static_url("base/js/security.js") }}" type="text/javascript" charset="utf-8"></script>
327 <script src="{{ static_url("base/js/security.js") }}" type="text/javascript" charset="utf-8"></script>
328 <script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
328 <script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
329 <script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
329 <script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
330 <script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
330 <script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
331 <script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
331 <script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
332 <script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
332 <script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
333 <script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
333 <script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
334 <script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
334 <script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
335 <script src="{{ static_url("notebook/js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
335 <script src="{{ static_url("notebook/js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
336 <script src="{{ static_url("notebook/js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
336 <script src="{{ static_url("notebook/js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
337 <script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
337 <script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
338 <script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
338 <script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
339 <script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
339 <script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
340 <script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
340 <script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
341 <script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
341 <script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
342 <script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
342 <script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
343 <script src="{{ static_url("notebook/js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
343 <script src="{{ static_url("notebook/js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
344 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
344 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
345 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
345 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
346 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
346 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
347 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
347 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
348 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
348 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
349 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
349 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
350 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
350 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
351 <script src="{{ static_url("notebook/js/tour.js") }}" type="text/javascript" charset="utf-8"></script>
351 <script src="{{ static_url("notebook/js/tour.js") }}" type="text/javascript" charset="utf-8"></script>
352
352
353 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
353 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
354 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
354 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
355
355
356 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
356 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
357
357
358 <script src="{{ static_url("notebook/js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
358 <script src="{{ static_url("notebook/js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
359 <script src="{{ static_url("notebook/js/celltoolbarpresets/rawcell.js") }}" type="text/javascript" charset="utf-8"></script>
359 <script src="{{ static_url("notebook/js/celltoolbarpresets/rawcell.js") }}" type="text/javascript" charset="utf-8"></script>
360 <script src="{{ static_url("notebook/js/celltoolbarpresets/slideshow.js") }}" type="text/javascript" charset="utf-8"></script>
360 <script src="{{ static_url("notebook/js/celltoolbarpresets/slideshow.js") }}" type="text/javascript" charset="utf-8"></script>
361
361
362 {% endblock %}
362 {% endblock %}
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from IPython/html/tests/notebook/merge_cells.js to IPython/html/tests/notebook/merge_cells_api.js
NO CONTENT: file renamed from IPython/html/tests/notebook/merge_cells.js to IPython/html/tests/notebook/merge_cells_api.js
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from docs/source/_templates/htmlnotebook.html to docs/source/_templates/notebook_redirect.html
NO CONTENT: file renamed from docs/source/_templates/htmlnotebook.html to docs/source/_templates/notebook_redirect.html
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file renamed from docs/source/interactive/cm_keyboard.rst to docs/source/notebook/cm_keyboard.rst
NO CONTENT: file renamed from docs/source/interactive/cm_keyboard.rst to docs/source/notebook/cm_keyboard.rst
1 NO CONTENT: file renamed from docs/source/interactive/nbconvert.rst to docs/source/notebook/nbconvert.rst
NO CONTENT: file renamed from docs/source/interactive/nbconvert.rst to docs/source/notebook/nbconvert.rst
1 NO CONTENT: file renamed from docs/source/interactive/notebook.rst to docs/source/notebook/notebook.rst
NO CONTENT: file renamed from docs/source/interactive/notebook.rst to docs/source/notebook/notebook.rst
1 NO CONTENT: file renamed from docs/source/interactive/public_server.rst to docs/source/notebook/public_server.rst
NO CONTENT: file renamed from docs/source/interactive/public_server.rst to docs/source/notebook/public_server.rst
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed, binary diff hidden
NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now