##// 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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 2 The IPython licensing terms
3 3 =============================
4 4
5 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
9 Copyright (c) 2001-2007, Fernando Perez. <fernando.perez@colorado.edu>
10 Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
11 Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
8 - Copyright (c) 2008-2014, IPython Development Team
9 - Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
10 - Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
11 - Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
12 12
13 13 All rights reserved.
14 14
15 15 Redistribution and use in source and binary forms, with or without
16 16 modification, are permitted provided that the following conditions are met:
17 17
18 18 Redistributions of source code must retain the above copyright notice, this
19 19 list of conditions and the following disclaimer.
20 20
21 21 Redistributions in binary form must reproduce the above copyright notice, this
22 22 list of conditions and the following disclaimer in the documentation and/or
23 23 other materials provided with the distribution.
24 24
25 25 Neither the name of the IPython Development Team nor the names of its
26 26 contributors may be used to endorse or promote products derived from this
27 27 software without specific prior written permission.
28 28
29 29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
30 30 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31 31 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32 32 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
33 33 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 34 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 35 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36 36 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 37 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 39
40 40 About the IPython Development Team
41 41 ----------------------------------
42 42
43 43 Fernando Perez began IPython in 2001 based on code from Janko Hauser
44 44 <jhauser@zscout.de> and Nathaniel Gray <n8gray@caltech.edu>. Fernando is still
45 45 the project lead.
46 46
47 47 The IPython Development Team is the set of all contributors to the IPython
48 48 project. This includes all of the IPython subprojects. A full list with
49 49 details is kept in the documentation directory, in the file
50 50 ``about/credits.txt``.
51 51
52 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:
54
55 * Brian E. Granger
56 * Jonathan March
57 * Evan Patterson
58 * Fernando Perez
59 * Min Ragan-Kelley
60 * Robert Kern
61
53 https://github.com/ipython/.
62 54
63 55 Our Copyright Policy
64 56 --------------------
65 57
66 58 IPython uses a shared copyright model. Each contributor maintains copyright
67 59 over their contributions to IPython. But, it is important to note that these
68 60 contributions are typically only changes to the repositories. Thus, the IPython
69 61 source code, in its entirety is not the copyright of any single person or
70 62 institution. Instead, it is the collective copyright of the entire IPython
71 63 Development Team. If individual contributors want to maintain a record of what
72 64 changes/contributions they have specific copyright on, they should indicate
73 65 their copyright in the commit message of the change, when they commit the
74 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 69 to indicate the copyright and license terms:
78 70
79 #-----------------------------------------------------------------------------
80 # Copyright (c) 2010, IPython Development Team.
81 #
82 # 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 #-----------------------------------------------------------------------------
71 ::
72
73 # Copyright (c) IPython Development Team.
74 # Distributed under the terms of the Modified BSD License.
@@ -1,811 +1,854 b''
1 1 """ History related magics and functionality """
2 2 #-----------------------------------------------------------------------------
3 3 # Copyright (C) 2010-2011 The IPython Development Team.
4 4 #
5 5 # Distributed under the terms of the BSD License.
6 6 #
7 7 # The full license is in the file COPYING.txt, distributed with this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 from __future__ import print_function
14 14
15 15 # Stdlib imports
16 16 import atexit
17 17 import datetime
18 18 import os
19 19 import re
20 20 try:
21 21 import sqlite3
22 22 except ImportError:
23 23 try:
24 24 from pysqlite2 import dbapi2 as sqlite3
25 25 except ImportError:
26 26 sqlite3 = None
27 27 import threading
28 28
29 29 # Our own packages
30 30 from IPython.config.configurable import Configurable
31 31 from IPython.external.decorator import decorator
32 from IPython.utils.decorators import undoc
32 33 from IPython.utils.path import locate_profile
33 34 from IPython.utils import py3compat
34 35 from IPython.utils.traitlets import (
35 36 Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError,
36 37 )
37 38 from IPython.utils.warn import warn
38 39
39 40 #-----------------------------------------------------------------------------
40 41 # Classes and functions
41 42 #-----------------------------------------------------------------------------
42 43
44 @undoc
43 45 class DummyDB(object):
44 46 """Dummy DB that will act as a black hole for history.
45 47
46 48 Only used in the absence of sqlite"""
47 49 def execute(*args, **kwargs):
48 50 return []
49 51
50 52 def commit(self, *args, **kwargs):
51 53 pass
52 54
53 55 def __enter__(self, *args, **kwargs):
54 56 pass
55 57
56 58 def __exit__(self, *args, **kwargs):
57 59 pass
58 60
59 61
60 62 @decorator
61 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 65 if sqlite3 is None or not self.enabled:
64 66 return []
65 67 else:
66 68 return f(self, *a, **kw)
67 69
68 70
69 71 if sqlite3 is not None:
70 72 DatabaseError = sqlite3.DatabaseError
71 73 else:
74 @undoc
72 75 class DatabaseError(Exception):
73 76 "Dummy exception when sqlite could not be imported. Should never occur."
74 77
75 78 @decorator
76 79 def catch_corrupt_db(f, self, *a, **kw):
77 80 """A decorator which wraps HistoryAccessor method calls to catch errors from
78 81 a corrupt SQLite database, move the old database out of the way, and create
79 82 a new one.
80 83 """
81 84 try:
82 85 return f(self, *a, **kw)
83 86 except DatabaseError:
84 87 if os.path.isfile(self.hist_file):
85 88 # Try to move the file out of the way
86 89 base,ext = os.path.splitext(self.hist_file)
87 90 newpath = base + '-corrupt' + ext
88 91 os.rename(self.hist_file, newpath)
89 92 self.init_db()
90 93 print("ERROR! History file wasn't a valid SQLite database.",
91 94 "It was moved to %s" % newpath, "and a new file created.")
92 95 return []
93 96
94 97 else:
95 98 # The hist_file is probably :memory: or something else.
96 99 raise
97 100
98 101
99 102
100 103 class HistoryAccessor(Configurable):
101 104 """Access the history database without adding to it.
102 105
103 106 This is intended for use by standalone history tools. IPython shells use
104 107 HistoryManager, below, which is a subclass of this."""
105 108
106 109 # String holding the path to the history file
107 110 hist_file = Unicode(config=True,
108 111 help="""Path to file to use for SQLite history database.
109 112
110 113 By default, IPython will put the history database in the IPython
111 114 profile directory. If you would rather share one history among
112 115 profiles, you can set this value in each, so that they are consistent.
113 116
114 117 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
115 118 mounts. If you see IPython hanging, try setting this to something on a
116 119 local disk, e.g::
117 120
118 121 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
119 122
120 123 """)
121 124
122 125 enabled = Bool(True, config=True,
123 126 help="""enable the SQLite history
124 127
125 128 set enabled=False to disable the SQLite history,
126 129 in which case there will be no stored history, no SQLite connection,
127 130 and no background saving thread. This may be necessary in some
128 131 threaded environments where IPython is embedded.
129 132 """
130 133 )
131 134
132 135 connection_options = Dict(config=True,
133 136 help="""Options for configuring the SQLite connection
134 137
135 138 These options are passed as keyword args to sqlite3.connect
136 139 when establishing database conenctions.
137 140 """
138 141 )
139 142
140 143 # The SQLite database
141 144 db = Any()
142 145 def _db_changed(self, name, old, new):
143 146 """validate the db, since it can be an Instance of two different types"""
144 147 connection_types = (DummyDB,)
145 148 if sqlite3 is not None:
146 149 connection_types = (DummyDB, sqlite3.Connection)
147 150 if not isinstance(new, connection_types):
148 151 msg = "%s.db must be sqlite3 Connection or DummyDB, not %r" % \
149 152 (self.__class__.__name__, new)
150 153 raise TraitError(msg)
151 154
152 155 def __init__(self, profile='default', hist_file=u'', **traits):
153 156 """Create a new history accessor.
154 157
155 158 Parameters
156 159 ----------
157 160 profile : str
158 161 The name of the profile from which to open history.
159 162 hist_file : str
160 163 Path to an SQLite history database stored by IPython. If specified,
161 164 hist_file overrides profile.
162 config :
165 config : :class:`~IPython.config.loader.Config`
163 166 Config object. hist_file can also be set through this.
164 167 """
165 168 # We need a pointer back to the shell for various tasks.
166 169 super(HistoryAccessor, self).__init__(**traits)
167 170 # defer setting hist_file from kwarg until after init,
168 171 # otherwise the default kwarg value would clobber any value
169 172 # set by config
170 173 if hist_file:
171 174 self.hist_file = hist_file
172 175
173 176 if self.hist_file == u'':
174 177 # No one has set the hist_file, yet.
175 178 self.hist_file = self._get_hist_file_name(profile)
176 179
177 180 if sqlite3 is None and self.enabled:
178 181 warn("IPython History requires SQLite, your history will not be saved")
179 182 self.enabled = False
180 183
181 184 self.init_db()
182 185
183 186 def _get_hist_file_name(self, profile='default'):
184 187 """Find the history file for the given profile name.
185 188
186 189 This is overridden by the HistoryManager subclass, to use the shell's
187 190 active profile.
188 191
189 192 Parameters
190 193 ----------
191 194 profile : str
192 195 The name of a profile which has a history file.
193 196 """
194 197 return os.path.join(locate_profile(profile), 'history.sqlite')
195 198
196 199 @catch_corrupt_db
197 200 def init_db(self):
198 201 """Connect to the database, and create tables if necessary."""
199 202 if not self.enabled:
200 203 self.db = DummyDB()
201 204 return
202 205
203 206 # use detect_types so that timestamps return datetime objects
204 207 kwargs = dict(detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
205 208 kwargs.update(self.connection_options)
206 209 self.db = sqlite3.connect(self.hist_file, **kwargs)
207 210 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
208 211 primary key autoincrement, start timestamp,
209 212 end timestamp, num_cmds integer, remark text)""")
210 213 self.db.execute("""CREATE TABLE IF NOT EXISTS history
211 214 (session integer, line integer, source text, source_raw text,
212 215 PRIMARY KEY (session, line))""")
213 216 # Output history is optional, but ensure the table's there so it can be
214 217 # enabled later.
215 218 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
216 219 (session integer, line integer, output text,
217 220 PRIMARY KEY (session, line))""")
218 221 self.db.commit()
219 222
220 223 def writeout_cache(self):
221 224 """Overridden by HistoryManager to dump the cache before certain
222 225 database lookups."""
223 226 pass
224 227
225 228 ## -------------------------------
226 229 ## Methods for retrieving history:
227 230 ## -------------------------------
228 231 def _run_sql(self, sql, params, raw=True, output=False):
229 232 """Prepares and runs an SQL query for the history database.
230 233
231 234 Parameters
232 235 ----------
233 236 sql : str
234 237 Any filtering expressions to go after SELECT ... FROM ...
235 238 params : tuple
236 239 Parameters passed to the SQL query (to replace "?")
237 240 raw, output : bool
238 241 See :meth:`get_range`
239 242
240 243 Returns
241 244 -------
242 245 Tuples as :meth:`get_range`
243 246 """
244 247 toget = 'source_raw' if raw else 'source'
245 248 sqlfrom = "history"
246 249 if output:
247 250 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
248 251 toget = "history.%s, output_history.output" % toget
249 252 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
250 253 (toget, sqlfrom) + sql, params)
251 254 if output: # Regroup into 3-tuples, and parse JSON
252 255 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
253 256 return cur
254 257
255 258 @needs_sqlite
256 259 @catch_corrupt_db
257 def get_session_info(self, session=0):
258 """get info about a session
260 def get_session_info(self, session):
261 """Get info about a session.
259 262
260 263 Parameters
261 264 ----------
262 265
263 266 session : int
264 Session number to retrieve. The current session is 0, and negative
265 numbers count back from current session, so -1 is previous session.
267 Session number to retrieve.
266 268
267 269 Returns
268 270 -------
269
270 (session_id [int], start [datetime], end [datetime], num_cmds [int],
271 remark [unicode])
272
273 Sessions that are running or did not exit cleanly will have `end=None`
274 and `num_cmds=None`.
275
271
272 session_id : int
273 Session ID number
274 start : datetime
275 Timestamp for the start of the session.
276 end : datetime
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 283 query = "SELECT * from sessions where session == ?"
282 284 return self.db.execute(query, (session,)).fetchone()
283 285
284 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 297 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
286 298 """Get the last n lines from the history database.
287 299
288 300 Parameters
289 301 ----------
290 302 n : int
291 303 The number of lines to get
292 304 raw, output : bool
293 305 See :meth:`get_range`
294 306 include_latest : bool
295 307 If False (default), n+1 lines are fetched, and the latest one
296 308 is discarded. This is intended to be used where the function
297 309 is called by a user command, which it should not return.
298 310
299 311 Returns
300 312 -------
301 313 Tuples as :meth:`get_range`
302 314 """
303 315 self.writeout_cache()
304 316 if not include_latest:
305 317 n += 1
306 318 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
307 319 (n,), raw=raw, output=output)
308 320 if not include_latest:
309 321 return reversed(list(cur)[1:])
310 322 return reversed(list(cur))
311 323
312 324 @catch_corrupt_db
313 325 def search(self, pattern="*", raw=True, search_raw=True,
314 326 output=False, n=None, unique=False):
315 327 """Search the database using unix glob-style matching (wildcards
316 328 * and ?).
317 329
318 330 Parameters
319 331 ----------
320 332 pattern : str
321 333 The wildcarded pattern to match when searching
322 334 search_raw : bool
323 335 If True, search the raw input, otherwise, the parsed input
324 336 raw, output : bool
325 337 See :meth:`get_range`
326 338 n : None or int
327 339 If an integer is given, it defines the limit of
328 340 returned entries.
329 341 unique : bool
330 342 When it is true, return only unique entries.
331 343
332 344 Returns
333 345 -------
334 346 Tuples as :meth:`get_range`
335 347 """
336 348 tosearch = "source_raw" if search_raw else "source"
337 349 if output:
338 350 tosearch = "history." + tosearch
339 351 self.writeout_cache()
340 352 sqlform = "WHERE %s GLOB ?" % tosearch
341 353 params = (pattern,)
342 354 if unique:
343 355 sqlform += ' GROUP BY {0}'.format(tosearch)
344 356 if n is not None:
345 357 sqlform += " ORDER BY session DESC, line DESC LIMIT ?"
346 358 params += (n,)
347 359 elif unique:
348 360 sqlform += " ORDER BY session, line"
349 361 cur = self._run_sql(sqlform, params, raw=raw, output=output)
350 362 if n is not None:
351 363 return reversed(list(cur))
352 364 return cur
353 365
354 366 @catch_corrupt_db
355 367 def get_range(self, session, start=1, stop=None, raw=True,output=False):
356 368 """Retrieve input by session.
357 369
358 370 Parameters
359 371 ----------
360 372 session : int
361 373 Session number to retrieve.
362 374 start : int
363 375 First line to retrieve.
364 376 stop : int
365 377 End of line range (excluded from output itself). If None, retrieve
366 378 to the end of the session.
367 379 raw : bool
368 380 If True, return untranslated input
369 381 output : bool
370 382 If True, attempt to include output. This will be 'real' Python
371 383 objects for the current session, or text reprs from previous
372 384 sessions if db_log_output was enabled at the time. Where no output
373 385 is found, None is used.
374 386
375 387 Returns
376 388 -------
377 An iterator over the desired lines. Each line is a 3-tuple, either
378 (session, line, input) if output is False, or
379 (session, line, (input, output)) if output is True.
389 entries
390 An iterator over the desired lines. Each line is a 3-tuple, either
391 (session, line, input) if output is False, or
392 (session, line, (input, output)) if output is True.
380 393 """
381 394 if stop:
382 395 lineclause = "line >= ? AND line < ?"
383 396 params = (session, start, stop)
384 397 else:
385 398 lineclause = "line>=?"
386 399 params = (session, start)
387 400
388 401 return self._run_sql("WHERE session==? AND %s" % lineclause,
389 402 params, raw=raw, output=output)
390 403
391 404 def get_range_by_str(self, rangestr, raw=True, output=False):
392 405 """Get lines of history from a string of ranges, as used by magic
393 406 commands %hist, %save, %macro, etc.
394 407
395 408 Parameters
396 409 ----------
397 410 rangestr : str
398 411 A string specifying ranges, e.g. "5 ~2/1-4". See
399 412 :func:`magic_history` for full details.
400 413 raw, output : bool
401 414 As :meth:`get_range`
402 415
403 416 Returns
404 417 -------
405 418 Tuples as :meth:`get_range`
406 419 """
407 420 for sess, s, e in extract_hist_ranges(rangestr):
408 421 for line in self.get_range(sess, s, e, raw=raw, output=output):
409 422 yield line
410 423
411 424
412 425 class HistoryManager(HistoryAccessor):
413 426 """A class to organize all history-related functionality in one place.
414 427 """
415 428 # Public interface
416 429
417 430 # An instance of the IPython shell we are attached to
418 431 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
419 432 # Lists to hold processed and raw history. These start with a blank entry
420 433 # so that we can index them starting from 1
421 434 input_hist_parsed = List([""])
422 435 input_hist_raw = List([""])
423 436 # A list of directories visited during session
424 437 dir_hist = List()
425 438 def _dir_hist_default(self):
426 439 try:
427 440 return [py3compat.getcwd()]
428 441 except OSError:
429 442 return []
430 443
431 444 # A dict of output history, keyed with ints from the shell's
432 445 # execution count.
433 446 output_hist = Dict()
434 447 # The text/plain repr of outputs.
435 448 output_hist_reprs = Dict()
436 449
437 450 # The number of the current session in the history database
438 451 session_number = Integer()
439 452
440 453 db_log_output = Bool(False, config=True,
441 454 help="Should the history database include output? (default: no)"
442 455 )
443 456 db_cache_size = Integer(0, config=True,
444 457 help="Write to database every x commands (higher values save disk access & power).\n"
445 458 "Values of 1 or less effectively disable caching."
446 459 )
447 460 # The input and output caches
448 461 db_input_cache = List()
449 462 db_output_cache = List()
450 463
451 464 # History saving in separate thread
452 465 save_thread = Instance('IPython.core.history.HistorySavingThread')
453 466 try: # Event is a function returning an instance of _Event...
454 467 save_flag = Instance(threading._Event)
455 468 except AttributeError: # ...until Python 3.3, when it's a class.
456 469 save_flag = Instance(threading.Event)
457 470
458 471 # Private interface
459 472 # Variables used to store the three last inputs from the user. On each new
460 473 # history update, we populate the user's namespace with these, shifted as
461 474 # necessary.
462 475 _i00 = Unicode(u'')
463 476 _i = Unicode(u'')
464 477 _ii = Unicode(u'')
465 478 _iii = Unicode(u'')
466 479
467 480 # A regex matching all forms of the exit command, so that we don't store
468 481 # them in the history (it's annoying to rewind the first entry and land on
469 482 # an exit call).
470 483 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
471 484
472 485 def __init__(self, shell=None, config=None, **traits):
473 486 """Create a new history manager associated with a shell instance.
474 487 """
475 488 # We need a pointer back to the shell for various tasks.
476 489 super(HistoryManager, self).__init__(shell=shell, config=config,
477 490 **traits)
478 491 self.save_flag = threading.Event()
479 492 self.db_input_cache_lock = threading.Lock()
480 493 self.db_output_cache_lock = threading.Lock()
481 494 if self.enabled and self.hist_file != ':memory:':
482 495 self.save_thread = HistorySavingThread(self)
483 496 self.save_thread.start()
484 497
485 498 self.new_session()
486 499
487 500 def _get_hist_file_name(self, profile=None):
488 501 """Get default history file name based on the Shell's profile.
489 502
490 503 The profile parameter is ignored, but must exist for compatibility with
491 504 the parent class."""
492 505 profile_dir = self.shell.profile_dir.location
493 506 return os.path.join(profile_dir, 'history.sqlite')
494 507
495 508 @needs_sqlite
496 509 def new_session(self, conn=None):
497 510 """Get a new session number."""
498 511 if conn is None:
499 512 conn = self.db
500 513
501 514 with conn:
502 515 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
503 516 NULL, "") """, (datetime.datetime.now(),))
504 517 self.session_number = cur.lastrowid
505 518
506 519 def end_session(self):
507 520 """Close the database session, filling in the end time and line count."""
508 521 self.writeout_cache()
509 522 with self.db:
510 523 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
511 524 session==?""", (datetime.datetime.now(),
512 525 len(self.input_hist_parsed)-1, self.session_number))
513 526 self.session_number = 0
514 527
515 528 def name_session(self, name):
516 529 """Give the current session a name in the history database."""
517 530 with self.db:
518 531 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
519 532 (name, self.session_number))
520 533
521 534 def reset(self, new_session=True):
522 535 """Clear the session history, releasing all object references, and
523 536 optionally open a new session."""
524 537 self.output_hist.clear()
525 538 # The directory history can't be completely empty
526 539 self.dir_hist[:] = [py3compat.getcwd()]
527 540
528 541 if new_session:
529 542 if self.session_number:
530 543 self.end_session()
531 544 self.input_hist_parsed[:] = [""]
532 545 self.input_hist_raw[:] = [""]
533 546 self.new_session()
534 547
535 548 # ------------------------------
536 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 580 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
539 581 """Get input and output history from the current session. Called by
540 582 get_range, and takes similar parameters."""
541 583 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
542 584
543 585 n = len(input_hist)
544 586 if start < 0:
545 587 start += n
546 588 if not stop or (stop > n):
547 589 stop = n
548 590 elif stop < 0:
549 591 stop += n
550 592
551 593 for i in range(start, stop):
552 594 if output:
553 595 line = (input_hist[i], self.output_hist_reprs.get(i))
554 596 else:
555 597 line = input_hist[i]
556 598 yield (0, i, line)
557 599
558 600 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
559 601 """Retrieve input by session.
560 602
561 603 Parameters
562 604 ----------
563 605 session : int
564 606 Session number to retrieve. The current session is 0, and negative
565 607 numbers count back from current session, so -1 is previous session.
566 608 start : int
567 609 First line to retrieve.
568 610 stop : int
569 611 End of line range (excluded from output itself). If None, retrieve
570 612 to the end of the session.
571 613 raw : bool
572 614 If True, return untranslated input
573 615 output : bool
574 616 If True, attempt to include output. This will be 'real' Python
575 617 objects for the current session, or text reprs from previous
576 618 sessions if db_log_output was enabled at the time. Where no output
577 619 is found, None is used.
578 620
579 621 Returns
580 622 -------
581 An iterator over the desired lines. Each line is a 3-tuple, either
582 (session, line, input) if output is False, or
583 (session, line, (input, output)) if output is True.
623 entries
624 An iterator over the desired lines. Each line is a 3-tuple, either
625 (session, line, input) if output is False, or
626 (session, line, (input, output)) if output is True.
584 627 """
585 628 if session <= 0:
586 629 session += self.session_number
587 630 if session==self.session_number: # Current session
588 631 return self._get_range_session(start, stop, raw, output)
589 632 return super(HistoryManager, self).get_range(session, start, stop, raw,
590 633 output)
591 634
592 635 ## ----------------------------
593 636 ## Methods for storing history:
594 637 ## ----------------------------
595 638 def store_inputs(self, line_num, source, source_raw=None):
596 639 """Store source and raw input in history and create input cache
597 variables _i*.
640 variables ``_i*``.
598 641
599 642 Parameters
600 643 ----------
601 644 line_num : int
602 645 The prompt number of this input.
603 646
604 647 source : str
605 648 Python input.
606 649
607 650 source_raw : str, optional
608 651 If given, this is the raw input without any IPython transformations
609 652 applied to it. If not given, ``source`` is used.
610 653 """
611 654 if source_raw is None:
612 655 source_raw = source
613 656 source = source.rstrip('\n')
614 657 source_raw = source_raw.rstrip('\n')
615 658
616 659 # do not store exit/quit commands
617 660 if self._exit_re.match(source_raw.strip()):
618 661 return
619 662
620 663 self.input_hist_parsed.append(source)
621 664 self.input_hist_raw.append(source_raw)
622 665
623 666 with self.db_input_cache_lock:
624 667 self.db_input_cache.append((line_num, source, source_raw))
625 668 # Trigger to flush cache and write to DB.
626 669 if len(self.db_input_cache) >= self.db_cache_size:
627 670 self.save_flag.set()
628 671
629 672 # update the auto _i variables
630 673 self._iii = self._ii
631 674 self._ii = self._i
632 675 self._i = self._i00
633 676 self._i00 = source_raw
634 677
635 678 # hackish access to user namespace to create _i1,_i2... dynamically
636 679 new_i = '_i%s' % line_num
637 680 to_main = {'_i': self._i,
638 681 '_ii': self._ii,
639 682 '_iii': self._iii,
640 683 new_i : self._i00 }
641 684
642 685 if self.shell is not None:
643 686 self.shell.push(to_main, interactive=False)
644 687
645 688 def store_output(self, line_num):
646 689 """If database output logging is enabled, this saves all the
647 690 outputs from the indicated prompt number to the database. It's
648 691 called by run_cell after code has been executed.
649 692
650 693 Parameters
651 694 ----------
652 695 line_num : int
653 696 The line number from which to save outputs
654 697 """
655 698 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
656 699 return
657 700 output = self.output_hist_reprs[line_num]
658 701
659 702 with self.db_output_cache_lock:
660 703 self.db_output_cache.append((line_num, output))
661 704 if self.db_cache_size <= 1:
662 705 self.save_flag.set()
663 706
664 707 def _writeout_input_cache(self, conn):
665 708 with conn:
666 709 for line in self.db_input_cache:
667 710 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
668 711 (self.session_number,)+line)
669 712
670 713 def _writeout_output_cache(self, conn):
671 714 with conn:
672 715 for line in self.db_output_cache:
673 716 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
674 717 (self.session_number,)+line)
675 718
676 719 @needs_sqlite
677 720 def writeout_cache(self, conn=None):
678 721 """Write any entries in the cache to the database."""
679 722 if conn is None:
680 723 conn = self.db
681 724
682 725 with self.db_input_cache_lock:
683 726 try:
684 727 self._writeout_input_cache(conn)
685 728 except sqlite3.IntegrityError:
686 729 self.new_session(conn)
687 730 print("ERROR! Session/line number was not unique in",
688 731 "database. History logging moved to new session",
689 732 self.session_number)
690 733 try:
691 734 # Try writing to the new session. If this fails, don't
692 735 # recurse
693 736 self._writeout_input_cache(conn)
694 737 except sqlite3.IntegrityError:
695 738 pass
696 739 finally:
697 740 self.db_input_cache = []
698 741
699 742 with self.db_output_cache_lock:
700 743 try:
701 744 self._writeout_output_cache(conn)
702 745 except sqlite3.IntegrityError:
703 746 print("!! Session/line number for output was not unique",
704 747 "in database. Output will not be stored.")
705 748 finally:
706 749 self.db_output_cache = []
707 750
708 751
709 752 class HistorySavingThread(threading.Thread):
710 753 """This thread takes care of writing history to the database, so that
711 754 the UI isn't held up while that happens.
712 755
713 756 It waits for the HistoryManager's save_flag to be set, then writes out
714 757 the history cache. The main thread is responsible for setting the flag when
715 758 the cache size reaches a defined threshold."""
716 759 daemon = True
717 760 stop_now = False
718 761 enabled = True
719 762 def __init__(self, history_manager):
720 763 super(HistorySavingThread, self).__init__(name="IPythonHistorySavingThread")
721 764 self.history_manager = history_manager
722 765 self.enabled = history_manager.enabled
723 766 atexit.register(self.stop)
724 767
725 768 @needs_sqlite
726 769 def run(self):
727 770 # We need a separate db connection per thread:
728 771 try:
729 772 self.db = sqlite3.connect(self.history_manager.hist_file,
730 773 **self.history_manager.connection_options
731 774 )
732 775 while True:
733 776 self.history_manager.save_flag.wait()
734 777 if self.stop_now:
735 778 return
736 779 self.history_manager.save_flag.clear()
737 780 self.history_manager.writeout_cache(self.db)
738 781 except Exception as e:
739 782 print(("The history saving thread hit an unexpected error (%s)."
740 783 "History will not be written to the database.") % repr(e))
741 784
742 785 def stop(self):
743 786 """This can be called from the main thread to safely stop this thread.
744 787
745 788 Note that it does not attempt to write out remaining history before
746 789 exiting. That should be done by calling the HistoryManager's
747 790 end_session method."""
748 791 self.stop_now = True
749 792 self.history_manager.save_flag.set()
750 793 self.join()
751 794
752 795
753 796 # To match, e.g. ~5/8-~2/3
754 797 range_re = re.compile(r"""
755 798 ((?P<startsess>~?\d+)/)?
756 799 (?P<start>\d+)?
757 800 ((?P<sep>[\-:])
758 801 ((?P<endsess>~?\d+)/)?
759 802 (?P<end>\d+))?
760 803 $""", re.VERBOSE)
761 804
762 805
763 806 def extract_hist_ranges(ranges_str):
764 807 """Turn a string of history ranges into 3-tuples of (session, start, stop).
765 808
766 809 Examples
767 810 --------
768 list(extract_input_ranges("~8/5-~7/4 2"))
769 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
811 >>> list(extract_hist_ranges("~8/5-~7/4 2"))
812 [(-8, 5, None), (-7, 1, 5), (0, 2, 3)]
770 813 """
771 814 for range_str in ranges_str.split():
772 815 rmatch = range_re.match(range_str)
773 816 if not rmatch:
774 817 continue
775 818 start = rmatch.group("start")
776 819 if start:
777 820 start = int(start)
778 821 end = rmatch.group("end")
779 822 # If no end specified, get (a, a + 1)
780 823 end = int(end) if end else start + 1
781 824 else: # start not specified
782 825 if not rmatch.group('startsess'): # no startsess
783 826 continue
784 827 start = 1
785 828 end = None # provide the entire session hist
786 829
787 830 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
788 831 end += 1
789 832 startsess = rmatch.group("startsess") or "0"
790 833 endsess = rmatch.group("endsess") or startsess
791 834 startsess = int(startsess.replace("~","-"))
792 835 endsess = int(endsess.replace("~","-"))
793 836 assert endsess >= startsess, "start session must be earlier than end session"
794 837
795 838 if endsess == startsess:
796 839 yield (startsess, start, end)
797 840 continue
798 841 # Multiple sessions in one range:
799 842 yield (startsess, start, None)
800 843 for sess in range(startsess+1, endsess):
801 844 yield (sess, 1, None)
802 845 yield (endsess, 1, end)
803 846
804 847
805 848 def _format_lineno(session, line):
806 849 """Helper function to format line numbers properly."""
807 850 if session == 0:
808 851 return str(line)
809 852 return "%s#%s" % (session, line)
810 853
811 854
@@ -1,280 +1,281 b''
1 1 """Magic functions for running cells in various scripts."""
2 2 from __future__ import print_function
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012 The IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 # Stdlib
16 16 import errno
17 17 import os
18 18 import sys
19 19 import signal
20 20 import time
21 21 from subprocess import Popen, PIPE
22 22 import atexit
23 23
24 24 # Our own packages
25 25 from IPython.config.configurable import Configurable
26 26 from IPython.core import magic_arguments
27 27 from IPython.core.magic import (
28 28 Magics, magics_class, line_magic, cell_magic
29 29 )
30 30 from IPython.lib.backgroundjobs import BackgroundJobManager
31 31 from IPython.utils import py3compat
32 32 from IPython.utils.process import arg_split
33 33 from IPython.utils.traitlets import List, Dict
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Magic implementation classes
37 37 #-----------------------------------------------------------------------------
38 38
39 39 def script_args(f):
40 40 """single decorator for adding script args"""
41 41 args = [
42 42 magic_arguments.argument(
43 43 '--out', type=str,
44 44 help="""The variable in which to store stdout from the script.
45 45 If the script is backgrounded, this will be the stdout *pipe*,
46 46 instead of the stderr text itself.
47 47 """
48 48 ),
49 49 magic_arguments.argument(
50 50 '--err', type=str,
51 51 help="""The variable in which to store stderr from the script.
52 52 If the script is backgrounded, this will be the stderr *pipe*,
53 53 instead of the stderr text itself.
54 54 """
55 55 ),
56 56 magic_arguments.argument(
57 57 '--bg', action="store_true",
58 58 help="""Whether to run the script in the background.
59 59 If given, the only way to see the output of the command is
60 60 with --out/err.
61 61 """
62 62 ),
63 63 magic_arguments.argument(
64 64 '--proc', type=str,
65 65 help="""The variable in which to store Popen instance.
66 66 This is used only when --bg option is given.
67 67 """
68 68 ),
69 69 ]
70 70 for arg in args:
71 71 f = arg(f)
72 72 return f
73 73
74 74 @magics_class
75 75 class ScriptMagics(Magics):
76 76 """Magics for talking to scripts
77 77
78 78 This defines a base `%%script` cell magic for running a cell
79 79 with a program in a subprocess, and registers a few top-level
80 80 magics that call %%script with common interpreters.
81 81 """
82 82 script_magics = List(config=True,
83 83 help="""Extra script cell magics to define
84 84
85 85 This generates simple wrappers of `%%script foo` as `%%foo`.
86 86
87 87 If you want to add script magics that aren't on your path,
88 88 specify them in script_paths
89 89 """,
90 90 )
91 91 def _script_magics_default(self):
92 92 """default to a common list of programs"""
93 93
94 94 defaults = [
95 95 'sh',
96 96 'bash',
97 97 'perl',
98 98 'ruby',
99 99 'python',
100 'python2',
100 101 'python3',
101 102 'pypy',
102 103 ]
103 104 if os.name == 'nt':
104 105 defaults.extend([
105 106 'cmd',
106 107 'powershell',
107 108 ])
108 109
109 110 return defaults
110 111
111 112 script_paths = Dict(config=True,
112 113 help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby'
113 114
114 115 Only necessary for items in script_magics where the default path will not
115 116 find the right interpreter.
116 117 """
117 118 )
118 119
119 120 def __init__(self, shell=None):
120 121 super(ScriptMagics, self).__init__(shell=shell)
121 122 self._generate_script_magics()
122 123 self.job_manager = BackgroundJobManager()
123 124 self.bg_processes = []
124 125 atexit.register(self.kill_bg_processes)
125 126
126 127 def __del__(self):
127 128 self.kill_bg_processes()
128 129
129 130 def _generate_script_magics(self):
130 131 cell_magics = self.magics['cell']
131 132 for name in self.script_magics:
132 133 cell_magics[name] = self._make_script_magic(name)
133 134
134 135 def _make_script_magic(self, name):
135 136 """make a named magic, that calls %%script with a particular program"""
136 137 # expand to explicit path if necessary:
137 138 script = self.script_paths.get(name, name)
138 139
139 140 @magic_arguments.magic_arguments()
140 141 @script_args
141 142 def named_script_magic(line, cell):
142 143 # if line, add it as cl-flags
143 144 if line:
144 145 line = "%s %s" % (script, line)
145 146 else:
146 147 line = script
147 148 return self.shebang(line, cell)
148 149
149 150 # write a basic docstring:
150 151 named_script_magic.__doc__ = \
151 152 """%%{name} script magic
152 153
153 154 Run cells with {script} in a subprocess.
154 155
155 156 This is a shortcut for `%%script {script}`
156 157 """.format(**locals())
157 158
158 159 return named_script_magic
159 160
160 161 @magic_arguments.magic_arguments()
161 162 @script_args
162 163 @cell_magic("script")
163 164 def shebang(self, line, cell):
164 165 """Run a cell via a shell command
165 166
166 167 The `%%script` line is like the #! line of script,
167 168 specifying a program (bash, perl, ruby, etc.) with which to run.
168 169
169 170 The rest of the cell is run by that program.
170 171
171 172 Examples
172 173 --------
173 174 ::
174 175
175 176 In [1]: %%script bash
176 177 ...: for i in 1 2 3; do
177 178 ...: echo $i
178 179 ...: done
179 180 1
180 181 2
181 182 3
182 183 """
183 184 argv = arg_split(line, posix = not sys.platform.startswith('win'))
184 185 args, cmd = self.shebang.parser.parse_known_args(argv)
185 186
186 187 try:
187 188 p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
188 189 except OSError as e:
189 190 if e.errno == errno.ENOENT:
190 191 print("Couldn't find program: %r" % cmd[0])
191 192 return
192 193 else:
193 194 raise
194 195
195 196 cell = cell.encode('utf8', 'replace')
196 197 if args.bg:
197 198 self.bg_processes.append(p)
198 199 self._gc_bg_processes()
199 200 if args.out:
200 201 self.shell.user_ns[args.out] = p.stdout
201 202 if args.err:
202 203 self.shell.user_ns[args.err] = p.stderr
203 204 self.job_manager.new(self._run_script, p, cell, daemon=True)
204 205 if args.proc:
205 206 self.shell.user_ns[args.proc] = p
206 207 return
207 208
208 209 try:
209 210 out, err = p.communicate(cell)
210 211 except KeyboardInterrupt:
211 212 try:
212 213 p.send_signal(signal.SIGINT)
213 214 time.sleep(0.1)
214 215 if p.poll() is not None:
215 216 print("Process is interrupted.")
216 217 return
217 218 p.terminate()
218 219 time.sleep(0.1)
219 220 if p.poll() is not None:
220 221 print("Process is terminated.")
221 222 return
222 223 p.kill()
223 224 print("Process is killed.")
224 225 except OSError:
225 226 pass
226 227 except Exception as e:
227 228 print("Error while terminating subprocess (pid=%i): %s" \
228 229 % (p.pid, e))
229 230 return
230 231 out = py3compat.bytes_to_str(out)
231 232 err = py3compat.bytes_to_str(err)
232 233 if args.out:
233 234 self.shell.user_ns[args.out] = out
234 235 else:
235 236 sys.stdout.write(out)
236 237 sys.stdout.flush()
237 238 if args.err:
238 239 self.shell.user_ns[args.err] = err
239 240 else:
240 241 sys.stderr.write(err)
241 242 sys.stderr.flush()
242 243
243 244 def _run_script(self, p, cell):
244 245 """callback for running the script in the background"""
245 246 p.stdin.write(cell)
246 247 p.stdin.close()
247 248 p.wait()
248 249
249 250 @line_magic("killbgscripts")
250 251 def killbgscripts(self, _nouse_=''):
251 252 """Kill all BG processes started by %%script and its family."""
252 253 self.kill_bg_processes()
253 254 print("All background processes were killed.")
254 255
255 256 def kill_bg_processes(self):
256 257 """Kill all BG processes which are still running."""
257 258 for p in self.bg_processes:
258 259 if p.poll() is None:
259 260 try:
260 261 p.send_signal(signal.SIGINT)
261 262 except:
262 263 pass
263 264 time.sleep(0.1)
264 265 for p in self.bg_processes:
265 266 if p.poll() is None:
266 267 try:
267 268 p.terminate()
268 269 except:
269 270 pass
270 271 time.sleep(0.1)
271 272 for p in self.bg_processes:
272 273 if p.poll() is None:
273 274 try:
274 275 p.kill()
275 276 except:
276 277 pass
277 278 self._gc_bg_processes()
278 279
279 280 def _gc_bg_processes(self):
280 281 self.bg_processes = [p for p in self.bg_processes if p.poll() is None]
@@ -1,376 +1,382 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Pylab (matplotlib) support utilities.
3 3
4 4 Authors
5 5 -------
6 6
7 7 * Fernando Perez.
8 8 * Brian Granger
9 9 """
10 10 from __future__ import print_function
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2009 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import sys
24 24 from io import BytesIO
25 25
26 26 from IPython.core.display import _pngxy
27 27 from IPython.utils.decorators import flag_calls
28 28 from IPython.utils import py3compat
29 29
30 30 # If user specifies a GUI, that dictates the backend, otherwise we read the
31 31 # user's mpl default from the mpl rc structure
32 32 backends = {'tk': 'TkAgg',
33 33 'gtk': 'GTKAgg',
34 34 'gtk3': 'GTK3Agg',
35 35 'wx': 'WXAgg',
36 36 'qt': 'Qt4Agg', # qt3 not supported
37 37 'qt4': 'Qt4Agg',
38 38 'osx': 'MacOSX',
39 39 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
40 40
41 41 # We also need a reverse backends2guis mapping that will properly choose which
42 42 # GUI support to activate based on the desired matplotlib backend. For the
43 43 # most part it's just a reverse of the above dict, but we also need to add a
44 44 # few others that map to the same GUI manually:
45 45 backend2gui = dict(zip(backends.values(), backends.keys()))
46 46 # Our tests expect backend2gui to just return 'qt'
47 47 backend2gui['Qt4Agg'] = 'qt'
48 48 # In the reverse mapping, there are a few extra valid matplotlib backends that
49 49 # map to the same GUI support
50 50 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
51 51 backend2gui['GTK3Cairo'] = 'gtk3'
52 52 backend2gui['WX'] = 'wx'
53 53 backend2gui['CocoaAgg'] = 'osx'
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Matplotlib utilities
57 57 #-----------------------------------------------------------------------------
58 58
59 59
60 60 def getfigs(*fig_nums):
61 61 """Get a list of matplotlib figures by figure numbers.
62 62
63 63 If no arguments are given, all available figures are returned. If the
64 64 argument list contains references to invalid figures, a warning is printed
65 65 but the function continues pasting further figures.
66 66
67 67 Parameters
68 68 ----------
69 69 figs : tuple
70 70 A tuple of ints giving the figure numbers of the figures to return.
71 71 """
72 72 from matplotlib._pylab_helpers import Gcf
73 73 if not fig_nums:
74 74 fig_managers = Gcf.get_all_fig_managers()
75 75 return [fm.canvas.figure for fm in fig_managers]
76 76 else:
77 77 figs = []
78 78 for num in fig_nums:
79 79 f = Gcf.figs.get(num)
80 80 if f is None:
81 81 print('Warning: figure %s not available.' % num)
82 82 else:
83 83 figs.append(f.canvas.figure)
84 84 return figs
85 85
86 86
87 87 def figsize(sizex, sizey):
88 88 """Set the default figure size to be [sizex, sizey].
89 89
90 90 This is just an easy to remember, convenience wrapper that sets::
91 91
92 92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
93 93 """
94 94 import matplotlib
95 95 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
96 96
97 97
98 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 104 Any keyword args are passed to fig.canvas.print_figure,
102 105 such as ``quality`` or ``bbox_inches``.
103 106 """
104 107 from matplotlib import rcParams
105 108 # When there's an empty figure, we shouldn't return anything, otherwise we
106 109 # get big blank areas in the qt console.
107 110 if not fig.axes and not fig.lines:
108 111 return
109 112
110 113 dpi = rcParams['savefig.dpi']
111 114 if fmt == 'retina':
112 115 dpi = dpi * 2
113 116 fmt = 'png'
114 117
115 118 # build keyword args
116 119 kw = dict(
117 120 format=fmt,
118 121 fc=fig.get_facecolor(),
119 122 ec=fig.get_edgecolor(),
120 123 dpi=dpi,
121 124 bbox_inches=bbox_inches,
122 125 )
123 126 # **kwargs get higher priority
124 127 kw.update(kwargs)
125 128
126 129 bytes_io = BytesIO()
127 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 136 def retina_figure(fig, **kwargs):
131 137 """format a figure as a pixel-doubled (retina) PNG"""
132 138 pngdata = print_figure(fig, fmt='retina', **kwargs)
133 139 w, h = _pngxy(pngdata)
134 140 metadata = dict(width=w//2, height=h//2)
135 141 return pngdata, metadata
136 142
137 143 # We need a little factory function here to create the closure where
138 144 # safe_execfile can live.
139 145 def mpl_runner(safe_execfile):
140 146 """Factory to return a matplotlib-enabled runner for %run.
141 147
142 148 Parameters
143 149 ----------
144 150 safe_execfile : function
145 151 This must be a function with the same interface as the
146 152 :meth:`safe_execfile` method of IPython.
147 153
148 154 Returns
149 155 -------
150 156 A function suitable for use as the ``runner`` argument of the %run magic
151 157 function.
152 158 """
153 159
154 160 def mpl_execfile(fname,*where,**kw):
155 161 """matplotlib-aware wrapper around safe_execfile.
156 162
157 163 Its interface is identical to that of the :func:`execfile` builtin.
158 164
159 165 This is ultimately a call to execfile(), but wrapped in safeties to
160 166 properly handle interactive rendering."""
161 167
162 168 import matplotlib
163 169 import matplotlib.pylab as pylab
164 170
165 171 #print '*** Matplotlib runner ***' # dbg
166 172 # turn off rendering until end of script
167 173 is_interactive = matplotlib.rcParams['interactive']
168 174 matplotlib.interactive(False)
169 175 safe_execfile(fname,*where,**kw)
170 176 matplotlib.interactive(is_interactive)
171 177 # make rendering call now, if the user tried to do it
172 178 if pylab.draw_if_interactive.called:
173 179 pylab.draw()
174 180 pylab.draw_if_interactive.called = False
175 181
176 182 return mpl_execfile
177 183
178 184
179 185 def select_figure_formats(shell, formats, **kwargs):
180 186 """Select figure formats for the inline backend.
181 187
182 188 Parameters
183 189 ==========
184 190 shell : InteractiveShell
185 191 The main IPython instance.
186 192 formats : str or set
187 193 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
188 194 **kwargs : any
189 195 Extra keyword arguments to be passed to fig.canvas.print_figure.
190 196 """
191 197 from matplotlib.figure import Figure
192 198 from IPython.kernel.zmq.pylab import backend_inline
193 199
194 200 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
195 201 png_formatter = shell.display_formatter.formatters['image/png']
196 202 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
197 203 pdf_formatter = shell.display_formatter.formatters['application/pdf']
198 204
199 205 if isinstance(formats, py3compat.string_types):
200 206 formats = {formats}
201 207 # cast in case of list / tuple
202 208 formats = set(formats)
203 209
204 210 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
205 211
206 212 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
207 213 bad = formats.difference(supported)
208 214 if bad:
209 215 bs = "%s" % ','.join([repr(f) for f in bad])
210 216 gs = "%s" % ','.join([repr(f) for f in supported])
211 217 raise ValueError("supported formats are: %s not %s" % (gs, bs))
212 218
213 219 if 'png' in formats:
214 220 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
215 221 if 'retina' in formats or 'png2x' in formats:
216 222 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
217 223 if 'jpg' in formats or 'jpeg' in formats:
218 224 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
219 225 if 'svg' in formats:
220 226 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
221 227 if 'pdf' in formats:
222 228 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
223 229
224 230 #-----------------------------------------------------------------------------
225 231 # Code for initializing matplotlib and importing pylab
226 232 #-----------------------------------------------------------------------------
227 233
228 234
229 235 def find_gui_and_backend(gui=None, gui_select=None):
230 236 """Given a gui string return the gui and mpl backend.
231 237
232 238 Parameters
233 239 ----------
234 240 gui : str
235 241 Can be one of ('tk','gtk','wx','qt','qt4','inline').
236 242 gui_select : str
237 243 Can be one of ('tk','gtk','wx','qt','qt4','inline').
238 244 This is any gui already selected by the shell.
239 245
240 246 Returns
241 247 -------
242 248 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
243 249 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
244 250 """
245 251
246 252 import matplotlib
247 253
248 254 if gui and gui != 'auto':
249 255 # select backend based on requested gui
250 256 backend = backends[gui]
251 257 else:
252 258 # We need to read the backend from the original data structure, *not*
253 259 # from mpl.rcParams, since a prior invocation of %matplotlib may have
254 260 # overwritten that.
255 261 # WARNING: this assumes matplotlib 1.1 or newer!!
256 262 backend = matplotlib.rcParamsOrig['backend']
257 263 # In this case, we need to find what the appropriate gui selection call
258 264 # should be for IPython, so we can activate inputhook accordingly
259 265 gui = backend2gui.get(backend, None)
260 266
261 267 # If we have already had a gui active, we need it and inline are the
262 268 # ones allowed.
263 269 if gui_select and gui != gui_select:
264 270 gui = gui_select
265 271 backend = backends[gui]
266 272
267 273 return gui, backend
268 274
269 275
270 276 def activate_matplotlib(backend):
271 277 """Activate the given backend and set interactive to True."""
272 278
273 279 import matplotlib
274 280 matplotlib.interactive(True)
275 281
276 282 # Matplotlib had a bug where even switch_backend could not force
277 283 # the rcParam to update. This needs to be set *before* the module
278 284 # magic of switch_backend().
279 285 matplotlib.rcParams['backend'] = backend
280 286
281 287 import matplotlib.pyplot
282 288 matplotlib.pyplot.switch_backend(backend)
283 289
284 290 # This must be imported last in the matplotlib series, after
285 291 # backend/interactivity choices have been made
286 292 import matplotlib.pylab as pylab
287 293
288 294 pylab.show._needmain = False
289 295 # We need to detect at runtime whether show() is called by the user.
290 296 # For this, we wrap it into a decorator which adds a 'called' flag.
291 297 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
292 298
293 299
294 300 def import_pylab(user_ns, import_all=True):
295 301 """Populate the namespace with pylab-related values.
296 302
297 303 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
298 304
299 305 Also imports a few names from IPython (figsize, display, getfigs)
300 306
301 307 """
302 308
303 309 # Import numpy as np/pyplot as plt are conventions we're trying to
304 310 # somewhat standardize on. Making them available to users by default
305 311 # will greatly help this.
306 312 s = ("import numpy\n"
307 313 "import matplotlib\n"
308 314 "from matplotlib import pylab, mlab, pyplot\n"
309 315 "np = numpy\n"
310 316 "plt = pyplot\n"
311 317 )
312 318 exec(s, user_ns)
313 319
314 320 if import_all:
315 321 s = ("from matplotlib.pylab import *\n"
316 322 "from numpy import *\n")
317 323 exec(s, user_ns)
318 324
319 325 # IPython symbols to add
320 326 user_ns['figsize'] = figsize
321 327 from IPython.core.display import display
322 328 # Add display and getfigs to the user's namespace
323 329 user_ns['display'] = display
324 330 user_ns['getfigs'] = getfigs
325 331
326 332
327 333 def configure_inline_support(shell, backend):
328 334 """Configure an IPython shell object for matplotlib use.
329 335
330 336 Parameters
331 337 ----------
332 338 shell : InteractiveShell instance
333 339
334 340 backend : matplotlib backend
335 341 """
336 342 # If using our svg payload backend, register the post-execution
337 343 # function that will pick up the results for display. This can only be
338 344 # done with access to the real shell object.
339 345
340 346 # Note: if we can't load the inline backend, then there's no point
341 347 # continuing (such as in terminal-only shells in environments without
342 348 # zeromq available).
343 349 try:
344 350 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
345 351 except ImportError:
346 352 return
347 353 from matplotlib import pyplot
348 354
349 355 cfg = InlineBackend.instance(parent=shell)
350 356 cfg.shell = shell
351 357 if cfg not in shell.configurables:
352 358 shell.configurables.append(cfg)
353 359
354 360 if backend == backends['inline']:
355 361 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
356 362 shell.events.register('post_execute', flush_figures)
357 363
358 364 # Save rcParams that will be overwrittern
359 365 shell._saved_rcParams = dict()
360 366 for k in cfg.rc:
361 367 shell._saved_rcParams[k] = pyplot.rcParams[k]
362 368 # load inline_rc
363 369 pyplot.rcParams.update(cfg.rc)
364 370 else:
365 371 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
366 372 try:
367 373 shell.events.unregister('post_execute', flush_figures)
368 374 except ValueError:
369 375 pass
370 376 if hasattr(shell, '_saved_rcParams'):
371 377 pyplot.rcParams.update(shell._saved_rcParams)
372 378 del shell._saved_rcParams
373 379
374 380 # Setup the default figure format
375 381 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
376 382
@@ -1,148 +1,149 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Release data for the IPython project."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2008, IPython Development Team.
6 6 # Copyright (c) 2001, Fernando Perez <fernando.perez@colorado.edu>
7 7 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
8 8 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 # Name of the package for release purposes. This is the name which labels
16 16 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
17 17 name = 'ipython'
18 18
19 19 # IPython version information. An empty _version_extra corresponds to a full
20 20 # release. 'dev' as a _version_extra string means this is a development
21 21 # version
22 22 _version_major = 2
23 23 _version_minor = 0
24 24 _version_patch = 0
25 25 _version_extra = 'dev'
26 26 # _version_extra = 'rc1'
27 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 32 # Construct full version string from these.
32 33 _ver = [_version_major, _version_minor, _version_patch]
33 34
34 35 __version__ = '.'.join(map(str, _ver))
35 36 if _version_extra:
36 37 __version__ = __version__ + '-' + _version_extra
37 38
38 39 version = __version__ # backwards compatibility name
39 40 version_info = (_version_major, _version_minor, _version_patch, _version_extra)
40 41
41 42 # Change this when incrementing the kernel protocol version
42 43 kernel_protocol_version_info = (4, 1)
43 44
44 45 description = "IPython: Productive Interactive Computing"
45 46
46 47 long_description = \
47 48 """
48 49 IPython provides a rich toolkit to help you make the most out of using Python
49 50 interactively. Its main components are:
50 51
51 52 * Powerful interactive Python shells (terminal- and Qt-based).
52 53 * A web-based interactive notebook environment with all shell features plus
53 54 support for embedded figures, animations and rich media.
54 55 * Support for interactive data visualization and use of GUI toolkits.
55 56 * Flexible, embeddable interpreters to load into your own projects.
56 57 * A high-performance library for high level and interactive parallel computing
57 58 that works in multicore systems, clusters, supercomputing and cloud scenarios.
58 59
59 60 The enhanced interactive Python shells have the following main features:
60 61
61 62 * Comprehensive object introspection.
62 63
63 64 * Input history, persistent across sessions.
64 65
65 66 * Caching of output results during a session with automatically generated
66 67 references.
67 68
68 69 * Extensible tab completion, with support by default for completion of python
69 70 variables and keywords, filenames and function keywords.
70 71
71 72 * Extensible system of 'magic' commands for controlling the environment and
72 73 performing many tasks related either to IPython or the operating system.
73 74
74 75 * A rich configuration system with easy switching between different setups
75 76 (simpler than changing $PYTHONSTARTUP environment variables every time).
76 77
77 78 * Session logging and reloading.
78 79
79 80 * Extensible syntax processing for special purpose situations.
80 81
81 82 * Access to the system shell with user-extensible alias system.
82 83
83 84 * Easily embeddable in other Python programs and GUIs.
84 85
85 86 * Integrated access to the pdb debugger and the Python profiler.
86 87
87 88 The parallel computing architecture has the following main features:
88 89
89 90 * Quickly parallelize Python code from an interactive Python/IPython session.
90 91
91 92 * A flexible and dynamic process model that be deployed on anything from
92 93 multicore workstations to supercomputers.
93 94
94 95 * An architecture that supports many different styles of parallelism, from
95 96 message passing to task farming.
96 97
97 98 * Both blocking and fully asynchronous interfaces.
98 99
99 100 * High level APIs that enable many things to be parallelized in a few lines
100 101 of code.
101 102
102 103 * Share live parallel jobs with other users securely.
103 104
104 105 * Dynamically load balanced task farming system.
105 106
106 107 * Robust error handling in parallel code.
107 108
108 109 The latest development version is always available from IPython's `GitHub
109 110 site <http://github.com/ipython>`_.
110 111 """
111 112
112 113 license = 'BSD'
113 114
114 115 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
115 116 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
116 117 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
117 118 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
118 119 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
119 120 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com'),
120 121 'Thomas' : ('Thomas A. Kluyver', 'takowl@gmail.com'),
121 122 'Jorgen' : ('Jorgen Stenarson', 'jorgen.stenarson@bostream.nu'),
122 123 'Matthias' : ('Matthias Bussonnier', 'bussonniermatthias@gmail.com'),
123 124 }
124 125
125 126 author = 'The IPython Development Team'
126 127
127 128 author_email = 'ipython-dev@scipy.org'
128 129
129 130 url = 'http://ipython.org'
130 131
131 132 download_url = 'https://github.com/ipython/ipython/downloads'
132 133
133 134 platforms = ['Linux','Mac OSX','Windows XP/Vista/7/8']
134 135
135 136 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed',
136 137 'Web-based computing', 'Qt console', 'Embedding']
137 138
138 139 classifiers = [
139 140 'Intended Audience :: Developers',
140 141 'Intended Audience :: Science/Research',
141 142 'License :: OSI Approved :: BSD License',
142 143 'Programming Language :: Python',
143 144 'Programming Language :: Python :: 2',
144 145 'Programming Language :: Python :: 2.7',
145 146 'Programming Language :: Python :: 3',
146 147 'Topic :: System :: Distributed Computing',
147 148 'Topic :: System :: Shells'
148 149 ]
@@ -1,241 +1,241 b''
1 1 """Tests for pylab tools module.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2011, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 from io import UnsupportedOperation, BytesIO
17 17
18 18 import matplotlib
19 19 matplotlib.use('Agg')
20 20 from matplotlib.figure import Figure
21 21
22 22 from nose import SkipTest
23 23 import nose.tools as nt
24 24
25 25 from matplotlib import pyplot as plt
26 26 import numpy as np
27 27
28 28 # Our own imports
29 29 from IPython.core.getipython import get_ipython
30 30 from IPython.core.interactiveshell import InteractiveShell
31 31 from IPython.core.display import _PNG, _JPEG
32 32 from .. import pylabtools as pt
33 33
34 34 from IPython.testing import decorators as dec
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Globals and constants
38 38 #-----------------------------------------------------------------------------
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Local utilities
42 42 #-----------------------------------------------------------------------------
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Classes and functions
46 46 #-----------------------------------------------------------------------------
47 47
48 48 def test_figure_to_svg():
49 49 # simple empty-figure test
50 50 fig = plt.figure()
51 51 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
52 52
53 53 plt.close('all')
54 54
55 55 # simple check for at least svg-looking output
56 56 fig = plt.figure()
57 57 ax = fig.add_subplot(1,1,1)
58 58 ax.plot([1,2,3])
59 59 plt.draw()
60 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 63 def _check_pil_jpeg_bytes():
64 64 """Skip if PIL can't write JPEGs to BytesIO objects"""
65 65 # PIL's JPEG plugin can't write to BytesIO objects
66 66 # Pillow fixes this
67 67 from PIL import Image
68 68 buf = BytesIO()
69 69 img = Image.new("RGB", (4,4))
70 70 try:
71 71 img.save(buf, 'jpeg')
72 72 except Exception as e:
73 73 ename = e.__class__.__name__
74 74 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
75 75
76 76 @dec.skip_without("PIL.Image")
77 77 def test_figure_to_jpeg():
78 78 _check_pil_jpeg_bytes()
79 79 # simple check for at least jpeg-looking output
80 80 fig = plt.figure()
81 81 ax = fig.add_subplot(1,1,1)
82 82 ax.plot([1,2,3])
83 83 plt.draw()
84 84 jpeg = pt.print_figure(fig, 'jpeg', quality=50)[:100].lower()
85 85 assert jpeg.startswith(_JPEG)
86 86
87 87 def test_retina_figure():
88 88 fig = plt.figure()
89 89 ax = fig.add_subplot(1,1,1)
90 90 ax.plot([1,2,3])
91 91 plt.draw()
92 92 png, md = pt.retina_figure(fig)
93 93 assert png.startswith(_PNG)
94 94 nt.assert_in('width', md)
95 95 nt.assert_in('height', md)
96 96
97 97 _fmt_mime_map = {
98 98 'png': 'image/png',
99 99 'jpeg': 'image/jpeg',
100 100 'pdf': 'application/pdf',
101 101 'retina': 'image/png',
102 102 'svg': 'image/svg+xml',
103 103 }
104 104
105 105 def test_select_figure_formats_str():
106 106 ip = get_ipython()
107 107 for fmt, active_mime in _fmt_mime_map.items():
108 108 pt.select_figure_formats(ip, fmt)
109 109 for mime, f in ip.display_formatter.formatters.items():
110 110 if mime == active_mime:
111 111 nt.assert_in(Figure, f)
112 112 else:
113 113 nt.assert_not_in(Figure, f)
114 114
115 115 def test_select_figure_formats_kwargs():
116 116 ip = get_ipython()
117 117 kwargs = dict(quality=10, bbox_inches='tight')
118 118 pt.select_figure_formats(ip, 'png', **kwargs)
119 119 formatter = ip.display_formatter.formatters['image/png']
120 120 f = formatter.lookup_by_type(Figure)
121 121 cell = f.__closure__[0].cell_contents
122 122 nt.assert_equal(cell, kwargs)
123 123
124 124 # check that the formatter doesn't raise
125 125 fig = plt.figure()
126 126 ax = fig.add_subplot(1,1,1)
127 127 ax.plot([1,2,3])
128 128 plt.draw()
129 129 formatter.enabled = True
130 130 png = formatter(fig)
131 131 assert png.startswith(_PNG)
132 132
133 133 def test_select_figure_formats_set():
134 134 ip = get_ipython()
135 135 for fmts in [
136 136 {'png', 'svg'},
137 137 ['png'],
138 138 ('jpeg', 'pdf', 'retina'),
139 139 {'svg'},
140 140 ]:
141 141 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
142 142 pt.select_figure_formats(ip, fmts)
143 143 for mime, f in ip.display_formatter.formatters.items():
144 144 if mime in active_mimes:
145 145 nt.assert_in(Figure, f)
146 146 else:
147 147 nt.assert_not_in(Figure, f)
148 148
149 149 def test_select_figure_formats_bad():
150 150 ip = get_ipython()
151 151 with nt.assert_raises(ValueError):
152 152 pt.select_figure_formats(ip, 'foo')
153 153 with nt.assert_raises(ValueError):
154 154 pt.select_figure_formats(ip, {'png', 'foo'})
155 155 with nt.assert_raises(ValueError):
156 156 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
157 157
158 158 def test_import_pylab():
159 159 ns = {}
160 160 pt.import_pylab(ns, import_all=False)
161 161 nt.assert_true('plt' in ns)
162 162 nt.assert_equal(ns['np'], np)
163 163
164 164 class TestPylabSwitch(object):
165 165 class Shell(InteractiveShell):
166 166 def enable_gui(self, gui):
167 167 pass
168 168
169 169 def setup(self):
170 170 import matplotlib
171 171 def act_mpl(backend):
172 172 matplotlib.rcParams['backend'] = backend
173 173
174 174 # Save rcParams since they get modified
175 175 self._saved_rcParams = matplotlib.rcParams
176 176 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
177 177 matplotlib.rcParams = dict(backend='Qt4Agg')
178 178 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
179 179
180 180 # Mock out functions
181 181 self._save_am = pt.activate_matplotlib
182 182 pt.activate_matplotlib = act_mpl
183 183 self._save_ip = pt.import_pylab
184 184 pt.import_pylab = lambda *a,**kw:None
185 185 self._save_cis = pt.configure_inline_support
186 186 pt.configure_inline_support = lambda *a,**kw:None
187 187
188 188 def teardown(self):
189 189 pt.activate_matplotlib = self._save_am
190 190 pt.import_pylab = self._save_ip
191 191 pt.configure_inline_support = self._save_cis
192 192 import matplotlib
193 193 matplotlib.rcParams = self._saved_rcParams
194 194 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
195 195
196 196 def test_qt(self):
197 197 s = self.Shell()
198 198 gui, backend = s.enable_matplotlib(None)
199 199 nt.assert_equal(gui, 'qt')
200 200 nt.assert_equal(s.pylab_gui_select, 'qt')
201 201
202 202 gui, backend = s.enable_matplotlib('inline')
203 203 nt.assert_equal(gui, 'inline')
204 204 nt.assert_equal(s.pylab_gui_select, 'qt')
205 205
206 206 gui, backend = s.enable_matplotlib('qt')
207 207 nt.assert_equal(gui, 'qt')
208 208 nt.assert_equal(s.pylab_gui_select, 'qt')
209 209
210 210 gui, backend = s.enable_matplotlib('inline')
211 211 nt.assert_equal(gui, 'inline')
212 212 nt.assert_equal(s.pylab_gui_select, 'qt')
213 213
214 214 gui, backend = s.enable_matplotlib()
215 215 nt.assert_equal(gui, 'qt')
216 216 nt.assert_equal(s.pylab_gui_select, 'qt')
217 217
218 218 def test_inline(self):
219 219 s = self.Shell()
220 220 gui, backend = s.enable_matplotlib('inline')
221 221 nt.assert_equal(gui, 'inline')
222 222 nt.assert_equal(s.pylab_gui_select, None)
223 223
224 224 gui, backend = s.enable_matplotlib('inline')
225 225 nt.assert_equal(gui, 'inline')
226 226 nt.assert_equal(s.pylab_gui_select, None)
227 227
228 228 gui, backend = s.enable_matplotlib('qt')
229 229 nt.assert_equal(gui, 'qt')
230 230 nt.assert_equal(s.pylab_gui_select, 'qt')
231 231
232 232 def test_qt_gtk(self):
233 233 s = self.Shell()
234 234 gui, backend = s.enable_matplotlib('qt')
235 235 nt.assert_equal(gui, 'qt')
236 236 nt.assert_equal(s.pylab_gui_select, 'qt')
237 237
238 238 gui, backend = s.enable_matplotlib('gtk')
239 239 nt.assert_equal(gui, 'qt')
240 240 nt.assert_equal(s.pylab_gui_select, 'qt')
241 241
@@ -1,851 +1,854 b''
1 1 # coding: utf-8
2 2 """A tornado based IPython notebook server.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 7 """
8 8 from __future__ import print_function
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2013 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 # stdlib
21 21 import errno
22 22 import io
23 23 import json
24 24 import logging
25 25 import os
26 26 import random
27 27 import select
28 28 import signal
29 29 import socket
30 30 import sys
31 31 import threading
32 32 import time
33 33 import webbrowser
34 34
35 35
36 36 # Third party
37 37 # check for pyzmq 2.1.11
38 38 from IPython.utils.zmqrelated import check_for_zmq
39 39 check_for_zmq('2.1.11', 'IPython.html')
40 40
41 41 from jinja2 import Environment, FileSystemLoader
42 42
43 43 # Install the pyzmq ioloop. This has to be done before anything else from
44 44 # tornado is imported.
45 45 from zmq.eventloop import ioloop
46 46 ioloop.install()
47 47
48 48 # check for tornado 3.1.0
49 49 msg = "The IPython Notebook requires tornado >= 3.1.0"
50 50 try:
51 51 import tornado
52 52 except ImportError:
53 53 raise ImportError(msg)
54 54 try:
55 55 version_info = tornado.version_info
56 56 except AttributeError:
57 57 raise ImportError(msg + ", but you have < 1.1.0")
58 58 if version_info < (3,1,0):
59 59 raise ImportError(msg + ", but you have %s" % tornado.version)
60 60
61 61 from tornado import httpserver
62 62 from tornado import web
63 63
64 64 # Our own libraries
65 65 from IPython.html import DEFAULT_STATIC_FILES_PATH
66 66 from .base.handlers import Template404
67 67 from .log import log_request
68 68 from .services.kernels.kernelmanager import MappingKernelManager
69 69 from .services.notebooks.nbmanager import NotebookManager
70 70 from .services.notebooks.filenbmanager import FileNotebookManager
71 71 from .services.clusters.clustermanager import ClusterManager
72 72 from .services.sessions.sessionmanager import SessionManager
73 73
74 74 from .base.handlers import AuthenticatedFileHandler, FileFindHandler
75 75
76 from IPython.config import Config
76 77 from IPython.config.application import catch_config_error, boolean_flag
77 78 from IPython.core.application import BaseIPythonApplication
78 79 from IPython.core.profiledir import ProfileDir
79 80 from IPython.consoleapp import IPythonConsoleApp
80 81 from IPython.kernel import swallow_argv
81 82 from IPython.kernel.zmq.session import default_secure
82 83 from IPython.kernel.zmq.kernelapp import (
83 84 kernel_flags,
84 85 kernel_aliases,
85 86 )
86 87 from IPython.nbformat.sign import NotebookNotary
87 88 from IPython.utils.importstring import import_item
88 89 from IPython.utils.localinterfaces import localhost
89 90 from IPython.utils import submodule
90 91 from IPython.utils.traitlets import (
91 92 Dict, Unicode, Integer, List, Bool, Bytes,
92 93 DottedObjectName, TraitError,
93 94 )
94 95 from IPython.utils import py3compat
95 96 from IPython.utils.path import filefind, get_ipython_dir
96 97
97 98 from .utils import url_path_join
98 99
99 100 #-----------------------------------------------------------------------------
100 101 # Module globals
101 102 #-----------------------------------------------------------------------------
102 103
103 104 _examples = """
104 105 ipython notebook # start the notebook
105 106 ipython notebook --profile=sympy # use the sympy profile
106 107 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
107 108 """
108 109
109 110 #-----------------------------------------------------------------------------
110 111 # Helper functions
111 112 #-----------------------------------------------------------------------------
112 113
113 114 def random_ports(port, n):
114 115 """Generate a list of n random ports near the given port.
115 116
116 117 The first 5 ports will be sequential, and the remaining n-5 will be
117 118 randomly selected in the range [port-2*n, port+2*n].
118 119 """
119 120 for i in range(min(5, n)):
120 121 yield port + i
121 122 for i in range(n-5):
122 123 yield max(1, port + random.randint(-2*n, 2*n))
123 124
124 125 def load_handlers(name):
125 126 """Load the (URL pattern, handler) tuples for each component."""
126 127 name = 'IPython.html.' + name
127 128 mod = __import__(name, fromlist=['default_handlers'])
128 129 return mod.default_handlers
129 130
130 131 #-----------------------------------------------------------------------------
131 132 # The Tornado web application
132 133 #-----------------------------------------------------------------------------
133 134
134 135 class NotebookWebApplication(web.Application):
135 136
136 137 def __init__(self, ipython_app, kernel_manager, notebook_manager,
137 138 cluster_manager, session_manager, log, base_url,
138 139 settings_overrides, jinja_env_options):
139 140
140 141 settings = self.init_settings(
141 142 ipython_app, kernel_manager, notebook_manager, cluster_manager,
142 143 session_manager, log, base_url, settings_overrides, jinja_env_options)
143 144 handlers = self.init_handlers(settings)
144 145
145 146 super(NotebookWebApplication, self).__init__(handlers, **settings)
146 147
147 148 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
148 149 cluster_manager, session_manager, log, base_url,
149 150 settings_overrides, jinja_env_options=None):
150 151 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
151 152 # base_url will always be unicode, which will in turn
152 153 # make the patterns unicode, and ultimately result in unicode
153 154 # keys in kwargs to handler._execute(**kwargs) in tornado.
154 155 # This enforces that base_url be ascii in that situation.
155 156 #
156 157 # Note that the URLs these patterns check against are escaped,
157 158 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
158 159 base_url = py3compat.unicode_to_str(base_url, 'ascii')
159 160 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
160 161 jenv_opt = jinja_env_options if jinja_env_options else {}
161 162 env = Environment(loader=FileSystemLoader(template_path),**jenv_opt )
162 163 settings = dict(
163 164 # basics
164 165 log_function=log_request,
165 166 base_url=base_url,
166 167 template_path=template_path,
167 168 static_path=ipython_app.static_file_path,
168 169 static_handler_class = FileFindHandler,
169 170 static_url_prefix = url_path_join(base_url,'/static/'),
170 171
171 172 # authentication
172 173 cookie_secret=ipython_app.cookie_secret,
173 174 login_url=url_path_join(base_url,'/login'),
174 175 password=ipython_app.password,
175 176
176 177 # managers
177 178 kernel_manager=kernel_manager,
178 179 notebook_manager=notebook_manager,
179 180 cluster_manager=cluster_manager,
180 181 session_manager=session_manager,
181 182
182 183 # IPython stuff
183 184 nbextensions_path = ipython_app.nbextensions_path,
184 185 mathjax_url=ipython_app.mathjax_url,
185 186 config=ipython_app.config,
186 187 jinja2_env=env,
187 188 )
188 189
189 190 # allow custom overrides for the tornado web app.
190 191 settings.update(settings_overrides)
191 192 return settings
192 193
193 194 def init_handlers(self, settings):
194 195 # Load the (URL pattern, handler) tuples for each component.
195 196 handlers = []
196 197 handlers.extend(load_handlers('base.handlers'))
197 198 handlers.extend(load_handlers('tree.handlers'))
198 199 handlers.extend(load_handlers('auth.login'))
199 200 handlers.extend(load_handlers('auth.logout'))
200 201 handlers.extend(load_handlers('notebook.handlers'))
201 202 handlers.extend(load_handlers('nbconvert.handlers'))
202 203 handlers.extend(load_handlers('services.kernels.handlers'))
203 204 handlers.extend(load_handlers('services.notebooks.handlers'))
204 205 handlers.extend(load_handlers('services.clusters.handlers'))
205 206 handlers.extend(load_handlers('services.sessions.handlers'))
206 207 handlers.extend(load_handlers('services.nbconvert.handlers'))
207 208 # FIXME: /files/ should be handled by the Contents service when it exists
208 209 nbm = settings['notebook_manager']
209 210 if hasattr(nbm, 'notebook_dir'):
210 211 handlers.extend([
211 212 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : nbm.notebook_dir}),
212 213 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
213 214 ])
214 215 # prepend base_url onto the patterns that we match
215 216 new_handlers = []
216 217 for handler in handlers:
217 218 pattern = url_path_join(settings['base_url'], handler[0])
218 219 new_handler = tuple([pattern] + list(handler[1:]))
219 220 new_handlers.append(new_handler)
220 221 # add 404 on the end, which will catch everything that falls through
221 222 new_handlers.append((r'(.*)', Template404))
222 223 return new_handlers
223 224
224 225
225 226 class NbserverListApp(BaseIPythonApplication):
226 227
227 228 description="List currently running notebook servers in this profile."
228 229
229 230 flags = dict(
230 231 json=({'NbserverListApp': {'json': True}},
231 232 "Produce machine-readable JSON output."),
232 233 )
233 234
234 235 json = Bool(False, config=True,
235 236 help="If True, each line of output will be a JSON object with the "
236 237 "details from the server info file.")
237 238
238 239 def start(self):
239 240 if not self.json:
240 241 print("Currently running servers:")
241 242 for serverinfo in list_running_servers(self.profile):
242 243 if self.json:
243 244 print(json.dumps(serverinfo))
244 245 else:
245 246 print(serverinfo['url'], "::", serverinfo['notebook_dir'])
246 247
247 248 #-----------------------------------------------------------------------------
248 249 # Aliases and Flags
249 250 #-----------------------------------------------------------------------------
250 251
251 252 flags = dict(kernel_flags)
252 253 flags['no-browser']=(
253 254 {'NotebookApp' : {'open_browser' : False}},
254 255 "Don't open the notebook in a browser after startup."
255 256 )
256 257 flags['no-mathjax']=(
257 258 {'NotebookApp' : {'enable_mathjax' : False}},
258 259 """Disable MathJax
259 260
260 261 MathJax is the javascript library IPython uses to render math/LaTeX. It is
261 262 very large, so you may want to disable it if you have a slow internet
262 263 connection, or for offline use of the notebook.
263 264
264 265 When disabled, equations etc. will appear as their untransformed TeX source.
265 266 """
266 267 )
267 268
268 269 # Add notebook manager flags
269 270 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
270 271 'Auto-save a .py script everytime the .ipynb notebook is saved',
271 272 'Do not auto-save .py scripts for every notebook'))
272 273
273 274 # the flags that are specific to the frontend
274 275 # these must be scrubbed before being passed to the kernel,
275 276 # or it will raise an error on unrecognized flags
276 277 notebook_flags = ['no-browser', 'no-mathjax', 'script', 'no-script']
277 278
278 279 aliases = dict(kernel_aliases)
279 280
280 281 aliases.update({
281 282 'ip': 'NotebookApp.ip',
282 283 'port': 'NotebookApp.port',
283 284 'port-retries': 'NotebookApp.port_retries',
284 285 'transport': 'KernelManager.transport',
285 286 'keyfile': 'NotebookApp.keyfile',
286 287 'certfile': 'NotebookApp.certfile',
287 288 'notebook-dir': 'NotebookApp.notebook_dir',
288 289 'browser': 'NotebookApp.browser',
289 290 })
290 291
291 292 # remove ipkernel flags that are singletons, and don't make sense in
292 293 # multi-kernel evironment:
293 294 aliases.pop('f', None)
294 295
295 296 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
296 297 u'notebook-dir', u'profile', u'profile-dir']
297 298
298 299 #-----------------------------------------------------------------------------
299 300 # NotebookApp
300 301 #-----------------------------------------------------------------------------
301 302
302 303 class NotebookApp(BaseIPythonApplication):
303 304
304 305 name = 'ipython-notebook'
305 306
306 307 description = """
307 308 The IPython HTML Notebook.
308 309
309 310 This launches a Tornado based HTML Notebook Server that serves up an
310 311 HTML5/Javascript Notebook client.
311 312 """
312 313 examples = _examples
313 314
314 315 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
315 316 FileNotebookManager, NotebookNotary]
316 317 flags = Dict(flags)
317 318 aliases = Dict(aliases)
318 319
319 320 subcommands = dict(
320 321 list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
321 322 )
322 323
323 324 kernel_argv = List(Unicode)
324 325
325 326 def _log_level_default(self):
326 327 return logging.INFO
327 328
328 329 def _log_format_default(self):
329 330 """override default log format to include time"""
330 331 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
331 332
332 333 # create requested profiles by default, if they don't exist:
333 334 auto_create = Bool(True)
334 335
335 336 # file to be opened in the notebook server
336 337 file_to_run = Unicode('', config=True)
337 338 def _file_to_run_changed(self, name, old, new):
338 339 path, base = os.path.split(new)
339 340 if path:
340 341 self.file_to_run = base
341 342 self.notebook_dir = path
342 343
343 344 # Network related information.
344 345
345 346 ip = Unicode(config=True,
346 347 help="The IP address the notebook server will listen on."
347 348 )
348 349 def _ip_default(self):
349 350 return localhost()
350 351
351 352 def _ip_changed(self, name, old, new):
352 353 if new == u'*': self.ip = u''
353 354
354 355 port = Integer(8888, config=True,
355 356 help="The port the notebook server will listen on."
356 357 )
357 358 port_retries = Integer(50, config=True,
358 359 help="The number of additional ports to try if the specified port is not available."
359 360 )
360 361
361 362 certfile = Unicode(u'', config=True,
362 363 help="""The full path to an SSL/TLS certificate file."""
363 364 )
364 365
365 366 keyfile = Unicode(u'', config=True,
366 367 help="""The full path to a private key file for usage with SSL/TLS."""
367 368 )
368 369
369 370 cookie_secret = Bytes(b'', config=True,
370 371 help="""The random bytes used to secure cookies.
371 372 By default this is a new random number every time you start the Notebook.
372 373 Set it to a value in a config file to enable logins to persist across server sessions.
373 374
374 375 Note: Cookie secrets should be kept private, do not share config files with
375 376 cookie_secret stored in plaintext (you can read the value from a file).
376 377 """
377 378 )
378 379 def _cookie_secret_default(self):
379 380 return os.urandom(1024)
380 381
381 382 password = Unicode(u'', config=True,
382 383 help="""Hashed password to use for web authentication.
383 384
384 385 To generate, type in a python/IPython shell:
385 386
386 387 from IPython.lib import passwd; passwd()
387 388
388 389 The string should be of the form type:salt:hashed-password.
389 390 """
390 391 )
391 392
392 393 open_browser = Bool(True, config=True,
393 394 help="""Whether to open in a browser after starting.
394 395 The specific browser used is platform dependent and
395 396 determined by the python standard library `webbrowser`
396 397 module, unless it is overridden using the --browser
397 398 (NotebookApp.browser) configuration option.
398 399 """)
399 400
400 401 browser = Unicode(u'', config=True,
401 402 help="""Specify what command to use to invoke a web
402 403 browser when opening the notebook. If not specified, the
403 404 default browser will be determined by the `webbrowser`
404 405 standard library module, which allows setting of the
405 406 BROWSER environment variable to override it.
406 407 """)
407 408
408 409 webapp_settings = Dict(config=True,
409 410 help="Supply overrides for the tornado.web.Application that the "
410 411 "IPython notebook uses.")
411 412
412 413 jinja_environment_options = Dict(config=True,
413 414 help="Supply extra arguments that will be passed to Jinja environment.")
414 415
415 416
416 417 enable_mathjax = Bool(True, config=True,
417 418 help="""Whether to enable MathJax for typesetting math/TeX
418 419
419 420 MathJax is the javascript library IPython uses to render math/LaTeX. It is
420 421 very large, so you may want to disable it if you have a slow internet
421 422 connection, or for offline use of the notebook.
422 423
423 424 When disabled, equations etc. will appear as their untransformed TeX source.
424 425 """
425 426 )
426 427 def _enable_mathjax_changed(self, name, old, new):
427 428 """set mathjax url to empty if mathjax is disabled"""
428 429 if not new:
429 430 self.mathjax_url = u''
430 431
431 432 base_url = Unicode('/', config=True,
432 433 help='''The base URL for the notebook server.
433 434
434 435 Leading and trailing slashes can be omitted,
435 436 and will automatically be added.
436 437 ''')
437 438 def _base_url_changed(self, name, old, new):
438 439 if not new.startswith('/'):
439 440 self.base_url = '/'+new
440 441 elif not new.endswith('/'):
441 442 self.base_url = new+'/'
442 443
443 444 base_project_url = Unicode('/', config=True, help="""DEPRECATED use base_url""")
444 445 def _base_project_url_changed(self, name, old, new):
445 446 self.log.warn("base_project_url is deprecated, use base_url")
446 447 self.base_url = new
447 448
448 449 extra_static_paths = List(Unicode, config=True,
449 450 help="""Extra paths to search for serving static files.
450 451
451 452 This allows adding javascript/css to be available from the notebook server machine,
452 453 or overriding individual files in the IPython"""
453 454 )
454 455 def _extra_static_paths_default(self):
455 456 return [os.path.join(self.profile_dir.location, 'static')]
456 457
457 458 @property
458 459 def static_file_path(self):
459 460 """return extra paths + the default location"""
460 461 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
461 462
462 463 nbextensions_path = List(Unicode, config=True,
463 464 help="""paths for Javascript extensions. By default, this is just IPYTHONDIR/nbextensions"""
464 465 )
465 466 def _nbextensions_path_default(self):
466 467 return [os.path.join(get_ipython_dir(), 'nbextensions')]
467 468
468 469 mathjax_url = Unicode("", config=True,
469 470 help="""The url for MathJax.js."""
470 471 )
471 472 def _mathjax_url_default(self):
472 473 if not self.enable_mathjax:
473 474 return u''
474 475 static_url_prefix = self.webapp_settings.get("static_url_prefix",
475 476 url_path_join(self.base_url, "static")
476 477 )
477 478
478 479 # try local mathjax, either in nbextensions/mathjax or static/mathjax
479 480 for (url_prefix, search_path) in [
480 481 (url_path_join(self.base_url, "nbextensions"), self.nbextensions_path),
481 482 (static_url_prefix, self.static_file_path),
482 483 ]:
483 484 self.log.debug("searching for local mathjax in %s", search_path)
484 485 try:
485 486 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
486 487 except IOError:
487 488 continue
488 489 else:
489 490 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
490 491 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
491 492 return url
492 493
493 494 # no local mathjax, serve from CDN
494 495 if self.certfile:
495 496 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
496 497 host = u"https://c328740.ssl.cf1.rackcdn.com"
497 498 else:
498 499 host = u"http://cdn.mathjax.org"
499 500
500 501 url = host + u"/mathjax/latest/MathJax.js"
501 502 self.log.info("Using MathJax from CDN: %s", url)
502 503 return url
503 504
504 505 def _mathjax_url_changed(self, name, old, new):
505 506 if new and not self.enable_mathjax:
506 507 # enable_mathjax=False overrides mathjax_url
507 508 self.mathjax_url = u''
508 509 else:
509 510 self.log.info("Using MathJax: %s", new)
510 511
511 512 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
512 513 config=True,
513 514 help='The notebook manager class to use.')
514 515
515 516 trust_xheaders = Bool(False, config=True,
516 517 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
517 518 "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")
518 519 )
519 520
520 521 info_file = Unicode()
521 522
522 523 def _info_file_default(self):
523 524 info_file = "nbserver-%s.json"%os.getpid()
524 525 return os.path.join(self.profile_dir.security_dir, info_file)
525 526
526 527 notebook_dir = Unicode(py3compat.getcwd(), config=True,
527 528 help="The directory to use for notebooks and kernels."
528 529 )
529 530
530 531 def _notebook_dir_changed(self, name, old, new):
531 532 """Do a bit of validation of the notebook dir."""
532 533 if not os.path.isabs(new):
533 534 # If we receive a non-absolute path, make it absolute.
534 535 self.notebook_dir = os.path.abspath(new)
535 536 return
536 537 if not os.path.isdir(new):
537 538 raise TraitError("No such notebook dir: %r" % new)
538 539
539 540 # setting App.notebook_dir implies setting notebook and kernel dirs as well
540 541 self.config.FileNotebookManager.notebook_dir = new
541 542 self.config.MappingKernelManager.root_dir = new
542 543
543 544
544 545 def parse_command_line(self, argv=None):
545 546 super(NotebookApp, self).parse_command_line(argv)
546 547
547 548 if self.extra_args:
548 549 arg0 = self.extra_args[0]
549 550 f = os.path.abspath(arg0)
550 551 self.argv.remove(arg0)
551 552 if not os.path.exists(f):
552 553 self.log.critical("No such file or directory: %s", f)
553 554 self.exit(1)
554 555
555 556 # Use config here, to ensure that it takes higher priority than
556 557 # anything that comes from the profile.
558 c = Config()
557 559 if os.path.isdir(f):
558 self.config.NotebookApp.notebook_dir = f
560 c.NotebookApp.notebook_dir = f
559 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 565 def init_kernel_argv(self):
563 566 """construct the kernel arguments"""
564 567 # Scrub frontend-specific flags
565 568 self.kernel_argv = swallow_argv(self.argv, notebook_aliases, notebook_flags)
566 569 if any(arg.startswith(u'--pylab') for arg in self.kernel_argv):
567 570 self.log.warn('\n '.join([
568 571 "Starting all kernels in pylab mode is not recommended,",
569 572 "and will be disabled in a future release.",
570 573 "Please use the %matplotlib magic to enable matplotlib instead.",
571 574 "pylab implies many imports, which can have confusing side effects",
572 575 "and harm the reproducibility of your notebooks.",
573 576 ]))
574 577 # Kernel should inherit default config file from frontend
575 578 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
576 579 # Kernel should get *absolute* path to profile directory
577 580 self.kernel_argv.extend(["--profile-dir", self.profile_dir.location])
578 581
579 582 def init_configurables(self):
580 583 # force Session default to be secure
581 584 default_secure(self.config)
582 585 self.kernel_manager = MappingKernelManager(
583 586 parent=self, log=self.log, kernel_argv=self.kernel_argv,
584 587 connection_dir = self.profile_dir.security_dir,
585 588 )
586 589 kls = import_item(self.notebook_manager_class)
587 590 self.notebook_manager = kls(parent=self, log=self.log)
588 591 self.session_manager = SessionManager(parent=self, log=self.log)
589 592 self.cluster_manager = ClusterManager(parent=self, log=self.log)
590 593 self.cluster_manager.update_profiles()
591 594
592 595 def init_logging(self):
593 596 # This prevents double log messages because tornado use a root logger that
594 597 # self.log is a child of. The logging module dipatches log messages to a log
595 598 # and all of its ancenstors until propagate is set to False.
596 599 self.log.propagate = False
597 600
598 601 # hook up tornado 3's loggers to our app handlers
599 602 for name in ('access', 'application', 'general'):
600 603 logger = logging.getLogger('tornado.%s' % name)
601 604 logger.parent = self.log
602 605 logger.setLevel(self.log.level)
603 606
604 607 def init_webapp(self):
605 608 """initialize tornado webapp and httpserver"""
606 609 self.web_app = NotebookWebApplication(
607 610 self, self.kernel_manager, self.notebook_manager,
608 611 self.cluster_manager, self.session_manager,
609 612 self.log, self.base_url, self.webapp_settings,
610 613 self.jinja_environment_options
611 614 )
612 615 if self.certfile:
613 616 ssl_options = dict(certfile=self.certfile)
614 617 if self.keyfile:
615 618 ssl_options['keyfile'] = self.keyfile
616 619 else:
617 620 ssl_options = None
618 621 self.web_app.password = self.password
619 622 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
620 623 xheaders=self.trust_xheaders)
621 624 if not self.ip:
622 625 warning = "WARNING: The notebook server is listening on all IP addresses"
623 626 if ssl_options is None:
624 627 self.log.critical(warning + " and not using encryption. This "
625 628 "is not recommended.")
626 629 if not self.password:
627 630 self.log.critical(warning + " and not using authentication. "
628 631 "This is highly insecure and not recommended.")
629 632 success = None
630 633 for port in random_ports(self.port, self.port_retries+1):
631 634 try:
632 635 self.http_server.listen(port, self.ip)
633 636 except socket.error as e:
634 637 if e.errno == errno.EADDRINUSE:
635 638 self.log.info('The port %i is already in use, trying another random port.' % port)
636 639 continue
637 640 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
638 641 self.log.warn("Permission to listen on port %i denied" % port)
639 642 continue
640 643 else:
641 644 raise
642 645 else:
643 646 self.port = port
644 647 success = True
645 648 break
646 649 if not success:
647 650 self.log.critical('ERROR: the notebook server could not be started because '
648 651 'no available port could be found.')
649 652 self.exit(1)
650 653
651 654 @property
652 655 def display_url(self):
653 656 ip = self.ip if self.ip else '[all ip addresses on your system]'
654 657 return self._url(ip)
655 658
656 659 @property
657 660 def connection_url(self):
658 661 ip = self.ip if self.ip else localhost()
659 662 return self._url(ip)
660 663
661 664 def _url(self, ip):
662 665 proto = 'https' if self.certfile else 'http'
663 666 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_url)
664 667
665 668 def init_signal(self):
666 669 if not sys.platform.startswith('win'):
667 670 signal.signal(signal.SIGINT, self._handle_sigint)
668 671 signal.signal(signal.SIGTERM, self._signal_stop)
669 672 if hasattr(signal, 'SIGUSR1'):
670 673 # Windows doesn't support SIGUSR1
671 674 signal.signal(signal.SIGUSR1, self._signal_info)
672 675 if hasattr(signal, 'SIGINFO'):
673 676 # only on BSD-based systems
674 677 signal.signal(signal.SIGINFO, self._signal_info)
675 678
676 679 def _handle_sigint(self, sig, frame):
677 680 """SIGINT handler spawns confirmation dialog"""
678 681 # register more forceful signal handler for ^C^C case
679 682 signal.signal(signal.SIGINT, self._signal_stop)
680 683 # request confirmation dialog in bg thread, to avoid
681 684 # blocking the App
682 685 thread = threading.Thread(target=self._confirm_exit)
683 686 thread.daemon = True
684 687 thread.start()
685 688
686 689 def _restore_sigint_handler(self):
687 690 """callback for restoring original SIGINT handler"""
688 691 signal.signal(signal.SIGINT, self._handle_sigint)
689 692
690 693 def _confirm_exit(self):
691 694 """confirm shutdown on ^C
692 695
693 696 A second ^C, or answering 'y' within 5s will cause shutdown,
694 697 otherwise original SIGINT handler will be restored.
695 698
696 699 This doesn't work on Windows.
697 700 """
698 701 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
699 702 time.sleep(0.1)
700 703 info = self.log.info
701 704 info('interrupted')
702 705 print(self.notebook_info())
703 706 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
704 707 sys.stdout.flush()
705 708 r,w,x = select.select([sys.stdin], [], [], 5)
706 709 if r:
707 710 line = sys.stdin.readline()
708 711 if line.lower().startswith('y'):
709 712 self.log.critical("Shutdown confirmed")
710 713 ioloop.IOLoop.instance().stop()
711 714 return
712 715 else:
713 716 print("No answer for 5s:", end=' ')
714 717 print("resuming operation...")
715 718 # no answer, or answer is no:
716 719 # set it back to original SIGINT handler
717 720 # use IOLoop.add_callback because signal.signal must be called
718 721 # from main thread
719 722 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
720 723
721 724 def _signal_stop(self, sig, frame):
722 725 self.log.critical("received signal %s, stopping", sig)
723 726 ioloop.IOLoop.instance().stop()
724 727
725 728 def _signal_info(self, sig, frame):
726 729 print(self.notebook_info())
727 730
728 731 def init_components(self):
729 732 """Check the components submodule, and warn if it's unclean"""
730 733 status = submodule.check_submodule_status()
731 734 if status == 'missing':
732 735 self.log.warn("components submodule missing, running `git submodule update`")
733 736 submodule.update_submodules(submodule.ipython_parent())
734 737 elif status == 'unclean':
735 738 self.log.warn("components submodule unclean, you may see 404s on static/components")
736 739 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
737 740
738 741 @catch_config_error
739 742 def initialize(self, argv=None):
740 743 super(NotebookApp, self).initialize(argv)
741 744 self.init_logging()
742 745 self.init_kernel_argv()
743 746 self.init_configurables()
744 747 self.init_components()
745 748 self.init_webapp()
746 749 self.init_signal()
747 750
748 751 def cleanup_kernels(self):
749 752 """Shutdown all kernels.
750 753
751 754 The kernels will shutdown themselves when this process no longer exists,
752 755 but explicit shutdown allows the KernelManagers to cleanup the connection files.
753 756 """
754 757 self.log.info('Shutting down kernels')
755 758 self.kernel_manager.shutdown_all()
756 759
757 760 def notebook_info(self):
758 761 "Return the current working directory and the server url information"
759 762 info = self.notebook_manager.info_string() + "\n"
760 763 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
761 764 return info + "The IPython Notebook is running at: %s" % self.display_url
762 765
763 766 def server_info(self):
764 767 """Return a JSONable dict of information about this server."""
765 768 return {'url': self.connection_url,
766 769 'hostname': self.ip if self.ip else 'localhost',
767 770 'port': self.port,
768 771 'secure': bool(self.certfile),
769 772 'base_url': self.base_url,
770 773 'notebook_dir': os.path.abspath(self.notebook_dir),
771 774 }
772 775
773 776 def write_server_info_file(self):
774 777 """Write the result of server_info() to the JSON file info_file."""
775 778 with open(self.info_file, 'w') as f:
776 779 json.dump(self.server_info(), f, indent=2)
777 780
778 781 def remove_server_info_file(self):
779 782 """Remove the nbserver-<pid>.json file created for this server.
780 783
781 784 Ignores the error raised when the file has already been removed.
782 785 """
783 786 try:
784 787 os.unlink(self.info_file)
785 788 except OSError as e:
786 789 if e.errno != errno.ENOENT:
787 790 raise
788 791
789 792 def start(self):
790 793 """ Start the IPython Notebook server app, after initialization
791 794
792 795 This method takes no arguments so all configuration and initialization
793 796 must be done prior to calling this method."""
794 797 if self.subapp is not None:
795 798 return self.subapp.start()
796 799
797 800 info = self.log.info
798 801 for line in self.notebook_info().split("\n"):
799 802 info(line)
800 803 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
801 804
802 805 self.write_server_info_file()
803 806
804 807 if self.open_browser or self.file_to_run:
805 808 try:
806 809 browser = webbrowser.get(self.browser or None)
807 810 except webbrowser.Error as e:
808 811 self.log.warn('No web browser found: %s.' % e)
809 812 browser = None
810 813
811 814 if self.file_to_run:
812 815 fullpath = os.path.join(self.notebook_dir, self.file_to_run)
813 816 if not os.path.exists(fullpath):
814 817 self.log.critical("%s does not exist" % fullpath)
815 818 self.exit(1)
816 819
817 820 uri = url_path_join('notebooks', self.file_to_run)
818 821 else:
819 822 uri = 'tree'
820 823 if browser:
821 824 b = lambda : browser.open(url_path_join(self.connection_url, uri),
822 825 new=2)
823 826 threading.Thread(target=b).start()
824 827 try:
825 828 ioloop.IOLoop.instance().start()
826 829 except KeyboardInterrupt:
827 830 info("Interrupted...")
828 831 finally:
829 832 self.cleanup_kernels()
830 833 self.remove_server_info_file()
831 834
832 835
833 836 def list_running_servers(profile='default'):
834 837 """Iterate over the server info files of running notebook servers.
835 838
836 839 Given a profile name, find nbserver-* files in the security directory of
837 840 that profile, and yield dicts of their information, each one pertaining to
838 841 a currently running notebook server instance.
839 842 """
840 843 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile)
841 844 for file in os.listdir(pd.security_dir):
842 845 if file.startswith('nbserver-'):
843 846 with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f:
844 847 yield json.load(f)
845 848
846 849 #-----------------------------------------------------------------------------
847 850 # Main entry point
848 851 #-----------------------------------------------------------------------------
849 852
850 853 launch_new_instance = NotebookApp.launch_instance
851 854
@@ -1,269 +1,259 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Keyboard management
10 10 //============================================================================
11 11
12 12 IPython.namespace('IPython.keyboard');
13 13
14 14 IPython.keyboard = (function (IPython) {
15 15 "use strict";
16 16
17 17 // Setup global keycodes and inverse keycodes.
18 18
19 19 // See http://unixpapa.com/js/key.html for a complete description. The short of
20 20 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
21 21 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
22 22 // but have minor differences.
23 23
24 24 // These apply to Firefox, (Webkit and IE)
25 25 var _keycodes = {
26 26 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
27 27 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
28 28 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
29 29 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
30 30 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
31 31 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
32 32 '\\ |': 220, '\' "': 222,
33 33 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
34 34 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
35 35 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
36 36 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
37 37 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
38 38 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
39 39 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
40 40 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
41 41 'insert': 45, 'delete': 46, 'numlock': 144,
42 42 };
43 43
44 44 // These apply to Firefox and Opera
45 45 var _mozilla_keycodes = {
46 46 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
47 47 };
48 48
49 49 // This apply to Webkit and IE
50 50 var _ie_keycodes = {
51 51 '; :': 186, '= +': 187, '- _': 189
52 52 };
53 53
54 54 var browser = IPython.utils.browser[0];
55 55 var platform = IPython.utils.platform;
56 56
57 57 if (browser === 'Firefox' || browser === 'Opera' || browser === 'Netscape') {
58 58 $.extend(_keycodes, _mozilla_keycodes);
59 59 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
60 60 $.extend(_keycodes, _ie_keycodes);
61 61 }
62 62
63 63 var keycodes = {};
64 64 var inv_keycodes = {};
65 65 for (var name in _keycodes) {
66 66 var names = name.split(' ');
67 67 if (names.length === 1) {
68 68 var n = names[0];
69 69 keycodes[n] = _keycodes[n];
70 70 inv_keycodes[_keycodes[n]] = n;
71 71 } else {
72 72 var primary = names[0];
73 73 var secondary = names[1];
74 74 keycodes[primary] = _keycodes[name];
75 75 keycodes[secondary] = _keycodes[name];
76 76 inv_keycodes[_keycodes[name]] = primary;
77 77 }
78 78 }
79 79
80 80 var normalize_key = function (key) {
81 81 return inv_keycodes[keycodes[key]];
82 82 };
83 83
84 84 var normalize_shortcut = function (shortcut) {
85 85 // Put a shortcut into normalized form:
86 86 // 1. Make lowercase
87 87 // 2. Replace cmd by meta
88 88 // 3. Sort '-' separated modifiers into the order alt-ctrl-meta-shift
89 89 // 4. Normalize keys
90 90 shortcut = shortcut.toLowerCase().replace('cmd', 'meta');
91 91 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
92 92 var values = shortcut.split("-");
93 93 if (values.length === 1) {
94 94 return normalize_key(values[0]);
95 95 } else {
96 96 var modifiers = values.slice(0,-1);
97 97 var key = normalize_key(values[values.length-1]);
98 98 modifiers.sort();
99 99 return modifiers.join('-') + '-' + key;
100 100 }
101 101 };
102 102
103 103 var shortcut_to_event = function (shortcut, type) {
104 104 // Convert a shortcut (shift-r) to a jQuery Event object
105 105 type = type || 'keydown';
106 106 shortcut = normalize_shortcut(shortcut);
107 107 shortcut = shortcut.replace(/-$/, '_'); // catch shortcuts using '-' key
108 108 var values = shortcut.split("-");
109 109 var modifiers = values.slice(0,-1);
110 110 var key = values[values.length-1];
111 111 var opts = {which: keycodes[key]};
112 112 if (modifiers.indexOf('alt') !== -1) {opts.altKey = true;}
113 113 if (modifiers.indexOf('ctrl') !== -1) {opts.ctrlKey = true;}
114 114 if (modifiers.indexOf('meta') !== -1) {opts.metaKey = true;}
115 115 if (modifiers.indexOf('shift') !== -1) {opts.shiftKey = true;}
116 116 return $.Event(type, opts);
117 117 };
118 118
119 119 var event_to_shortcut = function (event) {
120 120 // Convert a jQuery Event object to a shortcut (shift-r)
121 121 var shortcut = '';
122 122 var key = inv_keycodes[event.which];
123 123 if (event.altKey && key !== 'alt') {shortcut += 'alt-';}
124 124 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl-';}
125 125 if (event.metaKey && key !== 'meta') {shortcut += 'meta-';}
126 126 if (event.shiftKey && key !== 'shift') {shortcut += 'shift-';}
127 127 shortcut += key;
128 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 131 // Shortcut manager class
141 132
142 133 var ShortcutManager = function (delay) {
143 134 this._shortcuts = {};
144 135 this._counts = {};
145 136 this._timers = {};
146 137 this.delay = delay || 800; // delay in milliseconds
147 138 };
148 139
149 140 ShortcutManager.prototype.help = function () {
150 141 var help = [];
151 142 for (var shortcut in this._shortcuts) {
152 143 var help_string = this._shortcuts[shortcut]['help'];
153 144 var help_index = this._shortcuts[shortcut]['help_index'];
154 145 if (help_string) {
155 146 if (platform === 'MacOS') {
156 147 shortcut = shortcut.replace('meta', 'cmd');
157 148 }
158 149 help.push({
159 150 shortcut: shortcut,
160 151 help: help_string,
161 152 help_index: help_index}
162 153 );
163 154 }
164 155 }
165 156 help.sort(function (a, b) {
166 157 if (a.help_index > b.help_index)
167 158 return 1;
168 159 if (a.help_index < b.help_index)
169 160 return -1;
170 161 return 0;
171 162 });
172 163 return help;
173 164 };
174 165
175 166 ShortcutManager.prototype.clear_shortcuts = function () {
176 167 this._shortcuts = {};
177 168 };
178 169
179 170 ShortcutManager.prototype.add_shortcut = function (shortcut, data, suppress_help_update) {
180 171 if (typeof(data) === 'function') {
181 172 data = {help: '', help_index: '', handler: data};
182 173 }
183 174 data.help_index = data.help_index || '';
184 175 data.help = data.help || '';
185 176 data.count = data.count || 1;
186 177 if (data.help_index === '') {
187 178 data.help_index = 'zz';
188 179 }
189 180 shortcut = normalize_shortcut(shortcut);
190 181 this._counts[shortcut] = 0;
191 182 this._shortcuts[shortcut] = data;
192 183 if (!suppress_help_update) {
193 184 // update the keyboard shortcuts notebook help
194 185 $([IPython.events]).trigger('rebuild.QuickHelp');
195 186 }
196 187 };
197 188
198 189 ShortcutManager.prototype.add_shortcuts = function (data) {
199 190 for (var shortcut in data) {
200 191 this.add_shortcut(shortcut, data[shortcut], true);
201 192 }
202 193 // update the keyboard shortcuts notebook help
203 194 $([IPython.events]).trigger('rebuild.QuickHelp');
204 195 };
205 196
206 197 ShortcutManager.prototype.remove_shortcut = function (shortcut, suppress_help_update) {
207 198 shortcut = normalize_shortcut(shortcut);
208 199 delete this._counts[shortcut];
209 200 delete this._shortcuts[shortcut];
210 201 if (!suppress_help_update) {
211 202 // update the keyboard shortcuts notebook help
212 203 $([IPython.events]).trigger('rebuild.QuickHelp');
213 204 }
214 205 };
215 206
216 207 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
217 208 var that = this;
218 209 var c = this._counts;
219 210 var t = this._timers;
220 211 var timer = null;
221 212 if (c[shortcut] === data.count-1) {
222 213 c[shortcut] = 0;
223 214 var timer = t[shortcut];
224 215 if (timer) {clearTimeout(timer); delete t[shortcut];}
225 216 return data.handler(event);
226 217 } else {
227 218 c[shortcut] = c[shortcut] + 1;
228 219 timer = setTimeout(function () {
229 220 c[shortcut] = 0;
230 221 }, that.delay);
231 222 t[shortcut] = timer;
232 223 }
233 224 return false;
234 225 };
235 226
236 227 ShortcutManager.prototype.call_handler = function (event) {
237 228 var shortcut = event_to_shortcut(event);
238 229 var data = this._shortcuts[shortcut];
239 230 if (data) {
240 231 var handler = data['handler'];
241 232 if (handler) {
242 233 if (data.count === 1) {
243 234 return handler(event);
244 235 } else if (data.count > 1) {
245 236 return this.count_handler(shortcut, event, data);
246 237 }
247 238 }
248 239 }
249 240 return true;
250 241 };
251 242
252 243 ShortcutManager.prototype.handles = function (event) {
253 244 var shortcut = event_to_shortcut(event);
254 245 var data = this._shortcuts[shortcut];
255 return !( data === undefined )
246 return !( data === undefined || data.handler === undefined )
256 247 }
257 248
258 249 return {
259 250 keycodes : keycodes,
260 251 inv_keycodes : inv_keycodes,
261 252 ShortcutManager : ShortcutManager,
262 253 normalize_key : normalize_key,
263 254 normalize_shortcut : normalize_shortcut,
264 255 shortcut_to_event : shortcut_to_event,
265 event_to_shortcut : event_to_shortcut,
266 trigger_keydown : trigger_keydown
256 event_to_shortcut : event_to_shortcut
267 257 };
268 258
269 259 }(IPython));
@@ -1,2407 +1,2413 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Notebook
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14
15 15 var utils = IPython.utils;
16 16
17 17 /**
18 18 * A notebook contains and manages cells.
19 19 *
20 20 * @class Notebook
21 21 * @constructor
22 22 * @param {String} selector A jQuery selector for the notebook's DOM element
23 23 * @param {Object} [options] A config object
24 24 */
25 25 var Notebook = function (selector, options) {
26 26 this.options = options = options || {};
27 27 this.base_url = options.base_url;
28 28 this.notebook_path = options.notebook_path;
29 29 this.notebook_name = options.notebook_name;
30 30 this.element = $(selector);
31 31 this.element.scroll();
32 32 this.element.data("notebook", this);
33 33 this.next_prompt_number = 1;
34 34 this.session = null;
35 35 this.kernel = null;
36 36 this.clipboard = null;
37 37 this.undelete_backup = null;
38 38 this.undelete_index = null;
39 39 this.undelete_below = false;
40 40 this.paste_enabled = false;
41 41 // It is important to start out in command mode to match the intial mode
42 42 // of the KeyboardManager.
43 43 this.mode = 'command';
44 44 this.set_dirty(false);
45 45 this.metadata = {};
46 46 this._checkpoint_after_save = false;
47 47 this.last_checkpoint = null;
48 48 this.checkpoints = [];
49 49 this.autosave_interval = 0;
50 50 this.autosave_timer = null;
51 51 // autosave *at most* every two minutes
52 52 this.minimum_autosave_interval = 120000;
53 53 // single worksheet for now
54 54 this.worksheet_metadata = {};
55 55 this.notebook_name_blacklist_re = /[\/\\:]/;
56 56 this.nbformat = 3; // Increment this when changing the nbformat
57 57 this.nbformat_minor = 0; // Increment this when changing the nbformat
58 58 this.style();
59 59 this.create_elements();
60 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 67 * Tweak the notebook's CSS style.
65 68 *
66 69 * @method style
67 70 */
68 71 Notebook.prototype.style = function () {
69 72 $('div#notebook').addClass('border-box-sizing');
70 73 };
71 74
72 75 /**
73 76 * Create an HTML and CSS representation of the notebook.
74 77 *
75 78 * @method create_elements
76 79 */
77 80 Notebook.prototype.create_elements = function () {
78 81 var that = this;
79 82 this.element.attr('tabindex','-1');
80 83 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
81 84 // We add this end_space div to the end of the notebook div to:
82 85 // i) provide a margin between the last cell and the end of the notebook
83 86 // ii) to prevent the div from scrolling up when the last cell is being
84 87 // edited, but is too low on the page, which browsers will do automatically.
85 88 var end_space = $('<div/>').addClass('end_space');
86 89 end_space.dblclick(function (e) {
87 90 var ncells = that.ncells();
88 91 that.insert_cell_below('code',ncells-1);
89 92 });
90 93 this.element.append(this.container);
91 94 this.container.append(end_space);
92 95 };
93 96
94 97 /**
95 98 * Bind JavaScript events: key presses and custom IPython events.
96 99 *
97 100 * @method bind_events
98 101 */
99 102 Notebook.prototype.bind_events = function () {
100 103 var that = this;
101 104
102 105 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
103 106 var index = that.find_cell_index(data.cell);
104 107 var new_cell = that.insert_cell_below('code',index);
105 108 new_cell.set_text(data.text);
106 109 that.dirty = true;
107 110 });
108 111
109 112 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
110 113 that.dirty = data.value;
111 114 });
112 115
113 116 $([IPython.events]).on('trust_changed.Notebook', function (event, data) {
114 117 that.trusted = data.value;
115 118 });
116 119
117 120 $([IPython.events]).on('select.Cell', function (event, data) {
118 121 var index = that.find_cell_index(data.cell);
119 122 that.select(index);
120 123 });
121 124
122 125 $([IPython.events]).on('edit_mode.Cell', function (event, data) {
123 126 that.handle_edit_mode(data.cell);
124 127 });
125 128
126 129 $([IPython.events]).on('command_mode.Cell', function (event, data) {
127 130 that.handle_command_mode(data.cell);
128 131 });
129 132
130 133 $([IPython.events]).on('status_autorestarting.Kernel', function () {
131 134 IPython.dialog.modal({
132 135 title: "Kernel Restarting",
133 136 body: "The kernel appears to have died. It will restart automatically.",
134 137 buttons: {
135 138 OK : {
136 139 class : "btn-primary"
137 140 }
138 141 }
139 142 });
140 143 });
141 144
142 145 var collapse_time = function (time) {
143 146 var app_height = $('#ipython-main-app').height(); // content height
144 147 var splitter_height = $('div#pager_splitter').outerHeight(true);
145 148 var new_height = app_height - splitter_height;
146 149 that.element.animate({height : new_height + 'px'}, time);
147 150 };
148 151
149 152 this.element.bind('collapse_pager', function (event, extrap) {
150 153 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
151 154 collapse_time(time);
152 155 });
153 156
154 157 var expand_time = function (time) {
155 158 var app_height = $('#ipython-main-app').height(); // content height
156 159 var splitter_height = $('div#pager_splitter').outerHeight(true);
157 160 var pager_height = $('div#pager').outerHeight(true);
158 161 var new_height = app_height - pager_height - splitter_height;
159 162 that.element.animate({height : new_height + 'px'}, time);
160 163 };
161 164
162 165 this.element.bind('expand_pager', function (event, extrap) {
163 166 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
164 167 expand_time(time);
165 168 });
166 169
167 170 // Firefox 22 broke $(window).on("beforeunload")
168 171 // I'm not sure why or how.
169 172 window.onbeforeunload = function (e) {
170 173 // TODO: Make killing the kernel configurable.
171 174 var kill_kernel = false;
172 175 if (kill_kernel) {
173 176 that.session.kill_kernel();
174 177 }
175 178 // if we are autosaving, trigger an autosave on nav-away.
176 179 // still warn, because if we don't the autosave may fail.
177 180 if (that.dirty) {
178 181 if ( that.autosave_interval ) {
179 182 // schedule autosave in a timeout
180 183 // this gives you a chance to forcefully discard changes
181 184 // by reloading the page if you *really* want to.
182 185 // the timer doesn't start until you *dismiss* the dialog.
183 186 setTimeout(function () {
184 187 if (that.dirty) {
185 188 that.save_notebook();
186 189 }
187 190 }, 1000);
188 191 return "Autosave in progress, latest changes may be lost.";
189 192 } else {
190 193 return "Unsaved changes will be lost.";
191 194 }
192 195 }
193 196 // Null is the *only* return value that will make the browser not
194 197 // pop up the "don't leave" dialog.
195 198 return null;
196 199 };
197 200 };
198 201
199 202 /**
200 203 * Set the dirty flag, and trigger the set_dirty.Notebook event
201 204 *
202 205 * @method set_dirty
203 206 */
204 207 Notebook.prototype.set_dirty = function (value) {
205 208 if (value === undefined) {
206 209 value = true;
207 210 }
208 211 if (this.dirty == value) {
209 212 return;
210 213 }
211 214 $([IPython.events]).trigger('set_dirty.Notebook', {value: value});
212 215 };
213 216
214 217 /**
215 218 * Scroll the top of the page to a given cell.
216 219 *
217 220 * @method scroll_to_cell
218 221 * @param {Number} cell_number An index of the cell to view
219 222 * @param {Number} time Animation time in milliseconds
220 223 * @return {Number} Pixel offset from the top of the container
221 224 */
222 225 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
223 226 var cells = this.get_cells();
224 227 time = time || 0;
225 228 cell_number = Math.min(cells.length-1,cell_number);
226 229 cell_number = Math.max(0 ,cell_number);
227 230 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
228 231 this.element.animate({scrollTop:scroll_value}, time);
229 232 return scroll_value;
230 233 };
231 234
232 235 /**
233 236 * Scroll to the bottom of the page.
234 237 *
235 238 * @method scroll_to_bottom
236 239 */
237 240 Notebook.prototype.scroll_to_bottom = function () {
238 241 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
239 242 };
240 243
241 244 /**
242 245 * Scroll to the top of the page.
243 246 *
244 247 * @method scroll_to_top
245 248 */
246 249 Notebook.prototype.scroll_to_top = function () {
247 250 this.element.animate({scrollTop:0}, 0);
248 251 };
249 252
250 253 // Edit Notebook metadata
251 254
252 255 Notebook.prototype.edit_metadata = function () {
253 256 var that = this;
254 257 IPython.dialog.edit_metadata(this.metadata, function (md) {
255 258 that.metadata = md;
256 259 }, 'Notebook');
257 260 };
258 261
259 262 // Cell indexing, retrieval, etc.
260 263
261 264 /**
262 265 * Get all cell elements in the notebook.
263 266 *
264 267 * @method get_cell_elements
265 268 * @return {jQuery} A selector of all cell elements
266 269 */
267 270 Notebook.prototype.get_cell_elements = function () {
268 271 return this.container.children("div.cell");
269 272 };
270 273
271 274 /**
272 275 * Get a particular cell element.
273 276 *
274 277 * @method get_cell_element
275 278 * @param {Number} index An index of a cell to select
276 279 * @return {jQuery} A selector of the given cell.
277 280 */
278 281 Notebook.prototype.get_cell_element = function (index) {
279 282 var result = null;
280 283 var e = this.get_cell_elements().eq(index);
281 284 if (e.length !== 0) {
282 285 result = e;
283 286 }
284 287 return result;
285 288 };
286 289
287 290 /**
288 291 * Try to get a particular cell by msg_id.
289 292 *
290 293 * @method get_msg_cell
291 294 * @param {String} msg_id A message UUID
292 295 * @return {Cell} Cell or null if no cell was found.
293 296 */
294 297 Notebook.prototype.get_msg_cell = function (msg_id) {
295 298 return IPython.CodeCell.msg_cells[msg_id] || null;
296 299 };
297 300
298 301 /**
299 302 * Count the cells in this notebook.
300 303 *
301 304 * @method ncells
302 305 * @return {Number} The number of cells in this notebook
303 306 */
304 307 Notebook.prototype.ncells = function () {
305 308 return this.get_cell_elements().length;
306 309 };
307 310
308 311 /**
309 312 * Get all Cell objects in this notebook.
310 313 *
311 314 * @method get_cells
312 315 * @return {Array} This notebook's Cell objects
313 316 */
314 317 // TODO: we are often calling cells as cells()[i], which we should optimize
315 318 // to cells(i) or a new method.
316 319 Notebook.prototype.get_cells = function () {
317 320 return this.get_cell_elements().toArray().map(function (e) {
318 321 return $(e).data("cell");
319 322 });
320 323 };
321 324
322 325 /**
323 326 * Get a Cell object from this notebook.
324 327 *
325 328 * @method get_cell
326 329 * @param {Number} index An index of a cell to retrieve
327 330 * @return {Cell} A particular cell
328 331 */
329 332 Notebook.prototype.get_cell = function (index) {
330 333 var result = null;
331 334 var ce = this.get_cell_element(index);
332 335 if (ce !== null) {
333 336 result = ce.data('cell');
334 337 }
335 338 return result;
336 339 };
337 340
338 341 /**
339 342 * Get the cell below a given cell.
340 343 *
341 344 * @method get_next_cell
342 345 * @param {Cell} cell The provided cell
343 346 * @return {Cell} The next cell
344 347 */
345 348 Notebook.prototype.get_next_cell = function (cell) {
346 349 var result = null;
347 350 var index = this.find_cell_index(cell);
348 351 if (this.is_valid_cell_index(index+1)) {
349 352 result = this.get_cell(index+1);
350 353 }
351 354 return result;
352 355 };
353 356
354 357 /**
355 358 * Get the cell above a given cell.
356 359 *
357 360 * @method get_prev_cell
358 361 * @param {Cell} cell The provided cell
359 362 * @return {Cell} The previous cell
360 363 */
361 364 Notebook.prototype.get_prev_cell = function (cell) {
362 365 // TODO: off-by-one
363 366 // nb.get_prev_cell(nb.get_cell(1)) is null
364 367 var result = null;
365 368 var index = this.find_cell_index(cell);
366 369 if (index !== null && index > 1) {
367 370 result = this.get_cell(index-1);
368 371 }
369 372 return result;
370 373 };
371 374
372 375 /**
373 376 * Get the numeric index of a given cell.
374 377 *
375 378 * @method find_cell_index
376 379 * @param {Cell} cell The provided cell
377 380 * @return {Number} The cell's numeric index
378 381 */
379 382 Notebook.prototype.find_cell_index = function (cell) {
380 383 var result = null;
381 384 this.get_cell_elements().filter(function (index) {
382 385 if ($(this).data("cell") === cell) {
383 386 result = index;
384 387 }
385 388 });
386 389 return result;
387 390 };
388 391
389 392 /**
390 393 * Get a given index , or the selected index if none is provided.
391 394 *
392 395 * @method index_or_selected
393 396 * @param {Number} index A cell's index
394 397 * @return {Number} The given index, or selected index if none is provided.
395 398 */
396 399 Notebook.prototype.index_or_selected = function (index) {
397 400 var i;
398 401 if (index === undefined || index === null) {
399 402 i = this.get_selected_index();
400 403 if (i === null) {
401 404 i = 0;
402 405 }
403 406 } else {
404 407 i = index;
405 408 }
406 409 return i;
407 410 };
408 411
409 412 /**
410 413 * Get the currently selected cell.
411 414 * @method get_selected_cell
412 415 * @return {Cell} The selected cell
413 416 */
414 417 Notebook.prototype.get_selected_cell = function () {
415 418 var index = this.get_selected_index();
416 419 return this.get_cell(index);
417 420 };
418 421
419 422 /**
420 423 * Check whether a cell index is valid.
421 424 *
422 425 * @method is_valid_cell_index
423 426 * @param {Number} index A cell index
424 427 * @return True if the index is valid, false otherwise
425 428 */
426 429 Notebook.prototype.is_valid_cell_index = function (index) {
427 430 if (index !== null && index >= 0 && index < this.ncells()) {
428 431 return true;
429 432 } else {
430 433 return false;
431 434 }
432 435 };
433 436
434 437 /**
435 438 * Get the index of the currently selected cell.
436 439
437 440 * @method get_selected_index
438 441 * @return {Number} The selected cell's numeric index
439 442 */
440 443 Notebook.prototype.get_selected_index = function () {
441 444 var result = null;
442 445 this.get_cell_elements().filter(function (index) {
443 446 if ($(this).data("cell").selected === true) {
444 447 result = index;
445 448 }
446 449 });
447 450 return result;
448 451 };
449 452
450 453
451 454 // Cell selection.
452 455
453 456 /**
454 457 * Programmatically select a cell.
455 458 *
456 459 * @method select
457 460 * @param {Number} index A cell's index
458 461 * @return {Notebook} This notebook
459 462 */
460 463 Notebook.prototype.select = function (index) {
461 464 if (this.is_valid_cell_index(index)) {
462 465 var sindex = this.get_selected_index();
463 466 if (sindex !== null && index !== sindex) {
464 467 // If we are about to select a different cell, make sure we are
465 468 // first in command mode.
466 469 if (this.mode !== 'command') {
467 470 this.command_mode();
468 471 }
469 472 this.get_cell(sindex).unselect();
470 473 }
471 474 var cell = this.get_cell(index);
472 475 cell.select();
473 476 if (cell.cell_type === 'heading') {
474 477 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
475 478 {'cell_type':cell.cell_type,level:cell.level}
476 479 );
477 480 } else {
478 481 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
479 482 {'cell_type':cell.cell_type}
480 483 );
481 484 }
482 485 }
483 486 return this;
484 487 };
485 488
486 489 /**
487 490 * Programmatically select the next cell.
488 491 *
489 492 * @method select_next
490 493 * @return {Notebook} This notebook
491 494 */
492 495 Notebook.prototype.select_next = function () {
493 496 var index = this.get_selected_index();
494 497 this.select(index+1);
495 498 return this;
496 499 };
497 500
498 501 /**
499 502 * Programmatically select the previous cell.
500 503 *
501 504 * @method select_prev
502 505 * @return {Notebook} This notebook
503 506 */
504 507 Notebook.prototype.select_prev = function () {
505 508 var index = this.get_selected_index();
506 509 this.select(index-1);
507 510 return this;
508 511 };
509 512
510 513
511 514 // Edit/Command mode
512 515
513 516 /**
514 517 * Gets the index of the cell that is in edit mode.
515 518 *
516 519 * @method get_edit_index
517 520 *
518 521 * @return index {int}
519 522 **/
520 523 Notebook.prototype.get_edit_index = function () {
521 524 var result = null;
522 525 this.get_cell_elements().filter(function (index) {
523 526 if ($(this).data("cell").mode === 'edit') {
524 527 result = index;
525 528 }
526 529 });
527 530 return result;
528 531 };
529 532
530 533 /**
531 534 * Handle when a a cell blurs and the notebook should enter command mode.
532 535 *
533 536 * @method handle_command_mode
534 537 * @param [cell] {Cell} Cell to enter command mode on.
535 538 **/
536 539 Notebook.prototype.handle_command_mode = function (cell) {
537 540 if (this.mode !== 'command') {
538 541 cell.command_mode();
539 542 this.mode = 'command';
540 543 $([IPython.events]).trigger('command_mode.Notebook');
541 544 IPython.keyboard_manager.command_mode();
542 545 }
543 546 };
544 547
545 548 /**
546 549 * Make the notebook enter command mode.
547 550 *
548 551 * @method command_mode
549 552 **/
550 553 Notebook.prototype.command_mode = function () {
551 554 var cell = this.get_cell(this.get_edit_index());
552 555 if (cell && this.mode !== 'command') {
553 556 // We don't call cell.command_mode, but rather call cell.focus_cell()
554 557 // which will blur and CM editor and trigger the call to
555 558 // handle_command_mode.
556 559 cell.focus_cell();
557 560 }
558 561 };
559 562
560 563 /**
561 564 * Handle when a cell fires it's edit_mode event.
562 565 *
563 566 * @method handle_edit_mode
564 567 * @param [cell] {Cell} Cell to enter edit mode on.
565 568 **/
566 569 Notebook.prototype.handle_edit_mode = function (cell) {
567 570 if (cell && this.mode !== 'edit') {
568 571 cell.edit_mode();
569 572 this.mode = 'edit';
570 573 $([IPython.events]).trigger('edit_mode.Notebook');
571 574 IPython.keyboard_manager.edit_mode();
572 575 }
573 576 };
574 577
575 578 /**
576 579 * Make a cell enter edit mode.
577 580 *
578 581 * @method edit_mode
579 582 **/
580 583 Notebook.prototype.edit_mode = function () {
581 584 var cell = this.get_selected_cell();
582 585 if (cell && this.mode !== 'edit') {
583 586 cell.unrender();
584 587 cell.focus_editor();
585 588 }
586 589 };
587 590
588 591 /**
589 592 * Focus the currently selected cell.
590 593 *
591 594 * @method focus_cell
592 595 **/
593 596 Notebook.prototype.focus_cell = function () {
594 597 var cell = this.get_selected_cell();
595 598 if (cell === null) {return;} // No cell is selected
596 599 cell.focus_cell();
597 600 };
598 601
599 602 // Cell movement
600 603
601 604 /**
602 605 * Move given (or selected) cell up and select it.
603 606 *
604 607 * @method move_cell_up
605 608 * @param [index] {integer} cell index
606 609 * @return {Notebook} This notebook
607 610 **/
608 611 Notebook.prototype.move_cell_up = function (index) {
609 612 var i = this.index_or_selected(index);
610 613 if (this.is_valid_cell_index(i) && i > 0) {
611 614 var pivot = this.get_cell_element(i-1);
612 615 var tomove = this.get_cell_element(i);
613 616 if (pivot !== null && tomove !== null) {
614 617 tomove.detach();
615 618 pivot.before(tomove);
616 619 this.select(i-1);
617 620 var cell = this.get_selected_cell();
618 621 cell.focus_cell();
619 622 }
620 623 this.set_dirty(true);
621 624 }
622 625 return this;
623 626 };
624 627
625 628
626 629 /**
627 630 * Move given (or selected) cell down and select it
628 631 *
629 632 * @method move_cell_down
630 633 * @param [index] {integer} cell index
631 634 * @return {Notebook} This notebook
632 635 **/
633 636 Notebook.prototype.move_cell_down = function (index) {
634 637 var i = this.index_or_selected(index);
635 638 if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) {
636 639 var pivot = this.get_cell_element(i+1);
637 640 var tomove = this.get_cell_element(i);
638 641 if (pivot !== null && tomove !== null) {
639 642 tomove.detach();
640 643 pivot.after(tomove);
641 644 this.select(i+1);
642 645 var cell = this.get_selected_cell();
643 646 cell.focus_cell();
644 647 }
645 648 }
646 649 this.set_dirty();
647 650 return this;
648 651 };
649 652
650 653
651 654 // Insertion, deletion.
652 655
653 656 /**
654 657 * Delete a cell from the notebook.
655 658 *
656 659 * @method delete_cell
657 660 * @param [index] A cell's numeric index
658 661 * @return {Notebook} This notebook
659 662 */
660 663 Notebook.prototype.delete_cell = function (index) {
661 664 var i = this.index_or_selected(index);
662 665 var cell = this.get_selected_cell();
663 666 this.undelete_backup = cell.toJSON();
664 667 $('#undelete_cell').removeClass('disabled');
665 668 if (this.is_valid_cell_index(i)) {
666 669 var old_ncells = this.ncells();
667 670 var ce = this.get_cell_element(i);
668 671 ce.remove();
669 672 if (i === 0) {
670 673 // Always make sure we have at least one cell.
671 674 if (old_ncells === 1) {
672 675 this.insert_cell_below('code');
673 676 }
674 677 this.select(0);
675 678 this.undelete_index = 0;
676 679 this.undelete_below = false;
677 680 } else if (i === old_ncells-1 && i !== 0) {
678 681 this.select(i-1);
679 682 this.undelete_index = i - 1;
680 683 this.undelete_below = true;
681 684 } else {
682 685 this.select(i);
683 686 this.undelete_index = i;
684 687 this.undelete_below = false;
685 688 }
686 689 $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i});
687 690 this.set_dirty(true);
688 691 }
689 692 return this;
690 693 };
691 694
692 695 /**
693 696 * Restore the most recently deleted cell.
694 697 *
695 698 * @method undelete
696 699 */
697 700 Notebook.prototype.undelete_cell = function() {
698 701 if (this.undelete_backup !== null && this.undelete_index !== null) {
699 702 var current_index = this.get_selected_index();
700 703 if (this.undelete_index < current_index) {
701 704 current_index = current_index + 1;
702 705 }
703 706 if (this.undelete_index >= this.ncells()) {
704 707 this.select(this.ncells() - 1);
705 708 }
706 709 else {
707 710 this.select(this.undelete_index);
708 711 }
709 712 var cell_data = this.undelete_backup;
710 713 var new_cell = null;
711 714 if (this.undelete_below) {
712 715 new_cell = this.insert_cell_below(cell_data.cell_type);
713 716 } else {
714 717 new_cell = this.insert_cell_above(cell_data.cell_type);
715 718 }
716 719 new_cell.fromJSON(cell_data);
717 720 if (this.undelete_below) {
718 721 this.select(current_index+1);
719 722 } else {
720 723 this.select(current_index);
721 724 }
722 725 this.undelete_backup = null;
723 726 this.undelete_index = null;
724 727 }
725 728 $('#undelete_cell').addClass('disabled');
726 729 };
727 730
728 731 /**
729 732 * Insert a cell so that after insertion the cell is at given index.
730 733 *
731 734 * Similar to insert_above, but index parameter is mandatory
732 735 *
733 736 * Index will be brought back into the accissible range [0,n]
734 737 *
735 738 * @method insert_cell_at_index
736 739 * @param type {string} in ['code','markdown','heading']
737 740 * @param [index] {int} a valid index where to inser cell
738 741 *
739 742 * @return cell {cell|null} created cell or null
740 743 **/
741 744 Notebook.prototype.insert_cell_at_index = function(type, index){
742 745
743 746 var ncells = this.ncells();
744 747 index = Math.min(index,ncells);
745 748 index = Math.max(index,0);
746 749 var cell = null;
747 750
748 751 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
749 752 if (type === 'code') {
750 753 cell = new IPython.CodeCell(this.kernel);
751 754 cell.set_input_prompt();
752 755 } else if (type === 'markdown') {
753 756 cell = new IPython.MarkdownCell();
754 757 } else if (type === 'raw') {
755 758 cell = new IPython.RawCell();
756 759 } else if (type === 'heading') {
757 760 cell = new IPython.HeadingCell();
758 761 }
759 762
760 763 if(this._insert_element_at_index(cell.element,index)) {
761 764 cell.render();
762 765 $([IPython.events]).trigger('create.Cell', {'cell': cell, 'index': index});
763 766 cell.refresh();
764 767 // We used to select the cell after we refresh it, but there
765 768 // are now cases were this method is called where select is
766 769 // not appropriate. The selection logic should be handled by the
767 770 // caller of the the top level insert_cell methods.
768 771 this.set_dirty(true);
769 772 }
770 773 }
771 774 return cell;
772 775
773 776 };
774 777
775 778 /**
776 779 * Insert an element at given cell index.
777 780 *
778 781 * @method _insert_element_at_index
779 782 * @param element {dom element} a cell element
780 783 * @param [index] {int} a valid index where to inser cell
781 784 * @private
782 785 *
783 786 * return true if everything whent fine.
784 787 **/
785 788 Notebook.prototype._insert_element_at_index = function(element, index){
786 789 if (element === undefined){
787 790 return false;
788 791 }
789 792
790 793 var ncells = this.ncells();
791 794
792 795 if (ncells === 0) {
793 796 // special case append if empty
794 797 this.element.find('div.end_space').before(element);
795 798 } else if ( ncells === index ) {
796 799 // special case append it the end, but not empty
797 800 this.get_cell_element(index-1).after(element);
798 801 } else if (this.is_valid_cell_index(index)) {
799 802 // otherwise always somewhere to append to
800 803 this.get_cell_element(index).before(element);
801 804 } else {
802 805 return false;
803 806 }
804 807
805 808 if (this.undelete_index !== null && index <= this.undelete_index) {
806 809 this.undelete_index = this.undelete_index + 1;
807 810 this.set_dirty(true);
808 811 }
809 812 return true;
810 813 };
811 814
812 815 /**
813 816 * Insert a cell of given type above given index, or at top
814 817 * of notebook if index smaller than 0.
815 818 *
816 819 * default index value is the one of currently selected cell
817 820 *
818 821 * @method insert_cell_above
819 822 * @param type {string} cell type
820 823 * @param [index] {integer}
821 824 *
822 825 * @return handle to created cell or null
823 826 **/
824 827 Notebook.prototype.insert_cell_above = function (type, index) {
825 828 index = this.index_or_selected(index);
826 829 return this.insert_cell_at_index(type, index);
827 830 };
828 831
829 832 /**
830 833 * Insert a cell of given type below given index, or at bottom
831 834 * of notebook if index greater thatn number of cell
832 835 *
833 836 * default index value is the one of currently selected cell
834 837 *
835 838 * @method insert_cell_below
836 839 * @param type {string} cell type
837 840 * @param [index] {integer}
838 841 *
839 842 * @return handle to created cell or null
840 843 *
841 844 **/
842 845 Notebook.prototype.insert_cell_below = function (type, index) {
843 846 index = this.index_or_selected(index);
844 847 return this.insert_cell_at_index(type, index+1);
845 848 };
846 849
847 850
848 851 /**
849 852 * Insert cell at end of notebook
850 853 *
851 854 * @method insert_cell_at_bottom
852 855 * @param {String} type cell type
853 856 *
854 857 * @return the added cell; or null
855 858 **/
856 859 Notebook.prototype.insert_cell_at_bottom = function (type){
857 860 var len = this.ncells();
858 861 return this.insert_cell_below(type,len-1);
859 862 };
860 863
861 864 /**
862 865 * Turn a cell into a code cell.
863 866 *
864 867 * @method to_code
865 868 * @param {Number} [index] A cell's index
866 869 */
867 870 Notebook.prototype.to_code = function (index) {
868 871 var i = this.index_or_selected(index);
869 872 if (this.is_valid_cell_index(i)) {
870 873 var source_element = this.get_cell_element(i);
871 874 var source_cell = source_element.data("cell");
872 875 if (!(source_cell instanceof IPython.CodeCell)) {
873 876 var target_cell = this.insert_cell_below('code',i);
874 877 var text = source_cell.get_text();
875 878 if (text === source_cell.placeholder) {
876 879 text = '';
877 880 }
878 881 target_cell.set_text(text);
879 882 // make this value the starting point, so that we can only undo
880 883 // to this state, instead of a blank cell
881 884 target_cell.code_mirror.clearHistory();
882 885 source_element.remove();
883 886 this.select(i);
884 887 this.set_dirty(true);
885 888 }
886 889 }
887 890 };
888 891
889 892 /**
890 893 * Turn a cell into a Markdown cell.
891 894 *
892 895 * @method to_markdown
893 896 * @param {Number} [index] A cell's index
894 897 */
895 898 Notebook.prototype.to_markdown = function (index) {
896 899 var i = this.index_or_selected(index);
897 900 if (this.is_valid_cell_index(i)) {
898 901 var source_element = this.get_cell_element(i);
899 902 var source_cell = source_element.data("cell");
900 903 if (!(source_cell instanceof IPython.MarkdownCell)) {
901 904 var target_cell = this.insert_cell_below('markdown',i);
902 905 var text = source_cell.get_text();
903 906 if (text === source_cell.placeholder) {
904 907 text = '';
905 908 }
906 909 // We must show the editor before setting its contents
907 910 target_cell.unrender();
908 911 target_cell.set_text(text);
909 912 // make this value the starting point, so that we can only undo
910 913 // to this state, instead of a blank cell
911 914 target_cell.code_mirror.clearHistory();
912 915 source_element.remove();
913 916 this.select(i);
914 917 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
915 918 target_cell.render();
916 919 }
917 920 this.set_dirty(true);
918 921 }
919 922 }
920 923 };
921 924
922 925 /**
923 926 * Turn a cell into a raw text cell.
924 927 *
925 928 * @method to_raw
926 929 * @param {Number} [index] A cell's index
927 930 */
928 931 Notebook.prototype.to_raw = function (index) {
929 932 var i = this.index_or_selected(index);
930 933 if (this.is_valid_cell_index(i)) {
931 934 var source_element = this.get_cell_element(i);
932 935 var source_cell = source_element.data("cell");
933 936 var target_cell = null;
934 937 if (!(source_cell instanceof IPython.RawCell)) {
935 938 target_cell = this.insert_cell_below('raw',i);
936 939 var text = source_cell.get_text();
937 940 if (text === source_cell.placeholder) {
938 941 text = '';
939 942 }
940 943 // We must show the editor before setting its contents
941 944 target_cell.unrender();
942 945 target_cell.set_text(text);
943 946 // make this value the starting point, so that we can only undo
944 947 // to this state, instead of a blank cell
945 948 target_cell.code_mirror.clearHistory();
946 949 source_element.remove();
947 950 this.select(i);
948 951 this.set_dirty(true);
949 952 }
950 953 }
951 954 };
952 955
953 956 /**
954 957 * Turn a cell into a heading cell.
955 958 *
956 959 * @method to_heading
957 960 * @param {Number} [index] A cell's index
958 961 * @param {Number} [level] A heading level (e.g., 1 becomes &lt;h1&gt;)
959 962 */
960 963 Notebook.prototype.to_heading = function (index, level) {
961 964 level = level || 1;
962 965 var i = this.index_or_selected(index);
963 966 if (this.is_valid_cell_index(i)) {
964 967 var source_element = this.get_cell_element(i);
965 968 var source_cell = source_element.data("cell");
966 969 var target_cell = null;
967 970 if (source_cell instanceof IPython.HeadingCell) {
968 971 source_cell.set_level(level);
969 972 } else {
970 973 target_cell = this.insert_cell_below('heading',i);
971 974 var text = source_cell.get_text();
972 975 if (text === source_cell.placeholder) {
973 976 text = '';
974 977 }
975 978 // We must show the editor before setting its contents
976 979 target_cell.set_level(level);
977 980 target_cell.unrender();
978 981 target_cell.set_text(text);
979 982 // make this value the starting point, so that we can only undo
980 983 // to this state, instead of a blank cell
981 984 target_cell.code_mirror.clearHistory();
982 985 source_element.remove();
983 986 this.select(i);
984 987 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
985 988 target_cell.render();
986 989 }
987 990 }
988 991 this.set_dirty(true);
989 992 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
990 993 {'cell_type':'heading',level:level}
991 994 );
992 995 }
993 996 };
994 997
995 998
996 999 // Cut/Copy/Paste
997 1000
998 1001 /**
999 1002 * Enable UI elements for pasting cells.
1000 1003 *
1001 1004 * @method enable_paste
1002 1005 */
1003 1006 Notebook.prototype.enable_paste = function () {
1004 1007 var that = this;
1005 1008 if (!this.paste_enabled) {
1006 1009 $('#paste_cell_replace').removeClass('disabled')
1007 1010 .on('click', function () {that.paste_cell_replace();});
1008 1011 $('#paste_cell_above').removeClass('disabled')
1009 1012 .on('click', function () {that.paste_cell_above();});
1010 1013 $('#paste_cell_below').removeClass('disabled')
1011 1014 .on('click', function () {that.paste_cell_below();});
1012 1015 this.paste_enabled = true;
1013 1016 }
1014 1017 };
1015 1018
1016 1019 /**
1017 1020 * Disable UI elements for pasting cells.
1018 1021 *
1019 1022 * @method disable_paste
1020 1023 */
1021 1024 Notebook.prototype.disable_paste = function () {
1022 1025 if (this.paste_enabled) {
1023 1026 $('#paste_cell_replace').addClass('disabled').off('click');
1024 1027 $('#paste_cell_above').addClass('disabled').off('click');
1025 1028 $('#paste_cell_below').addClass('disabled').off('click');
1026 1029 this.paste_enabled = false;
1027 1030 }
1028 1031 };
1029 1032
1030 1033 /**
1031 1034 * Cut a cell.
1032 1035 *
1033 1036 * @method cut_cell
1034 1037 */
1035 1038 Notebook.prototype.cut_cell = function () {
1036 1039 this.copy_cell();
1037 1040 this.delete_cell();
1038 1041 };
1039 1042
1040 1043 /**
1041 1044 * Copy a cell.
1042 1045 *
1043 1046 * @method copy_cell
1044 1047 */
1045 1048 Notebook.prototype.copy_cell = function () {
1046 1049 var cell = this.get_selected_cell();
1047 1050 this.clipboard = cell.toJSON();
1048 1051 this.enable_paste();
1049 1052 };
1050 1053
1051 1054 /**
1052 1055 * Replace the selected cell with a cell in the clipboard.
1053 1056 *
1054 1057 * @method paste_cell_replace
1055 1058 */
1056 1059 Notebook.prototype.paste_cell_replace = function () {
1057 1060 if (this.clipboard !== null && this.paste_enabled) {
1058 1061 var cell_data = this.clipboard;
1059 1062 var new_cell = this.insert_cell_above(cell_data.cell_type);
1060 1063 new_cell.fromJSON(cell_data);
1061 1064 var old_cell = this.get_next_cell(new_cell);
1062 1065 this.delete_cell(this.find_cell_index(old_cell));
1063 1066 this.select(this.find_cell_index(new_cell));
1064 1067 }
1065 1068 };
1066 1069
1067 1070 /**
1068 1071 * Paste a cell from the clipboard above the selected cell.
1069 1072 *
1070 1073 * @method paste_cell_above
1071 1074 */
1072 1075 Notebook.prototype.paste_cell_above = function () {
1073 1076 if (this.clipboard !== null && this.paste_enabled) {
1074 1077 var cell_data = this.clipboard;
1075 1078 var new_cell = this.insert_cell_above(cell_data.cell_type);
1076 1079 new_cell.fromJSON(cell_data);
1077 1080 new_cell.focus_cell();
1078 1081 }
1079 1082 };
1080 1083
1081 1084 /**
1082 1085 * Paste a cell from the clipboard below the selected cell.
1083 1086 *
1084 1087 * @method paste_cell_below
1085 1088 */
1086 1089 Notebook.prototype.paste_cell_below = function () {
1087 1090 if (this.clipboard !== null && this.paste_enabled) {
1088 1091 var cell_data = this.clipboard;
1089 1092 var new_cell = this.insert_cell_below(cell_data.cell_type);
1090 1093 new_cell.fromJSON(cell_data);
1091 1094 new_cell.focus_cell();
1092 1095 }
1093 1096 };
1094 1097
1095 1098 // Split/merge
1096 1099
1097 1100 /**
1098 1101 * Split the selected cell into two, at the cursor.
1099 1102 *
1100 1103 * @method split_cell
1101 1104 */
1102 1105 Notebook.prototype.split_cell = function () {
1103 1106 var mdc = IPython.MarkdownCell;
1104 1107 var rc = IPython.RawCell;
1105 1108 var cell = this.get_selected_cell();
1106 1109 if (cell.is_splittable()) {
1107 1110 var texta = cell.get_pre_cursor();
1108 1111 var textb = cell.get_post_cursor();
1109 1112 if (cell instanceof IPython.CodeCell) {
1110 1113 // In this case the operations keep the notebook in its existing mode
1111 1114 // so we don't need to do any post-op mode changes.
1112 1115 cell.set_text(textb);
1113 1116 var new_cell = this.insert_cell_above('code');
1114 1117 new_cell.set_text(texta);
1115 1118 } else if ((cell instanceof mdc && !cell.rendered) || (cell instanceof rc)) {
1116 1119 // We know cell is !rendered so we can use set_text.
1117 1120 cell.set_text(textb);
1118 1121 var new_cell = this.insert_cell_above(cell.cell_type);
1119 1122 // Unrender the new cell so we can call set_text.
1120 1123 new_cell.unrender();
1121 1124 new_cell.set_text(texta);
1122 1125 }
1123 1126 }
1124 1127 };
1125 1128
1126 1129 /**
1127 1130 * Combine the selected cell into the cell above it.
1128 1131 *
1129 1132 * @method merge_cell_above
1130 1133 */
1131 1134 Notebook.prototype.merge_cell_above = function () {
1132 1135 var mdc = IPython.MarkdownCell;
1133 1136 var rc = IPython.RawCell;
1134 1137 var index = this.get_selected_index();
1135 1138 var cell = this.get_cell(index);
1136 1139 var render = cell.rendered;
1137 1140 if (!cell.is_mergeable()) {
1138 1141 return;
1139 1142 }
1140 1143 if (index > 0) {
1141 1144 var upper_cell = this.get_cell(index-1);
1142 1145 if (!upper_cell.is_mergeable()) {
1143 1146 return;
1144 1147 }
1145 1148 var upper_text = upper_cell.get_text();
1146 1149 var text = cell.get_text();
1147 1150 if (cell instanceof IPython.CodeCell) {
1148 1151 cell.set_text(upper_text+'\n'+text);
1149 1152 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1150 1153 cell.unrender(); // Must unrender before we set_text.
1151 1154 cell.set_text(upper_text+'\n\n'+text);
1152 1155 if (render) {
1153 1156 // The rendered state of the final cell should match
1154 1157 // that of the original selected cell;
1155 1158 cell.render();
1156 1159 }
1157 1160 }
1158 1161 this.delete_cell(index-1);
1159 1162 this.select(this.find_cell_index(cell));
1160 1163 }
1161 1164 };
1162 1165
1163 1166 /**
1164 1167 * Combine the selected cell into the cell below it.
1165 1168 *
1166 1169 * @method merge_cell_below
1167 1170 */
1168 1171 Notebook.prototype.merge_cell_below = function () {
1169 1172 var mdc = IPython.MarkdownCell;
1170 1173 var rc = IPython.RawCell;
1171 1174 var index = this.get_selected_index();
1172 1175 var cell = this.get_cell(index);
1173 1176 var render = cell.rendered;
1174 1177 if (!cell.is_mergeable()) {
1175 1178 return;
1176 1179 }
1177 1180 if (index < this.ncells()-1) {
1178 1181 var lower_cell = this.get_cell(index+1);
1179 1182 if (!lower_cell.is_mergeable()) {
1180 1183 return;
1181 1184 }
1182 1185 var lower_text = lower_cell.get_text();
1183 1186 var text = cell.get_text();
1184 1187 if (cell instanceof IPython.CodeCell) {
1185 1188 cell.set_text(text+'\n'+lower_text);
1186 1189 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1187 1190 cell.unrender(); // Must unrender before we set_text.
1188 1191 cell.set_text(text+'\n\n'+lower_text);
1189 1192 if (render) {
1190 1193 // The rendered state of the final cell should match
1191 1194 // that of the original selected cell;
1192 1195 cell.render();
1193 1196 }
1194 1197 }
1195 1198 this.delete_cell(index+1);
1196 1199 this.select(this.find_cell_index(cell));
1197 1200 }
1198 1201 };
1199 1202
1200 1203
1201 1204 // Cell collapsing and output clearing
1202 1205
1203 1206 /**
1204 1207 * Hide a cell's output.
1205 1208 *
1206 1209 * @method collapse_output
1207 1210 * @param {Number} index A cell's numeric index
1208 1211 */
1209 1212 Notebook.prototype.collapse_output = function (index) {
1210 1213 var i = this.index_or_selected(index);
1211 1214 var cell = this.get_cell(i);
1212 1215 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1213 1216 cell.collapse_output();
1214 1217 this.set_dirty(true);
1215 1218 }
1216 1219 };
1217 1220
1218 1221 /**
1219 1222 * Hide each code cell's output area.
1220 1223 *
1221 1224 * @method collapse_all_output
1222 1225 */
1223 1226 Notebook.prototype.collapse_all_output = function () {
1224 1227 $.map(this.get_cells(), function (cell, i) {
1225 1228 if (cell instanceof IPython.CodeCell) {
1226 1229 cell.collapse_output();
1227 1230 }
1228 1231 });
1229 1232 // this should not be set if the `collapse` key is removed from nbformat
1230 1233 this.set_dirty(true);
1231 1234 };
1232 1235
1233 1236 /**
1234 1237 * Show a cell's output.
1235 1238 *
1236 1239 * @method expand_output
1237 1240 * @param {Number} index A cell's numeric index
1238 1241 */
1239 1242 Notebook.prototype.expand_output = function (index) {
1240 1243 var i = this.index_or_selected(index);
1241 1244 var cell = this.get_cell(i);
1242 1245 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1243 1246 cell.expand_output();
1244 1247 this.set_dirty(true);
1245 1248 }
1246 1249 };
1247 1250
1248 1251 /**
1249 1252 * Expand each code cell's output area, and remove scrollbars.
1250 1253 *
1251 1254 * @method expand_all_output
1252 1255 */
1253 1256 Notebook.prototype.expand_all_output = function () {
1254 1257 $.map(this.get_cells(), function (cell, i) {
1255 1258 if (cell instanceof IPython.CodeCell) {
1256 1259 cell.expand_output();
1257 1260 }
1258 1261 });
1259 1262 // this should not be set if the `collapse` key is removed from nbformat
1260 1263 this.set_dirty(true);
1261 1264 };
1262 1265
1263 1266 /**
1264 1267 * Clear the selected CodeCell's output area.
1265 1268 *
1266 1269 * @method clear_output
1267 1270 * @param {Number} index A cell's numeric index
1268 1271 */
1269 1272 Notebook.prototype.clear_output = function (index) {
1270 1273 var i = this.index_or_selected(index);
1271 1274 var cell = this.get_cell(i);
1272 1275 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1273 1276 cell.clear_output();
1274 1277 this.set_dirty(true);
1275 1278 }
1276 1279 };
1277 1280
1278 1281 /**
1279 1282 * Clear each code cell's output area.
1280 1283 *
1281 1284 * @method clear_all_output
1282 1285 */
1283 1286 Notebook.prototype.clear_all_output = function () {
1284 1287 $.map(this.get_cells(), function (cell, i) {
1285 1288 if (cell instanceof IPython.CodeCell) {
1286 1289 cell.clear_output();
1287 1290 }
1288 1291 });
1289 1292 this.set_dirty(true);
1290 1293 };
1291 1294
1292 1295 /**
1293 1296 * Scroll the selected CodeCell's output area.
1294 1297 *
1295 1298 * @method scroll_output
1296 1299 * @param {Number} index A cell's numeric index
1297 1300 */
1298 1301 Notebook.prototype.scroll_output = function (index) {
1299 1302 var i = this.index_or_selected(index);
1300 1303 var cell = this.get_cell(i);
1301 1304 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1302 1305 cell.scroll_output();
1303 1306 this.set_dirty(true);
1304 1307 }
1305 1308 };
1306 1309
1307 1310 /**
1308 1311 * Expand each code cell's output area, and add a scrollbar for long output.
1309 1312 *
1310 1313 * @method scroll_all_output
1311 1314 */
1312 1315 Notebook.prototype.scroll_all_output = function () {
1313 1316 $.map(this.get_cells(), function (cell, i) {
1314 1317 if (cell instanceof IPython.CodeCell) {
1315 1318 cell.scroll_output();
1316 1319 }
1317 1320 });
1318 1321 // this should not be set if the `collapse` key is removed from nbformat
1319 1322 this.set_dirty(true);
1320 1323 };
1321 1324
1322 1325 /** Toggle whether a cell's output is collapsed or expanded.
1323 1326 *
1324 1327 * @method toggle_output
1325 1328 * @param {Number} index A cell's numeric index
1326 1329 */
1327 1330 Notebook.prototype.toggle_output = function (index) {
1328 1331 var i = this.index_or_selected(index);
1329 1332 var cell = this.get_cell(i);
1330 1333 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1331 1334 cell.toggle_output();
1332 1335 this.set_dirty(true);
1333 1336 }
1334 1337 };
1335 1338
1336 1339 /**
1337 1340 * Hide/show the output of all cells.
1338 1341 *
1339 1342 * @method toggle_all_output
1340 1343 */
1341 1344 Notebook.prototype.toggle_all_output = function () {
1342 1345 $.map(this.get_cells(), function (cell, i) {
1343 1346 if (cell instanceof IPython.CodeCell) {
1344 1347 cell.toggle_output();
1345 1348 }
1346 1349 });
1347 1350 // this should not be set if the `collapse` key is removed from nbformat
1348 1351 this.set_dirty(true);
1349 1352 };
1350 1353
1351 1354 /**
1352 1355 * Toggle a scrollbar for long cell outputs.
1353 1356 *
1354 1357 * @method toggle_output_scroll
1355 1358 * @param {Number} index A cell's numeric index
1356 1359 */
1357 1360 Notebook.prototype.toggle_output_scroll = function (index) {
1358 1361 var i = this.index_or_selected(index);
1359 1362 var cell = this.get_cell(i);
1360 1363 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1361 1364 cell.toggle_output_scroll();
1362 1365 this.set_dirty(true);
1363 1366 }
1364 1367 };
1365 1368
1366 1369 /**
1367 1370 * Toggle the scrolling of long output on all cells.
1368 1371 *
1369 1372 * @method toggle_all_output_scrolling
1370 1373 */
1371 1374 Notebook.prototype.toggle_all_output_scroll = function () {
1372 1375 $.map(this.get_cells(), function (cell, i) {
1373 1376 if (cell instanceof IPython.CodeCell) {
1374 1377 cell.toggle_output_scroll();
1375 1378 }
1376 1379 });
1377 1380 // this should not be set if the `collapse` key is removed from nbformat
1378 1381 this.set_dirty(true);
1379 1382 };
1380 1383
1381 1384 // Other cell functions: line numbers, ...
1382 1385
1383 1386 /**
1384 1387 * Toggle line numbers in the selected cell's input area.
1385 1388 *
1386 1389 * @method cell_toggle_line_numbers
1387 1390 */
1388 1391 Notebook.prototype.cell_toggle_line_numbers = function() {
1389 1392 this.get_selected_cell().toggle_line_numbers();
1390 1393 };
1391 1394
1392 1395 // Session related things
1393 1396
1394 1397 /**
1395 1398 * Start a new session and set it on each code cell.
1396 1399 *
1397 1400 * @method start_session
1398 1401 */
1399 1402 Notebook.prototype.start_session = function () {
1400 1403 this.session = new IPython.Session(this, this.options);
1401 1404 this.session.start($.proxy(this._session_started, this));
1402 1405 };
1403 1406
1404 1407
1405 1408 /**
1406 1409 * Once a session is started, link the code cells to the kernel and pass the
1407 1410 * comm manager to the widget manager
1408 1411 *
1409 1412 */
1410 1413 Notebook.prototype._session_started = function(){
1411 1414 this.kernel = this.session.kernel;
1412 1415 var ncells = this.ncells();
1413 1416 for (var i=0; i<ncells; i++) {
1414 1417 var cell = this.get_cell(i);
1415 1418 if (cell instanceof IPython.CodeCell) {
1416 1419 cell.set_kernel(this.session.kernel);
1417 1420 }
1418 1421 }
1419 1422 };
1420 1423
1421 1424 /**
1422 1425 * Prompt the user to restart the IPython kernel.
1423 1426 *
1424 1427 * @method restart_kernel
1425 1428 */
1426 1429 Notebook.prototype.restart_kernel = function () {
1427 1430 var that = this;
1428 1431 IPython.dialog.modal({
1429 1432 title : "Restart kernel or continue running?",
1430 1433 body : $("<p/>").text(
1431 1434 'Do you want to restart the current kernel? You will lose all variables defined in it.'
1432 1435 ),
1433 1436 buttons : {
1434 1437 "Continue running" : {},
1435 1438 "Restart" : {
1436 1439 "class" : "btn-danger",
1437 1440 "click" : function() {
1438 1441 that.session.restart_kernel();
1439 1442 }
1440 1443 }
1441 1444 }
1442 1445 });
1443 1446 };
1444 1447
1445 1448 /**
1446 1449 * Execute or render cell outputs and go into command mode.
1447 1450 *
1448 1451 * @method execute_cell
1449 1452 */
1450 1453 Notebook.prototype.execute_cell = function () {
1451 1454 // mode = shift, ctrl, alt
1452 1455 var cell = this.get_selected_cell();
1453 1456 var cell_index = this.find_cell_index(cell);
1454 1457
1455 1458 cell.execute();
1456 1459 this.command_mode();
1457 1460 this.set_dirty(true);
1458 1461 };
1459 1462
1460 1463 /**
1461 1464 * Execute or render cell outputs and insert a new cell below.
1462 1465 *
1463 1466 * @method execute_cell_and_insert_below
1464 1467 */
1465 1468 Notebook.prototype.execute_cell_and_insert_below = function () {
1466 1469 var cell = this.get_selected_cell();
1467 1470 var cell_index = this.find_cell_index(cell);
1468 1471
1469 1472 cell.execute();
1470 1473
1471 1474 // If we are at the end always insert a new cell and return
1472 1475 if (cell_index === (this.ncells()-1)) {
1473 1476 this.command_mode();
1474 1477 this.insert_cell_below('code');
1475 1478 this.select(cell_index+1);
1476 1479 this.edit_mode();
1477 1480 this.scroll_to_bottom();
1478 1481 this.set_dirty(true);
1479 1482 return;
1480 1483 }
1481 1484
1482 1485 this.command_mode();
1483 1486 this.insert_cell_below('code');
1484 1487 this.select(cell_index+1);
1485 1488 this.edit_mode();
1486 1489 this.set_dirty(true);
1487 1490 };
1488 1491
1489 1492 /**
1490 1493 * Execute or render cell outputs and select the next cell.
1491 1494 *
1492 1495 * @method execute_cell_and_select_below
1493 1496 */
1494 1497 Notebook.prototype.execute_cell_and_select_below = function () {
1495 1498
1496 1499 var cell = this.get_selected_cell();
1497 1500 var cell_index = this.find_cell_index(cell);
1498 1501
1499 1502 cell.execute();
1500 1503
1501 1504 // If we are at the end always insert a new cell and return
1502 1505 if (cell_index === (this.ncells()-1)) {
1503 1506 this.command_mode();
1504 1507 this.insert_cell_below('code');
1505 1508 this.select(cell_index+1);
1506 1509 this.edit_mode();
1507 1510 this.scroll_to_bottom();
1508 1511 this.set_dirty(true);
1509 1512 return;
1510 1513 }
1511 1514
1512 1515 this.command_mode();
1513 1516 this.select(cell_index+1);
1514 1517 this.focus_cell();
1515 1518 this.set_dirty(true);
1516 1519 };
1517 1520
1518 1521 /**
1519 1522 * Execute all cells below the selected cell.
1520 1523 *
1521 1524 * @method execute_cells_below
1522 1525 */
1523 1526 Notebook.prototype.execute_cells_below = function () {
1524 1527 this.execute_cell_range(this.get_selected_index(), this.ncells());
1525 1528 this.scroll_to_bottom();
1526 1529 };
1527 1530
1528 1531 /**
1529 1532 * Execute all cells above the selected cell.
1530 1533 *
1531 1534 * @method execute_cells_above
1532 1535 */
1533 1536 Notebook.prototype.execute_cells_above = function () {
1534 1537 this.execute_cell_range(0, this.get_selected_index());
1535 1538 };
1536 1539
1537 1540 /**
1538 1541 * Execute all cells.
1539 1542 *
1540 1543 * @method execute_all_cells
1541 1544 */
1542 1545 Notebook.prototype.execute_all_cells = function () {
1543 1546 this.execute_cell_range(0, this.ncells());
1544 1547 this.scroll_to_bottom();
1545 1548 };
1546 1549
1547 1550 /**
1548 1551 * Execute a contiguous range of cells.
1549 1552 *
1550 1553 * @method execute_cell_range
1551 1554 * @param {Number} start Index of the first cell to execute (inclusive)
1552 1555 * @param {Number} end Index of the last cell to execute (exclusive)
1553 1556 */
1554 1557 Notebook.prototype.execute_cell_range = function (start, end) {
1555 1558 this.command_mode();
1556 1559 for (var i=start; i<end; i++) {
1557 1560 this.select(i);
1558 1561 this.execute_cell();
1559 1562 }
1560 1563 };
1561 1564
1562 1565 // Persistance and loading
1563 1566
1564 1567 /**
1565 1568 * Getter method for this notebook's name.
1566 1569 *
1567 1570 * @method get_notebook_name
1568 1571 * @return {String} This notebook's name (excluding file extension)
1569 1572 */
1570 1573 Notebook.prototype.get_notebook_name = function () {
1571 1574 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
1572 1575 return nbname;
1573 1576 };
1574 1577
1575 1578 /**
1576 1579 * Setter method for this notebook's name.
1577 1580 *
1578 1581 * @method set_notebook_name
1579 1582 * @param {String} name A new name for this notebook
1580 1583 */
1581 1584 Notebook.prototype.set_notebook_name = function (name) {
1582 1585 this.notebook_name = name;
1583 1586 };
1584 1587
1585 1588 /**
1586 1589 * Check that a notebook's name is valid.
1587 1590 *
1588 1591 * @method test_notebook_name
1589 1592 * @param {String} nbname A name for this notebook
1590 1593 * @return {Boolean} True if the name is valid, false if invalid
1591 1594 */
1592 1595 Notebook.prototype.test_notebook_name = function (nbname) {
1593 1596 nbname = nbname || '';
1594 1597 if (nbname.length>0 && !this.notebook_name_blacklist_re.test(nbname)) {
1595 1598 return true;
1596 1599 } else {
1597 1600 return false;
1598 1601 }
1599 1602 };
1600 1603
1601 1604 /**
1602 1605 * Load a notebook from JSON (.ipynb).
1603 1606 *
1604 1607 * This currently handles one worksheet: others are deleted.
1605 1608 *
1606 1609 * @method fromJSON
1607 1610 * @param {Object} data JSON representation of a notebook
1608 1611 */
1609 1612 Notebook.prototype.fromJSON = function (data) {
1610 1613 var content = data.content;
1611 1614 var ncells = this.ncells();
1612 1615 var i;
1613 1616 for (i=0; i<ncells; i++) {
1614 1617 // Always delete cell 0 as they get renumbered as they are deleted.
1615 1618 this.delete_cell(0);
1616 1619 }
1617 1620 // Save the metadata and name.
1618 1621 this.metadata = content.metadata;
1619 1622 this.notebook_name = data.name;
1620 1623 var trusted = true;
1621 1624 // Only handle 1 worksheet for now.
1622 1625 var worksheet = content.worksheets[0];
1623 1626 if (worksheet !== undefined) {
1624 1627 if (worksheet.metadata) {
1625 1628 this.worksheet_metadata = worksheet.metadata;
1626 1629 }
1627 1630 var new_cells = worksheet.cells;
1628 1631 ncells = new_cells.length;
1629 1632 var cell_data = null;
1630 1633 var new_cell = null;
1631 1634 for (i=0; i<ncells; i++) {
1632 1635 cell_data = new_cells[i];
1633 1636 // VERSIONHACK: plaintext -> raw
1634 1637 // handle never-released plaintext name for raw cells
1635 1638 if (cell_data.cell_type === 'plaintext'){
1636 1639 cell_data.cell_type = 'raw';
1637 1640 }
1638 1641
1639 1642 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1640 1643 new_cell.fromJSON(cell_data);
1641 1644 if (new_cell.cell_type == 'code' && !new_cell.output_area.trusted) {
1642 1645 trusted = false;
1643 1646 }
1644 1647 }
1645 1648 }
1646 1649 if (trusted != this.trusted) {
1647 1650 this.trusted = trusted;
1648 1651 $([IPython.events]).trigger("trust_changed.Notebook", trusted);
1649 1652 }
1650 1653 if (content.worksheets.length > 1) {
1651 1654 IPython.dialog.modal({
1652 1655 title : "Multiple worksheets",
1653 1656 body : "This notebook has " + data.worksheets.length + " worksheets, " +
1654 1657 "but this version of IPython can only handle the first. " +
1655 1658 "If you save this notebook, worksheets after the first will be lost.",
1656 1659 buttons : {
1657 1660 OK : {
1658 1661 class : "btn-danger"
1659 1662 }
1660 1663 }
1661 1664 });
1662 1665 }
1663 1666 };
1664 1667
1665 1668 /**
1666 1669 * Dump this notebook into a JSON-friendly object.
1667 1670 *
1668 1671 * @method toJSON
1669 1672 * @return {Object} A JSON-friendly representation of this notebook.
1670 1673 */
1671 1674 Notebook.prototype.toJSON = function () {
1672 1675 var cells = this.get_cells();
1673 1676 var ncells = cells.length;
1674 1677 var cell_array = new Array(ncells);
1675 1678 var trusted = true;
1676 1679 for (var i=0; i<ncells; i++) {
1677 1680 var cell = cells[i];
1678 1681 if (cell.cell_type == 'code' && !cell.output_area.trusted) {
1679 1682 trusted = false;
1680 1683 }
1681 1684 cell_array[i] = cell.toJSON();
1682 1685 }
1683 1686 var data = {
1684 1687 // Only handle 1 worksheet for now.
1685 1688 worksheets : [{
1686 1689 cells: cell_array,
1687 1690 metadata: this.worksheet_metadata
1688 1691 }],
1689 1692 metadata : this.metadata
1690 1693 };
1691 1694 if (trusted != this.trusted) {
1692 1695 this.trusted = trusted;
1693 1696 $([IPython.events]).trigger("trust_changed.Notebook", trusted);
1694 1697 }
1695 1698 return data;
1696 1699 };
1697 1700
1698 1701 /**
1699 1702 * Start an autosave timer, for periodically saving the notebook.
1700 1703 *
1701 1704 * @method set_autosave_interval
1702 1705 * @param {Integer} interval the autosave interval in milliseconds
1703 1706 */
1704 1707 Notebook.prototype.set_autosave_interval = function (interval) {
1705 1708 var that = this;
1706 1709 // clear previous interval, so we don't get simultaneous timers
1707 1710 if (this.autosave_timer) {
1708 1711 clearInterval(this.autosave_timer);
1709 1712 }
1710 1713
1711 1714 this.autosave_interval = this.minimum_autosave_interval = interval;
1712 1715 if (interval) {
1713 1716 this.autosave_timer = setInterval(function() {
1714 1717 if (that.dirty) {
1715 1718 that.save_notebook();
1716 1719 }
1717 1720 }, interval);
1718 1721 $([IPython.events]).trigger("autosave_enabled.Notebook", interval);
1719 1722 } else {
1720 1723 this.autosave_timer = null;
1721 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 1732 * @method save_notebook
1729 1733 */
1730 1734 Notebook.prototype.save_notebook = function (extra_settings) {
1731 1735 // Create a JSON model to be sent to the server.
1732 1736 var model = {};
1733 1737 model.name = this.notebook_name;
1734 1738 model.path = this.notebook_path;
1735 1739 model.content = this.toJSON();
1736 1740 model.content.nbformat = this.nbformat;
1737 1741 model.content.nbformat_minor = this.nbformat_minor;
1738 1742 // time the ajax call for autosave tuning purposes.
1739 1743 var start = new Date().getTime();
1740 1744 // We do the call with settings so we can set cache to false.
1741 1745 var settings = {
1742 1746 processData : false,
1743 1747 cache : false,
1744 1748 type : "PUT",
1745 1749 data : JSON.stringify(model),
1746 1750 headers : {'Content-Type': 'application/json'},
1747 1751 success : $.proxy(this.save_notebook_success, this, start),
1748 1752 error : $.proxy(this.save_notebook_error, this)
1749 1753 };
1750 1754 if (extra_settings) {
1751 1755 for (var key in extra_settings) {
1752 1756 settings[key] = extra_settings[key];
1753 1757 }
1754 1758 }
1755 1759 $([IPython.events]).trigger('notebook_saving.Notebook');
1756 1760 var url = utils.url_join_encode(
1757 1761 this.base_url,
1758 1762 'api/notebooks',
1759 1763 this.notebook_path,
1760 1764 this.notebook_name
1761 1765 );
1762 1766 $.ajax(url, settings);
1763 1767 };
1764 1768
1765 1769 /**
1766 1770 * Success callback for saving a notebook.
1767 1771 *
1768 1772 * @method save_notebook_success
1769 1773 * @param {Integer} start the time when the save request started
1770 1774 * @param {Object} data JSON representation of a notebook
1771 1775 * @param {String} status Description of response status
1772 1776 * @param {jqXHR} xhr jQuery Ajax object
1773 1777 */
1774 1778 Notebook.prototype.save_notebook_success = function (start, data, status, xhr) {
1775 1779 this.set_dirty(false);
1776 1780 $([IPython.events]).trigger('notebook_saved.Notebook');
1777 1781 this._update_autosave_interval(start);
1778 1782 if (this._checkpoint_after_save) {
1779 1783 this.create_checkpoint();
1780 1784 this._checkpoint_after_save = false;
1781 1785 }
1782 1786 };
1783 1787
1784 1788 /**
1785 1789 * update the autosave interval based on how long the last save took
1786 1790 *
1787 1791 * @method _update_autosave_interval
1788 1792 * @param {Integer} timestamp when the save request started
1789 1793 */
1790 1794 Notebook.prototype._update_autosave_interval = function (start) {
1791 1795 var duration = (new Date().getTime() - start);
1792 1796 if (this.autosave_interval) {
1793 1797 // new save interval: higher of 10x save duration or parameter (default 30 seconds)
1794 1798 var interval = Math.max(10 * duration, this.minimum_autosave_interval);
1795 1799 // round to 10 seconds, otherwise we will be setting a new interval too often
1796 1800 interval = 10000 * Math.round(interval / 10000);
1797 1801 // set new interval, if it's changed
1798 1802 if (interval != this.autosave_interval) {
1799 1803 this.set_autosave_interval(interval);
1800 1804 }
1801 1805 }
1802 1806 };
1803 1807
1804 1808 /**
1805 1809 * Failure callback for saving a notebook.
1806 1810 *
1807 1811 * @method save_notebook_error
1808 1812 * @param {jqXHR} xhr jQuery Ajax object
1809 1813 * @param {String} status Description of response status
1810 1814 * @param {String} error HTTP error message
1811 1815 */
1812 1816 Notebook.prototype.save_notebook_error = function (xhr, status, error) {
1813 1817 $([IPython.events]).trigger('notebook_save_failed.Notebook', [xhr, status, error]);
1814 1818 };
1815 1819
1816 1820 /**
1817 1821 * Explicitly trust the output of this notebook.
1818 1822 *
1819 1823 * @method trust_notebook
1820 1824 */
1821 1825 Notebook.prototype.trust_notebook = function (extra_settings) {
1822 1826 var body = $("<div>").append($("<p>")
1823 1827 .text("A trusted IPython notebook may execute hidden malicious code ")
1824 1828 .append($("<strong>")
1825 1829 .append(
1826 1830 $("<em>").text("when you open it")
1827 1831 )
1828 1832 ).append(".").append(
1829 1833 " Selecting trust will immediately reload this notebook in a trusted state."
1830 1834 ).append(
1831 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 1837 .text("IPython security documentation")
1834 1838 ).append(".")
1835 1839 );
1836 1840
1837 1841 var nb = this;
1838 1842 IPython.dialog.modal({
1839 1843 title: "Trust this notebook?",
1840 1844 body: body,
1841 1845
1842 1846 buttons: {
1843 1847 Cancel : {},
1844 1848 Trust : {
1845 1849 class : "btn-danger",
1846 1850 click : function () {
1847 1851 var cells = nb.get_cells();
1848 1852 for (var i = 0; i < cells.length; i++) {
1849 1853 var cell = cells[i];
1850 1854 if (cell.cell_type == 'code') {
1851 1855 cell.output_area.trusted = true;
1852 1856 }
1853 1857 }
1854 1858 $([IPython.events]).on('notebook_saved.Notebook', function () {
1855 1859 window.location.reload();
1856 1860 });
1857 1861 nb.save_notebook();
1858 1862 }
1859 1863 }
1860 1864 }
1861 1865 });
1862 1866 };
1863 1867
1864 1868 Notebook.prototype.new_notebook = function(){
1865 1869 var path = this.notebook_path;
1866 1870 var base_url = this.base_url;
1867 1871 var settings = {
1868 1872 processData : false,
1869 1873 cache : false,
1870 1874 type : "POST",
1871 1875 dataType : "json",
1872 1876 async : false,
1873 1877 success : function (data, status, xhr){
1874 1878 var notebook_name = data.name;
1875 1879 window.open(
1876 1880 utils.url_join_encode(
1877 1881 base_url,
1878 1882 'notebooks',
1879 1883 path,
1880 1884 notebook_name
1881 1885 ),
1882 1886 '_blank'
1883 1887 );
1884 1888 }
1885 1889 };
1886 1890 var url = utils.url_join_encode(
1887 1891 base_url,
1888 1892 'api/notebooks',
1889 1893 path
1890 1894 );
1891 1895 $.ajax(url,settings);
1892 1896 };
1893 1897
1894 1898
1895 1899 Notebook.prototype.copy_notebook = function(){
1896 1900 var path = this.notebook_path;
1897 1901 var base_url = this.base_url;
1898 1902 var settings = {
1899 1903 processData : false,
1900 1904 cache : false,
1901 1905 type : "POST",
1902 1906 dataType : "json",
1903 1907 data : JSON.stringify({copy_from : this.notebook_name}),
1904 1908 async : false,
1905 1909 success : function (data, status, xhr) {
1906 1910 window.open(utils.url_join_encode(
1907 1911 base_url,
1908 1912 'notebooks',
1909 1913 data.path,
1910 1914 data.name
1911 1915 ), '_blank');
1912 1916 }
1913 1917 };
1914 1918 var url = utils.url_join_encode(
1915 1919 base_url,
1916 1920 'api/notebooks',
1917 1921 path
1918 1922 );
1919 1923 $.ajax(url,settings);
1920 1924 };
1921 1925
1922 1926 Notebook.prototype.rename = function (nbname) {
1923 1927 var that = this;
1924 1928 if (!nbname.match(/\.ipynb$/)) {
1925 1929 nbname = nbname + ".ipynb";
1926 1930 }
1927 1931 var data = {name: nbname};
1928 1932 var settings = {
1929 1933 processData : false,
1930 1934 cache : false,
1931 1935 type : "PATCH",
1932 1936 data : JSON.stringify(data),
1933 1937 dataType: "json",
1934 1938 headers : {'Content-Type': 'application/json'},
1935 1939 success : $.proxy(that.rename_success, this),
1936 1940 error : $.proxy(that.rename_error, this)
1937 1941 };
1938 1942 $([IPython.events]).trigger('rename_notebook.Notebook', data);
1939 1943 var url = utils.url_join_encode(
1940 1944 this.base_url,
1941 1945 'api/notebooks',
1942 1946 this.notebook_path,
1943 1947 this.notebook_name
1944 1948 );
1945 1949 $.ajax(url, settings);
1946 1950 };
1947 1951
1948 1952 Notebook.prototype.delete = function () {
1949 1953 var that = this;
1950 1954 var settings = {
1951 1955 processData : false,
1952 1956 cache : false,
1953 1957 type : "DELETE",
1954 1958 dataType: "json",
1955 1959 };
1956 1960 var url = utils.url_join_encode(
1957 1961 this.base_url,
1958 1962 'api/notebooks',
1959 1963 this.notebook_path,
1960 1964 this.notebook_name
1961 1965 );
1962 1966 $.ajax(url, settings);
1963 1967 };
1964 1968
1965 1969
1966 1970 Notebook.prototype.rename_success = function (json, status, xhr) {
1967 1971 var name = this.notebook_name = json.name;
1968 1972 var path = json.path;
1969 1973 this.session.rename_notebook(name, path);
1970 1974 $([IPython.events]).trigger('notebook_renamed.Notebook', json);
1971 1975 };
1972 1976
1973 1977 Notebook.prototype.rename_error = function (xhr, status, error) {
1974 1978 var that = this;
1975 1979 var dialog = $('<div/>').append(
1976 1980 $("<p/>").addClass("rename-message")
1977 1981 .text('This notebook name already exists.')
1978 1982 );
1979 1983 $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]);
1980 1984 IPython.dialog.modal({
1981 1985 title: "Notebook Rename Error!",
1982 1986 body: dialog,
1983 1987 buttons : {
1984 1988 "Cancel": {},
1985 1989 "OK": {
1986 1990 class: "btn-primary",
1987 1991 click: function () {
1988 1992 IPython.save_widget.rename_notebook();
1989 1993 }}
1990 1994 },
1991 1995 open : function (event, ui) {
1992 1996 var that = $(this);
1993 1997 // Upon ENTER, click the OK button.
1994 1998 that.find('input[type="text"]').keydown(function (event, ui) {
1995 1999 if (event.which === IPython.keyboard.keycodes.enter) {
1996 2000 that.find('.btn-primary').first().click();
1997 2001 }
1998 2002 });
1999 2003 that.find('input[type="text"]').focus();
2000 2004 }
2001 2005 });
2002 2006 };
2003 2007
2004 2008 /**
2005 2009 * Request a notebook's data from the server.
2006 2010 *
2007 2011 * @method load_notebook
2008 2012 * @param {String} notebook_name and path A notebook to load
2009 2013 */
2010 2014 Notebook.prototype.load_notebook = function (notebook_name, notebook_path) {
2011 2015 var that = this;
2012 2016 this.notebook_name = notebook_name;
2013 2017 this.notebook_path = notebook_path;
2014 2018 // We do the call with settings so we can set cache to false.
2015 2019 var settings = {
2016 2020 processData : false,
2017 2021 cache : false,
2018 2022 type : "GET",
2019 2023 dataType : "json",
2020 2024 success : $.proxy(this.load_notebook_success,this),
2021 2025 error : $.proxy(this.load_notebook_error,this),
2022 2026 };
2023 2027 $([IPython.events]).trigger('notebook_loading.Notebook');
2024 2028 var url = utils.url_join_encode(
2025 2029 this.base_url,
2026 2030 'api/notebooks',
2027 2031 this.notebook_path,
2028 2032 this.notebook_name
2029 2033 );
2030 2034 $.ajax(url, settings);
2031 2035 };
2032 2036
2033 2037 /**
2034 2038 * Success callback for loading a notebook from the server.
2035 2039 *
2036 2040 * Load notebook data from the JSON response.
2037 2041 *
2038 2042 * @method load_notebook_success
2039 2043 * @param {Object} data JSON representation of a notebook
2040 2044 * @param {String} status Description of response status
2041 2045 * @param {jqXHR} xhr jQuery Ajax object
2042 2046 */
2043 2047 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
2044 2048 this.fromJSON(data);
2045 2049 if (this.ncells() === 0) {
2046 2050 this.insert_cell_below('code');
2047 2051 this.edit_mode(0);
2048 2052 } else {
2049 2053 this.select(0);
2050 2054 this.handle_command_mode(this.get_cell(0));
2051 2055 }
2052 2056 this.set_dirty(false);
2053 2057 this.scroll_to_top();
2054 2058 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
2055 2059 var msg = "This notebook has been converted from an older " +
2056 2060 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
2057 2061 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
2058 2062 "newer notebook format will be used and older versions of IPython " +
2059 2063 "may not be able to read it. To keep the older version, close the " +
2060 2064 "notebook without saving it.";
2061 2065 IPython.dialog.modal({
2062 2066 title : "Notebook converted",
2063 2067 body : msg,
2064 2068 buttons : {
2065 2069 OK : {
2066 2070 class : "btn-primary"
2067 2071 }
2068 2072 }
2069 2073 });
2070 2074 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
2071 2075 var that = this;
2072 2076 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
2073 2077 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
2074 2078 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
2075 2079 this_vs + ". You can still work with this notebook, but some features " +
2076 2080 "introduced in later notebook versions may not be available.";
2077 2081
2078 2082 IPython.dialog.modal({
2079 2083 title : "Newer Notebook",
2080 2084 body : msg,
2081 2085 buttons : {
2082 2086 OK : {
2083 2087 class : "btn-danger"
2084 2088 }
2085 2089 }
2086 2090 });
2087 2091
2088 2092 }
2089 2093
2090 2094 // Create the session after the notebook is completely loaded to prevent
2091 2095 // code execution upon loading, which is a security risk.
2092 2096 if (this.session === null) {
2093 2097 this.start_session();
2094 2098 }
2095 2099 // load our checkpoint list
2096 2100 this.list_checkpoints();
2097 2101
2098 2102 // load toolbar state
2099 2103 if (this.metadata.celltoolbar) {
2100 2104 IPython.CellToolbar.global_show();
2101 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 2110 $([IPython.events]).trigger('notebook_loaded.Notebook');
2105 2111 };
2106 2112
2107 2113 /**
2108 2114 * Failure callback for loading a notebook from the server.
2109 2115 *
2110 2116 * @method load_notebook_error
2111 2117 * @param {jqXHR} xhr jQuery Ajax object
2112 2118 * @param {String} status Description of response status
2113 2119 * @param {String} error HTTP error message
2114 2120 */
2115 2121 Notebook.prototype.load_notebook_error = function (xhr, status, error) {
2116 2122 $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]);
2117 2123 var msg;
2118 2124 if (xhr.status === 400) {
2119 2125 msg = error;
2120 2126 } else if (xhr.status === 500) {
2121 2127 msg = "An unknown error occurred while loading this notebook. " +
2122 2128 "This version can load notebook formats " +
2123 2129 "v" + this.nbformat + " or earlier.";
2124 2130 }
2125 2131 IPython.dialog.modal({
2126 2132 title: "Error loading notebook",
2127 2133 body : msg,
2128 2134 buttons : {
2129 2135 "OK": {}
2130 2136 }
2131 2137 });
2132 2138 };
2133 2139
2134 2140 /********************* checkpoint-related *********************/
2135 2141
2136 2142 /**
2137 2143 * Save the notebook then immediately create a checkpoint.
2138 2144 *
2139 2145 * @method save_checkpoint
2140 2146 */
2141 2147 Notebook.prototype.save_checkpoint = function () {
2142 2148 this._checkpoint_after_save = true;
2143 2149 this.save_notebook();
2144 2150 };
2145 2151
2146 2152 /**
2147 2153 * Add a checkpoint for this notebook.
2148 2154 * for use as a callback from checkpoint creation.
2149 2155 *
2150 2156 * @method add_checkpoint
2151 2157 */
2152 2158 Notebook.prototype.add_checkpoint = function (checkpoint) {
2153 2159 var found = false;
2154 2160 for (var i = 0; i < this.checkpoints.length; i++) {
2155 2161 var existing = this.checkpoints[i];
2156 2162 if (existing.id == checkpoint.id) {
2157 2163 found = true;
2158 2164 this.checkpoints[i] = checkpoint;
2159 2165 break;
2160 2166 }
2161 2167 }
2162 2168 if (!found) {
2163 2169 this.checkpoints.push(checkpoint);
2164 2170 }
2165 2171 this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1];
2166 2172 };
2167 2173
2168 2174 /**
2169 2175 * List checkpoints for this notebook.
2170 2176 *
2171 2177 * @method list_checkpoints
2172 2178 */
2173 2179 Notebook.prototype.list_checkpoints = function () {
2174 2180 var url = utils.url_join_encode(
2175 2181 this.base_url,
2176 2182 'api/notebooks',
2177 2183 this.notebook_path,
2178 2184 this.notebook_name,
2179 2185 'checkpoints'
2180 2186 );
2181 2187 $.get(url).done(
2182 2188 $.proxy(this.list_checkpoints_success, this)
2183 2189 ).fail(
2184 2190 $.proxy(this.list_checkpoints_error, this)
2185 2191 );
2186 2192 };
2187 2193
2188 2194 /**
2189 2195 * Success callback for listing checkpoints.
2190 2196 *
2191 2197 * @method list_checkpoint_success
2192 2198 * @param {Object} data JSON representation of a checkpoint
2193 2199 * @param {String} status Description of response status
2194 2200 * @param {jqXHR} xhr jQuery Ajax object
2195 2201 */
2196 2202 Notebook.prototype.list_checkpoints_success = function (data, status, xhr) {
2197 2203 data = $.parseJSON(data);
2198 2204 this.checkpoints = data;
2199 2205 if (data.length) {
2200 2206 this.last_checkpoint = data[data.length - 1];
2201 2207 } else {
2202 2208 this.last_checkpoint = null;
2203 2209 }
2204 2210 $([IPython.events]).trigger('checkpoints_listed.Notebook', [data]);
2205 2211 };
2206 2212
2207 2213 /**
2208 2214 * Failure callback for listing a checkpoint.
2209 2215 *
2210 2216 * @method list_checkpoint_error
2211 2217 * @param {jqXHR} xhr jQuery Ajax object
2212 2218 * @param {String} status Description of response status
2213 2219 * @param {String} error_msg HTTP error message
2214 2220 */
2215 2221 Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) {
2216 2222 $([IPython.events]).trigger('list_checkpoints_failed.Notebook');
2217 2223 };
2218 2224
2219 2225 /**
2220 2226 * Create a checkpoint of this notebook on the server from the most recent save.
2221 2227 *
2222 2228 * @method create_checkpoint
2223 2229 */
2224 2230 Notebook.prototype.create_checkpoint = function () {
2225 2231 var url = utils.url_join_encode(
2226 2232 this.base_url,
2227 2233 'api/notebooks',
2228 2234 this.notebook_path,
2229 2235 this.notebook_name,
2230 2236 'checkpoints'
2231 2237 );
2232 2238 $.post(url).done(
2233 2239 $.proxy(this.create_checkpoint_success, this)
2234 2240 ).fail(
2235 2241 $.proxy(this.create_checkpoint_error, this)
2236 2242 );
2237 2243 };
2238 2244
2239 2245 /**
2240 2246 * Success callback for creating a checkpoint.
2241 2247 *
2242 2248 * @method create_checkpoint_success
2243 2249 * @param {Object} data JSON representation of a checkpoint
2244 2250 * @param {String} status Description of response status
2245 2251 * @param {jqXHR} xhr jQuery Ajax object
2246 2252 */
2247 2253 Notebook.prototype.create_checkpoint_success = function (data, status, xhr) {
2248 2254 data = $.parseJSON(data);
2249 2255 this.add_checkpoint(data);
2250 2256 $([IPython.events]).trigger('checkpoint_created.Notebook', data);
2251 2257 };
2252 2258
2253 2259 /**
2254 2260 * Failure callback for creating a checkpoint.
2255 2261 *
2256 2262 * @method create_checkpoint_error
2257 2263 * @param {jqXHR} xhr jQuery Ajax object
2258 2264 * @param {String} status Description of response status
2259 2265 * @param {String} error_msg HTTP error message
2260 2266 */
2261 2267 Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) {
2262 2268 $([IPython.events]).trigger('checkpoint_failed.Notebook');
2263 2269 };
2264 2270
2265 2271 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2266 2272 var that = this;
2267 2273 checkpoint = checkpoint || this.last_checkpoint;
2268 2274 if ( ! checkpoint ) {
2269 2275 console.log("restore dialog, but no checkpoint to restore to!");
2270 2276 return;
2271 2277 }
2272 2278 var body = $('<div/>').append(
2273 2279 $('<p/>').addClass("p-space").text(
2274 2280 "Are you sure you want to revert the notebook to " +
2275 2281 "the latest checkpoint?"
2276 2282 ).append(
2277 2283 $("<strong/>").text(
2278 2284 " This cannot be undone."
2279 2285 )
2280 2286 )
2281 2287 ).append(
2282 2288 $('<p/>').addClass("p-space").text("The checkpoint was last updated at:")
2283 2289 ).append(
2284 2290 $('<p/>').addClass("p-space").text(
2285 2291 Date(checkpoint.last_modified)
2286 2292 ).css("text-align", "center")
2287 2293 );
2288 2294
2289 2295 IPython.dialog.modal({
2290 2296 title : "Revert notebook to checkpoint",
2291 2297 body : body,
2292 2298 buttons : {
2293 2299 Revert : {
2294 2300 class : "btn-danger",
2295 2301 click : function () {
2296 2302 that.restore_checkpoint(checkpoint.id);
2297 2303 }
2298 2304 },
2299 2305 Cancel : {}
2300 2306 }
2301 2307 });
2302 2308 };
2303 2309
2304 2310 /**
2305 2311 * Restore the notebook to a checkpoint state.
2306 2312 *
2307 2313 * @method restore_checkpoint
2308 2314 * @param {String} checkpoint ID
2309 2315 */
2310 2316 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2311 2317 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2312 2318 var url = utils.url_join_encode(
2313 2319 this.base_url,
2314 2320 'api/notebooks',
2315 2321 this.notebook_path,
2316 2322 this.notebook_name,
2317 2323 'checkpoints',
2318 2324 checkpoint
2319 2325 );
2320 2326 $.post(url).done(
2321 2327 $.proxy(this.restore_checkpoint_success, this)
2322 2328 ).fail(
2323 2329 $.proxy(this.restore_checkpoint_error, this)
2324 2330 );
2325 2331 };
2326 2332
2327 2333 /**
2328 2334 * Success callback for restoring a notebook to a checkpoint.
2329 2335 *
2330 2336 * @method restore_checkpoint_success
2331 2337 * @param {Object} data (ignored, should be empty)
2332 2338 * @param {String} status Description of response status
2333 2339 * @param {jqXHR} xhr jQuery Ajax object
2334 2340 */
2335 2341 Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) {
2336 2342 $([IPython.events]).trigger('checkpoint_restored.Notebook');
2337 2343 this.load_notebook(this.notebook_name, this.notebook_path);
2338 2344 };
2339 2345
2340 2346 /**
2341 2347 * Failure callback for restoring a notebook to a checkpoint.
2342 2348 *
2343 2349 * @method restore_checkpoint_error
2344 2350 * @param {jqXHR} xhr jQuery Ajax object
2345 2351 * @param {String} status Description of response status
2346 2352 * @param {String} error_msg HTTP error message
2347 2353 */
2348 2354 Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) {
2349 2355 $([IPython.events]).trigger('checkpoint_restore_failed.Notebook');
2350 2356 };
2351 2357
2352 2358 /**
2353 2359 * Delete a notebook checkpoint.
2354 2360 *
2355 2361 * @method delete_checkpoint
2356 2362 * @param {String} checkpoint ID
2357 2363 */
2358 2364 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2359 2365 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2360 2366 var url = utils.url_join_encode(
2361 2367 this.base_url,
2362 2368 'api/notebooks',
2363 2369 this.notebook_path,
2364 2370 this.notebook_name,
2365 2371 'checkpoints',
2366 2372 checkpoint
2367 2373 );
2368 2374 $.ajax(url, {
2369 2375 type: 'DELETE',
2370 2376 success: $.proxy(this.delete_checkpoint_success, this),
2371 2377 error: $.proxy(this.delete_notebook_error,this)
2372 2378 });
2373 2379 };
2374 2380
2375 2381 /**
2376 2382 * Success callback for deleting a notebook checkpoint
2377 2383 *
2378 2384 * @method delete_checkpoint_success
2379 2385 * @param {Object} data (ignored, should be empty)
2380 2386 * @param {String} status Description of response status
2381 2387 * @param {jqXHR} xhr jQuery Ajax object
2382 2388 */
2383 2389 Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) {
2384 2390 $([IPython.events]).trigger('checkpoint_deleted.Notebook', data);
2385 2391 this.load_notebook(this.notebook_name, this.notebook_path);
2386 2392 };
2387 2393
2388 2394 /**
2389 2395 * Failure callback for deleting a notebook checkpoint.
2390 2396 *
2391 2397 * @method delete_checkpoint_error
2392 2398 * @param {jqXHR} xhr jQuery Ajax object
2393 2399 * @param {String} status Description of response status
2394 2400 * @param {String} error_msg HTTP error message
2395 2401 */
2396 2402 Notebook.prototype.delete_checkpoint_error = function (xhr, status, error_msg) {
2397 2403 $([IPython.events]).trigger('checkpoint_delete_failed.Notebook');
2398 2404 };
2399 2405
2400 2406
2401 2407 IPython.Notebook = Notebook;
2402 2408
2403 2409
2404 2410 return IPython;
2405 2411
2406 2412 }(IPython));
2407 2413
@@ -1,235 +1,235 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2012 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Notification widget
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13 "use strict";
14 14 var utils = IPython.utils;
15 15
16 16
17 17 var NotificationArea = function (selector) {
18 18 this.selector = selector;
19 19 if (this.selector !== undefined) {
20 20 this.element = $(selector);
21 21 }
22 22 this.widget_dict = {};
23 23 };
24 24
25 25 NotificationArea.prototype.temp_message = function (msg, timeout, css_class) {
26 26 var uuid = utils.uuid();
27 27 if( css_class == 'danger') {css_class = 'ui-state-error';}
28 28 if( css_class == 'warning') {css_class = 'ui-state-highlight';}
29 29 var tdiv = $('<div>')
30 30 .attr('id',uuid)
31 31 .addClass('notification_widget ui-widget ui-widget-content ui-corner-all')
32 32 .addClass('border-box-sizing')
33 33 .addClass(css_class)
34 34 .hide()
35 35 .text(msg);
36 36
37 37 $(this.selector).append(tdiv);
38 38 var tmout = Math.max(1500,(timeout||1500));
39 39 tdiv.fadeIn(100);
40 40
41 41 setTimeout(function () {
42 42 tdiv.fadeOut(100, function () {tdiv.remove();});
43 43 }, tmout);
44 44 };
45 45
46 46 NotificationArea.prototype.widget = function(name) {
47 47 if(this.widget_dict[name] === undefined) {
48 48 return this.new_notification_widget(name);
49 49 }
50 50 return this.get_widget(name);
51 51 };
52 52
53 53 NotificationArea.prototype.get_widget = function(name) {
54 54 if(this.widget_dict[name] === undefined) {
55 55 throw('no widgets with this name');
56 56 }
57 57 return this.widget_dict[name];
58 58 };
59 59
60 60 NotificationArea.prototype.new_notification_widget = function(name) {
61 61 if(this.widget_dict[name] !== undefined) {
62 62 throw('widget with that name already exists ! ');
63 63 }
64 64 var div = $('<div/>').attr('id','notification_'+name);
65 65 $(this.selector).append(div);
66 66 this.widget_dict[name] = new IPython.NotificationWidget('#notification_'+name);
67 67 return this.widget_dict[name];
68 68 };
69 69
70 70 NotificationArea.prototype.init_notification_widgets = function() {
71 71 var knw = this.new_notification_widget('kernel');
72 72 var $kernel_ind_icon = $("#kernel_indicator_icon");
73 73 var $modal_ind_icon = $("#modal_indicator_icon");
74 74
75 75 // Command/Edit mode
76 76 $([IPython.events]).on('edit_mode.Notebook',function () {
77 77 IPython.save_widget.update_document_title();
78 78 $modal_ind_icon.attr('class','edit_mode_icon').attr('title','Edit Mode');
79 79 });
80 80
81 81 $([IPython.events]).on('command_mode.Notebook',function () {
82 82 IPython.save_widget.update_document_title();
83 83 $modal_ind_icon.attr('class','command_mode_icon').attr('title','Command Mode');
84 84 });
85 85
86 86 // Implicitly start off in Command mode, switching to Edit mode will trigger event
87 87 $modal_ind_icon.attr('class','command-mode_icon').attr('title','Command Mode');
88 88
89 89 // Kernel events
90 90 $([IPython.events]).on('status_idle.Kernel',function () {
91 91 IPython.save_widget.update_document_title();
92 92 $kernel_ind_icon.attr('class','kernel_idle_icon').attr('title','Kernel Idle');
93 93 });
94 94
95 95 $([IPython.events]).on('status_busy.Kernel',function () {
96 96 window.document.title='(Busy) '+window.document.title;
97 97 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
98 98 });
99 99
100 100 $([IPython.events]).on('status_restarting.Kernel',function () {
101 101 IPython.save_widget.update_document_title();
102 102 knw.set_message("Restarting kernel", 2000);
103 103 });
104 104
105 105 $([IPython.events]).on('status_interrupting.Kernel',function () {
106 106 knw.set_message("Interrupting kernel", 2000);
107 107 });
108 108
109 109 // Start the kernel indicator in the busy state, and send a kernel_info request.
110 110 // When the kernel_info reply arrives, the kernel is idle.
111 111 $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy');
112 112
113 113 $([IPython.events]).on('status_started.Kernel', function (evt, data) {
114 114 data.kernel.kernel_info(function () {
115 115 $([IPython.events]).trigger('status_idle.Kernel');
116 116 });
117 117 });
118 118
119 119 $([IPython.events]).on('status_dead.Kernel',function () {
120 120 var msg = 'The kernel has died, and the automatic restart has failed.' +
121 121 ' It is possible the kernel cannot be restarted.' +
122 122 ' If you are not able to restart the kernel, you will still be able to save' +
123 123 ' the notebook, but running code will no longer work until the notebook' +
124 124 ' is reopened.';
125 125
126 126 IPython.dialog.modal({
127 127 title: "Dead kernel",
128 128 body : msg,
129 129 buttons : {
130 130 "Manual Restart": {
131 131 class: "btn-danger",
132 132 click: function () {
133 133 $([IPython.events]).trigger('status_restarting.Kernel');
134 134 IPython.notebook.start_kernel();
135 135 }
136 136 },
137 137 "Don't restart": {}
138 138 }
139 139 });
140 140 });
141 141
142 142 $([IPython.events]).on('websocket_closed.Kernel', function (event, data) {
143 143 var kernel = data.kernel;
144 144 var ws_url = data.ws_url;
145 145 var early = data.early;
146 146 var msg;
147 147 if (!early) {
148 148 knw.set_message('Reconnecting WebSockets', 1000);
149 149 setTimeout(function () {
150 150 kernel.start_channels();
151 151 }, 5000);
152 152 return;
153 153 }
154 154 console.log('WebSocket connection failed: ', ws_url);
155 155 msg = "A WebSocket connection could not be established." +
156 156 " You will NOT be able to run code. Check your" +
157 157 " network connection or notebook server configuration.";
158 158 IPython.dialog.modal({
159 159 title: "WebSocket connection failed",
160 160 body: msg,
161 161 buttons : {
162 162 "OK": {},
163 163 "Reconnect": {
164 164 click: function () {
165 165 knw.set_message('Reconnecting WebSockets', 1000);
166 166 setTimeout(function () {
167 167 kernel.start_channels();
168 168 }, 5000);
169 169 }
170 170 }
171 171 }
172 172 });
173 173 });
174 174
175 175
176 176 var nnw = this.new_notification_widget('notebook');
177 177
178 178 // Notebook events
179 179 $([IPython.events]).on('notebook_loading.Notebook', function () {
180 180 nnw.set_message("Loading notebook",500);
181 181 });
182 182 $([IPython.events]).on('notebook_loaded.Notebook', function () {
183 183 nnw.set_message("Notebook loaded",500);
184 184 });
185 185 $([IPython.events]).on('notebook_saving.Notebook', function () {
186 186 nnw.set_message("Saving notebook",500);
187 187 });
188 188 $([IPython.events]).on('notebook_saved.Notebook', function () {
189 189 nnw.set_message("Notebook saved",2000);
190 190 });
191 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
192 nnw.set_message("Notebook save failed");
191 $([IPython.events]).on('notebook_save_failed.Notebook', function (evt, xhr, status, data) {
192 nnw.set_message(data || "Notebook save failed");
193 193 });
194 194
195 195 // Checkpoint events
196 196 $([IPython.events]).on('checkpoint_created.Notebook', function (evt, data) {
197 197 var msg = "Checkpoint created";
198 198 if (data.last_modified) {
199 199 var d = new Date(data.last_modified);
200 200 msg = msg + ": " + d.format("HH:MM:ss");
201 201 }
202 202 nnw.set_message(msg, 2000);
203 203 });
204 204 $([IPython.events]).on('checkpoint_failed.Notebook', function () {
205 205 nnw.set_message("Checkpoint failed");
206 206 });
207 207 $([IPython.events]).on('checkpoint_deleted.Notebook', function () {
208 208 nnw.set_message("Checkpoint deleted", 500);
209 209 });
210 210 $([IPython.events]).on('checkpoint_delete_failed.Notebook', function () {
211 211 nnw.set_message("Checkpoint delete failed");
212 212 });
213 213 $([IPython.events]).on('checkpoint_restoring.Notebook', function () {
214 214 nnw.set_message("Restoring to checkpoint...", 500);
215 215 });
216 216 $([IPython.events]).on('checkpoint_restore_failed.Notebook', function () {
217 217 nnw.set_message("Checkpoint restore failed");
218 218 });
219 219
220 220 // Autosave events
221 221 $([IPython.events]).on('autosave_disabled.Notebook', function () {
222 222 nnw.set_message("Autosave disabled", 2000);
223 223 });
224 224 $([IPython.events]).on('autosave_enabled.Notebook', function (evt, interval) {
225 225 nnw.set_message("Saving every " + interval / 1000 + "s", 1000);
226 226 });
227 227
228 228 };
229 229
230 230 IPython.NotificationArea = NotificationArea;
231 231
232 232 return IPython;
233 233
234 234 }(IPython));
235 235
@@ -1,874 +1,878 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // OutputArea
10 10 //============================================================================
11 11
12 12 /**
13 13 * @module IPython
14 14 * @namespace IPython
15 15 * @submodule OutputArea
16 16 */
17 17 var IPython = (function (IPython) {
18 18 "use strict";
19 19
20 20 var utils = IPython.utils;
21 21
22 22 /**
23 23 * @class OutputArea
24 24 *
25 25 * @constructor
26 26 */
27 27
28 28 var OutputArea = function (selector, prompt_area) {
29 29 this.selector = selector;
30 30 this.wrapper = $(selector);
31 31 this.outputs = [];
32 32 this.collapsed = false;
33 33 this.scrolled = false;
34 34 this.trusted = true;
35 35 this.clear_queued = null;
36 36 if (prompt_area === undefined) {
37 37 this.prompt_area = true;
38 38 } else {
39 39 this.prompt_area = prompt_area;
40 40 }
41 41 this.create_elements();
42 42 this.style();
43 43 this.bind_events();
44 44 };
45 45
46 46
47 47 /**
48 48 * Class prototypes
49 49 **/
50 50
51 51 OutputArea.prototype.create_elements = function () {
52 52 this.element = $("<div/>");
53 53 this.collapse_button = $("<div/>");
54 54 this.prompt_overlay = $("<div/>");
55 55 this.wrapper.append(this.prompt_overlay);
56 56 this.wrapper.append(this.element);
57 57 this.wrapper.append(this.collapse_button);
58 58 };
59 59
60 60
61 61 OutputArea.prototype.style = function () {
62 62 this.collapse_button.hide();
63 63 this.prompt_overlay.hide();
64 64
65 65 this.wrapper.addClass('output_wrapper');
66 66 this.element.addClass('output');
67 67
68 68 this.collapse_button.addClass("btn output_collapsed");
69 69 this.collapse_button.attr('title', 'click to expand output');
70 70 this.collapse_button.text('. . .');
71 71
72 72 this.prompt_overlay.addClass('out_prompt_overlay prompt');
73 73 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
74 74
75 75 this.collapse();
76 76 };
77 77
78 78 /**
79 79 * Should the OutputArea scroll?
80 80 * Returns whether the height (in lines) exceeds a threshold.
81 81 *
82 82 * @private
83 83 * @method _should_scroll
84 84 * @param [lines=100]{Integer}
85 85 * @return {Bool}
86 86 *
87 87 */
88 88 OutputArea.prototype._should_scroll = function (lines) {
89 89 if (lines <=0 ){ return }
90 90 if (!lines) {
91 91 lines = 100;
92 92 }
93 93 // line-height from http://stackoverflow.com/questions/1185151
94 94 var fontSize = this.element.css('font-size');
95 95 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
96 96
97 97 return (this.element.height() > lines * lineHeight);
98 98 };
99 99
100 100
101 101 OutputArea.prototype.bind_events = function () {
102 102 var that = this;
103 103 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
104 104 this.prompt_overlay.click(function () { that.toggle_scroll(); });
105 105
106 106 this.element.resize(function () {
107 107 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
108 108 if ( IPython.utils.browser[0] === "Firefox" ) {
109 109 return;
110 110 }
111 111 // maybe scroll output,
112 112 // if it's grown large enough and hasn't already been scrolled.
113 113 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
114 114 that.scroll_area();
115 115 }
116 116 });
117 117 this.collapse_button.click(function () {
118 118 that.expand();
119 119 });
120 120 };
121 121
122 122
123 123 OutputArea.prototype.collapse = function () {
124 124 if (!this.collapsed) {
125 125 this.element.hide();
126 126 this.prompt_overlay.hide();
127 127 if (this.element.html()){
128 128 this.collapse_button.show();
129 129 }
130 130 this.collapsed = true;
131 131 }
132 132 };
133 133
134 134
135 135 OutputArea.prototype.expand = function () {
136 136 if (this.collapsed) {
137 137 this.collapse_button.hide();
138 138 this.element.show();
139 139 this.prompt_overlay.show();
140 140 this.collapsed = false;
141 141 }
142 142 };
143 143
144 144
145 145 OutputArea.prototype.toggle_output = function () {
146 146 if (this.collapsed) {
147 147 this.expand();
148 148 } else {
149 149 this.collapse();
150 150 }
151 151 };
152 152
153 153
154 154 OutputArea.prototype.scroll_area = function () {
155 155 this.element.addClass('output_scroll');
156 156 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
157 157 this.scrolled = true;
158 158 };
159 159
160 160
161 161 OutputArea.prototype.unscroll_area = function () {
162 162 this.element.removeClass('output_scroll');
163 163 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
164 164 this.scrolled = false;
165 165 };
166 166
167 167 /**
168 168 *
169 169 * Scroll OutputArea if height supperior than a threshold (in lines).
170 170 *
171 171 * Threshold is a maximum number of lines. If unspecified, defaults to
172 172 * OutputArea.minimum_scroll_threshold.
173 173 *
174 174 * Negative threshold will prevent the OutputArea from ever scrolling.
175 175 *
176 176 * @method scroll_if_long
177 177 *
178 178 * @param [lines=20]{Number} Default to 20 if not set,
179 179 * behavior undefined for value of `0`.
180 180 *
181 181 **/
182 182 OutputArea.prototype.scroll_if_long = function (lines) {
183 183 var n = lines | OutputArea.minimum_scroll_threshold;
184 184 if(n <= 0){
185 185 return
186 186 }
187 187
188 188 if (this._should_scroll(n)) {
189 189 // only allow scrolling long-enough output
190 190 this.scroll_area();
191 191 }
192 192 };
193 193
194 194
195 195 OutputArea.prototype.toggle_scroll = function () {
196 196 if (this.scrolled) {
197 197 this.unscroll_area();
198 198 } else {
199 199 // only allow scrolling long-enough output
200 200 this.scroll_if_long();
201 201 }
202 202 };
203 203
204 204
205 205 // typeset with MathJax if MathJax is available
206 206 OutputArea.prototype.typeset = function () {
207 207 if (window.MathJax){
208 208 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
209 209 }
210 210 };
211 211
212 212
213 213 OutputArea.prototype.handle_output = function (msg) {
214 214 var json = {};
215 215 var msg_type = json.output_type = msg.header.msg_type;
216 216 var content = msg.content;
217 217 if (msg_type === "stream") {
218 218 json.text = content.data;
219 219 json.stream = content.name;
220 220 } else if (msg_type === "display_data") {
221 221 json = content.data;
222 222 json.output_type = msg_type;
223 223 json.metadata = content.metadata;
224 224 } else if (msg_type === "pyout") {
225 225 json = content.data;
226 226 json.output_type = msg_type;
227 227 json.metadata = content.metadata;
228 228 json.prompt_number = content.execution_count;
229 229 } else if (msg_type === "pyerr") {
230 230 json.ename = content.ename;
231 231 json.evalue = content.evalue;
232 232 json.traceback = content.traceback;
233 233 }
234 234 this.append_output(json);
235 235 };
236 236
237 237
238 238 OutputArea.prototype.rename_keys = function (data, key_map) {
239 239 var remapped = {};
240 240 for (var key in data) {
241 241 var new_key = key_map[key] || key;
242 242 remapped[new_key] = data[key];
243 243 }
244 244 return remapped;
245 245 };
246 246
247 247
248 248 OutputArea.output_types = [
249 249 'application/javascript',
250 250 'text/html',
251 251 'text/latex',
252 252 'image/svg+xml',
253 253 'image/png',
254 254 'image/jpeg',
255 255 'application/pdf',
256 256 'text/plain'
257 257 ];
258 258
259 259 OutputArea.prototype.validate_output = function (json) {
260 260 // scrub invalid outputs
261 261 // TODO: right now everything is a string, but JSON really shouldn't be.
262 262 // nbformat 4 will fix that.
263 263 $.map(OutputArea.output_types, function(key){
264 264 if (json[key] !== undefined && typeof json[key] !== 'string') {
265 265 console.log("Invalid type for " + key, json[key]);
266 266 delete json[key];
267 267 }
268 268 });
269 269 return json;
270 270 };
271 271
272 272 OutputArea.prototype.append_output = function (json) {
273 273 this.expand();
274 274 // Clear the output if clear is queued.
275 275 var needs_height_reset = false;
276 276 if (this.clear_queued) {
277 277 this.clear_output(false);
278 278 needs_height_reset = true;
279 279 }
280 280
281 281 // validate output data types
282 282 json = this.validate_output(json);
283 283
284 284 if (json.output_type === 'pyout') {
285 285 this.append_pyout(json);
286 286 } else if (json.output_type === 'pyerr') {
287 287 this.append_pyerr(json);
288 288 } else if (json.output_type === 'display_data') {
289 289 this.append_display_data(json);
290 290 } else if (json.output_type === 'stream') {
291 291 this.append_stream(json);
292 292 }
293 293
294 294 this.outputs.push(json);
295 295
296 296 // Only reset the height to automatic if the height is currently
297 297 // fixed (done by wait=True flag on clear_output).
298 298 if (needs_height_reset) {
299 299 this.element.height('');
300 300 }
301 301
302 302 var that = this;
303 303 setTimeout(function(){that.element.trigger('resize');}, 100);
304 304 };
305 305
306 306
307 307 OutputArea.prototype.create_output_area = function () {
308 308 var oa = $("<div/>").addClass("output_area");
309 309 if (this.prompt_area) {
310 310 oa.append($('<div/>').addClass('prompt'));
311 311 }
312 312 return oa;
313 313 };
314 314
315 315
316 316 function _get_metadata_key(metadata, key, mime) {
317 317 var mime_md = metadata[mime];
318 318 // mime-specific higher priority
319 319 if (mime_md && mime_md[key] !== undefined) {
320 320 return mime_md[key];
321 321 }
322 322 // fallback on global
323 323 return metadata[key];
324 324 }
325 325
326 326 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
327 327 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
328 328 if (_get_metadata_key(md, 'isolated', mime)) {
329 329 // Create an iframe to isolate the subarea from the rest of the
330 330 // document
331 331 var iframe = $('<iframe/>').addClass('box-flex1');
332 332 iframe.css({'height':1, 'width':'100%', 'display':'block'});
333 333 iframe.attr('frameborder', 0);
334 334 iframe.attr('scrolling', 'auto');
335 335
336 336 // Once the iframe is loaded, the subarea is dynamically inserted
337 337 iframe.on('load', function() {
338 338 // Workaround needed by Firefox, to properly render svg inside
339 339 // iframes, see http://stackoverflow.com/questions/10177190/
340 340 // svg-dynamically-added-to-iframe-does-not-render-correctly
341 341 this.contentDocument.open();
342 342
343 343 // Insert the subarea into the iframe
344 344 // We must directly write the html. When using Jquery's append
345 345 // method, javascript is evaluated in the parent document and
346 346 // not in the iframe document. At this point, subarea doesn't
347 347 // contain any user content.
348 348 this.contentDocument.write(subarea.html());
349 349
350 350 this.contentDocument.close();
351 351
352 352 var body = this.contentDocument.body;
353 353 // Adjust the iframe height automatically
354 354 iframe.height(body.scrollHeight + 'px');
355 355 });
356 356
357 357 // Elements should be appended to the inner subarea and not to the
358 358 // iframe
359 359 iframe.append = function(that) {
360 360 subarea.append(that);
361 361 };
362 362
363 363 return iframe;
364 364 } else {
365 365 return subarea;
366 366 }
367 367 }
368 368
369 369
370 370 OutputArea.prototype._append_javascript_error = function (err, element) {
371 371 // display a message when a javascript error occurs in display output
372 372 var msg = "Javascript error adding output!"
373 373 if ( element === undefined ) return;
374 374 element
375 375 .append($('<div/>').text(msg).addClass('js-error'))
376 376 .append($('<div/>').text(err.toString()).addClass('js-error'))
377 377 .append($('<div/>').text('See your browser Javascript console for more details.').addClass('js-error'));
378 378 };
379 379
380 380 OutputArea.prototype._safe_append = function (toinsert) {
381 381 // safely append an item to the document
382 382 // this is an object created by user code,
383 383 // and may have errors, which should not be raised
384 384 // under any circumstances.
385 385 try {
386 386 this.element.append(toinsert);
387 387 } catch(err) {
388 388 console.log(err);
389 389 // Create an actual output_area and output_subarea, which creates
390 390 // the prompt area and the proper indentation.
391 391 var toinsert = this.create_output_area();
392 392 var subarea = $('<div/>').addClass('output_subarea');
393 393 toinsert.append(subarea);
394 394 this._append_javascript_error(err, subarea);
395 395 this.element.append(toinsert);
396 396 }
397 397 };
398 398
399 399
400 400 OutputArea.prototype.append_pyout = function (json) {
401 401 var n = json.prompt_number || ' ';
402 402 var toinsert = this.create_output_area();
403 403 if (this.prompt_area) {
404 404 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
405 405 }
406 406 var inserted = this.append_mime_type(json, toinsert);
407 407 if (inserted) {
408 408 inserted.addClass('output_pyout');
409 409 }
410 410 this._safe_append(toinsert);
411 411 // If we just output latex, typeset it.
412 412 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
413 413 this.typeset();
414 414 }
415 415 };
416 416
417 417
418 418 OutputArea.prototype.append_pyerr = function (json) {
419 419 var tb = json.traceback;
420 420 if (tb !== undefined && tb.length > 0) {
421 421 var s = '';
422 422 var len = tb.length;
423 423 for (var i=0; i<len; i++) {
424 424 s = s + tb[i] + '\n';
425 425 }
426 426 s = s + '\n';
427 427 var toinsert = this.create_output_area();
428 428 var append_text = OutputArea.append_map['text/plain'];
429 429 if (append_text) {
430 430 append_text.apply(this, [s, {}, toinsert]).addClass('output_pyerr');
431 431 }
432 432 this._safe_append(toinsert);
433 433 }
434 434 };
435 435
436 436
437 437 OutputArea.prototype.append_stream = function (json) {
438 438 // temporary fix: if stream undefined (json file written prior to this patch),
439 439 // default to most likely stdout:
440 440 if (json.stream === undefined){
441 441 json.stream = 'stdout';
442 442 }
443 443 var text = json.text;
444 444 var subclass = "output_"+json.stream;
445 445 if (this.outputs.length > 0){
446 446 // have at least one output to consider
447 447 var last = this.outputs[this.outputs.length-1];
448 448 if (last.output_type == 'stream' && json.stream == last.stream){
449 449 // latest output was in the same stream,
450 450 // so append directly into its pre tag
451 451 // escape ANSI & HTML specials:
452 452 var pre = this.element.find('div.'+subclass).last().find('pre');
453 453 var html = utils.fixCarriageReturn(
454 454 pre.html() + utils.fixConsole(text));
455 455 // The only user content injected with this HTML call is
456 456 // escaped by the fixConsole() method.
457 457 pre.html(html);
458 458 return;
459 459 }
460 460 }
461 461
462 462 if (!text.replace("\r", "")) {
463 463 // text is nothing (empty string, \r, etc.)
464 464 // so don't append any elements, which might add undesirable space
465 465 return;
466 466 }
467 467
468 468 // If we got here, attach a new div
469 469 var toinsert = this.create_output_area();
470 470 var append_text = OutputArea.append_map['text/plain'];
471 471 if (append_text) {
472 472 append_text.apply(this, [text, {}, toinsert]).addClass("output_stream " + subclass);
473 473 }
474 474 this._safe_append(toinsert);
475 475 };
476 476
477 477
478 478 OutputArea.prototype.append_display_data = function (json) {
479 479 var toinsert = this.create_output_area();
480 480 if (this.append_mime_type(json, toinsert)) {
481 481 this._safe_append(toinsert);
482 482 // If we just output latex, typeset it.
483 483 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
484 484 this.typeset();
485 485 }
486 486 }
487 487 };
488 488
489 489
490 490 OutputArea.safe_outputs = {
491 491 'text/plain' : true,
492 492 'text/latex' : true,
493 493 'image/png' : true,
494 494 'image/jpeg' : true
495 495 };
496 496
497 497 OutputArea.prototype.append_mime_type = function (json, element) {
498 498 for (var type_i in OutputArea.display_order) {
499 499 var type = OutputArea.display_order[type_i];
500 500 var append = OutputArea.append_map[type];
501 501 if ((json[type] !== undefined) && append) {
502 502 var value = json[type];
503 503 if (!this.trusted && !OutputArea.safe_outputs[type]) {
504 504 // not trusted, sanitize HTML
505 505 if (type==='text/html' || type==='text/svg') {
506 506 value = IPython.security.sanitize_html(value);
507 507 } else {
508 508 // don't display if we don't know how to sanitize it
509 509 console.log("Ignoring untrusted " + type + " output.");
510 510 continue;
511 511 }
512 512 }
513 513 var md = json.metadata || {};
514 514 var toinsert = append.apply(this, [value, md, element]);
515 515 $([IPython.events]).trigger('output_appended.OutputArea', [type, value, md, toinsert]);
516 516 return toinsert;
517 517 }
518 518 }
519 519 return null;
520 520 };
521 521
522 522
523 523 var append_html = function (html, md, element) {
524 524 var type = 'text/html';
525 525 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
526 526 IPython.keyboard_manager.register_events(toinsert);
527 527 toinsert.append(html);
528 528 element.append(toinsert);
529 529 return toinsert;
530 530 };
531 531
532 532
533 533 var append_javascript = function (js, md, element) {
534 534 // We just eval the JS code, element appears in the local scope.
535 535 var type = 'application/javascript';
536 536 var toinsert = this.create_output_subarea(md, "output_javascript", type);
537 537 IPython.keyboard_manager.register_events(toinsert);
538 538 element.append(toinsert);
539 539 // FIXME TODO : remove `container element for 3.0`
540 540 //backward compat, js should be eval'ed in a context where `container` is defined.
541 541 var container = element;
542 542 container.show = function(){console.log('Warning "container.show()" is deprecated.')};
543 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 548 try {
545 549 eval(js);
546 550 } catch(err) {
547 551 console.log(err);
548 552 this._append_javascript_error(err, toinsert);
549 553 }
550 554 return toinsert;
551 555 };
552 556
553 557
554 558 var append_text = function (data, md, element) {
555 559 var type = 'text/plain';
556 560 var toinsert = this.create_output_subarea(md, "output_text", type);
557 561 // escape ANSI & HTML specials in plaintext:
558 562 data = utils.fixConsole(data);
559 563 data = utils.fixCarriageReturn(data);
560 564 data = utils.autoLinkUrls(data);
561 565 // The only user content injected with this HTML call is
562 566 // escaped by the fixConsole() method.
563 567 toinsert.append($("<pre/>").html(data));
564 568 element.append(toinsert);
565 569 return toinsert;
566 570 };
567 571
568 572
569 573 var append_svg = function (svg, md, element) {
570 574 var type = 'image/svg+xml';
571 575 var toinsert = this.create_output_subarea(md, "output_svg", type);
572 576 toinsert.append(svg);
573 577 element.append(toinsert);
574 578 return toinsert;
575 579 };
576 580
577 581
578 582 OutputArea.prototype._dblclick_to_reset_size = function (img) {
579 583 // wrap image after it's loaded on the page,
580 584 // otherwise the measured initial size will be incorrect
581 585 img.on("load", function (){
582 586 var h0 = img.height();
583 587 var w0 = img.width();
584 588 if (!(h0 && w0)) {
585 589 // zero size, don't make it resizable
586 590 return;
587 591 }
588 592 img.resizable({
589 593 aspectRatio: true,
590 594 autoHide: true
591 595 });
592 596 img.dblclick(function () {
593 597 // resize wrapper & image together for some reason:
594 598 img.parent().height(h0);
595 599 img.height(h0);
596 600 img.parent().width(w0);
597 601 img.width(w0);
598 602 });
599 603 });
600 604 };
601 605
602 606 var set_width_height = function (img, md, mime) {
603 607 // set width and height of an img element from metadata
604 608 var height = _get_metadata_key(md, 'height', mime);
605 609 if (height !== undefined) img.attr('height', height);
606 610 var width = _get_metadata_key(md, 'width', mime);
607 611 if (width !== undefined) img.attr('width', width);
608 612 };
609 613
610 614 var append_png = function (png, md, element) {
611 615 var type = 'image/png';
612 616 var toinsert = this.create_output_subarea(md, "output_png", type);
613 617 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
614 618 set_width_height(img, md, 'image/png');
615 619 this._dblclick_to_reset_size(img);
616 620 toinsert.append(img);
617 621 element.append(toinsert);
618 622 return toinsert;
619 623 };
620 624
621 625
622 626 var append_jpeg = function (jpeg, md, element) {
623 627 var type = 'image/jpeg';
624 628 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
625 629 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
626 630 set_width_height(img, md, 'image/jpeg');
627 631 this._dblclick_to_reset_size(img);
628 632 toinsert.append(img);
629 633 element.append(toinsert);
630 634 return toinsert;
631 635 };
632 636
633 637
634 638 var append_pdf = function (pdf, md, element) {
635 639 var type = 'application/pdf';
636 640 var toinsert = this.create_output_subarea(md, "output_pdf", type);
637 641 var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf);
638 642 a.attr('target', '_blank');
639 643 a.text('View PDF')
640 644 toinsert.append(a);
641 645 element.append(toinsert);
642 646 return toinsert;
643 647 }
644 648
645 649 var append_latex = function (latex, md, element) {
646 650 // This method cannot do the typesetting because the latex first has to
647 651 // be on the page.
648 652 var type = 'text/latex';
649 653 var toinsert = this.create_output_subarea(md, "output_latex", type);
650 654 toinsert.append(latex);
651 655 element.append(toinsert);
652 656 return toinsert;
653 657 };
654 658
655 659
656 660 OutputArea.prototype.append_raw_input = function (msg) {
657 661 var that = this;
658 662 this.expand();
659 663 var content = msg.content;
660 664 var area = this.create_output_area();
661 665
662 666 // disable any other raw_inputs, if they are left around
663 667 $("div.output_subarea.raw_input_container").remove();
664 668
665 669 area.append(
666 670 $("<div/>")
667 671 .addClass("box-flex1 output_subarea raw_input_container")
668 672 .append(
669 673 $("<span/>")
670 674 .addClass("raw_input_prompt")
671 675 .text(content.prompt)
672 676 )
673 677 .append(
674 678 $("<input/>")
675 679 .addClass("raw_input")
676 680 .attr('type', 'text')
677 681 .attr("size", 47)
678 682 .keydown(function (event, ui) {
679 683 // make sure we submit on enter,
680 684 // and don't re-execute the *cell* on shift-enter
681 685 if (event.which === IPython.keyboard.keycodes.enter) {
682 686 that._submit_raw_input();
683 687 return false;
684 688 }
685 689 })
686 690 )
687 691 );
688 692
689 693 this.element.append(area);
690 694 var raw_input = area.find('input.raw_input');
691 695 // Register events that enable/disable the keyboard manager while raw
692 696 // input is focused.
693 697 IPython.keyboard_manager.register_events(raw_input);
694 698 // Note, the following line used to read raw_input.focus().focus().
695 699 // This seemed to be needed otherwise only the cell would be focused.
696 700 // But with the modal UI, this seems to work fine with one call to focus().
697 701 raw_input.focus();
698 702 }
699 703
700 704 OutputArea.prototype._submit_raw_input = function (evt) {
701 705 var container = this.element.find("div.raw_input_container");
702 706 var theprompt = container.find("span.raw_input_prompt");
703 707 var theinput = container.find("input.raw_input");
704 708 var value = theinput.val();
705 709 var content = {
706 710 output_type : 'stream',
707 711 name : 'stdout',
708 712 text : theprompt.text() + value + '\n'
709 713 }
710 714 // remove form container
711 715 container.parent().remove();
712 716 // replace with plaintext version in stdout
713 717 this.append_output(content, false);
714 718 $([IPython.events]).trigger('send_input_reply.Kernel', value);
715 719 }
716 720
717 721
718 722 OutputArea.prototype.handle_clear_output = function (msg) {
719 723 // msg spec v4 had stdout, stderr, display keys
720 724 // v4.1 replaced these with just wait
721 725 // The default behavior is the same (stdout=stderr=display=True, wait=False),
722 726 // so v4 messages will still be properly handled,
723 727 // except for the rarely used clearing less than all output.
724 728 this.clear_output(msg.content.wait || false);
725 729 };
726 730
727 731
728 732 OutputArea.prototype.clear_output = function(wait) {
729 733 if (wait) {
730 734
731 735 // If a clear is queued, clear before adding another to the queue.
732 736 if (this.clear_queued) {
733 737 this.clear_output(false);
734 738 };
735 739
736 740 this.clear_queued = true;
737 741 } else {
738 742
739 743 // Fix the output div's height if the clear_output is waiting for
740 744 // new output (it is being used in an animation).
741 745 if (this.clear_queued) {
742 746 var height = this.element.height();
743 747 this.element.height(height);
744 748 this.clear_queued = false;
745 749 }
746 750
747 751 // clear all, no need for logic
748 752 this.element.html("");
749 753 this.outputs = [];
750 754 this.trusted = true;
751 755 this.unscroll_area();
752 756 return;
753 757 };
754 758 };
755 759
756 760
757 761 // JSON serialization
758 762
759 763 OutputArea.prototype.fromJSON = function (outputs) {
760 764 var len = outputs.length;
761 765 var data;
762 766
763 767 for (var i=0; i<len; i++) {
764 768 data = outputs[i];
765 769 var msg_type = data.output_type;
766 770 if (msg_type === "display_data" || msg_type === "pyout") {
767 771 // convert short keys to mime keys
768 772 // TODO: remove mapping of short keys when we update to nbformat 4
769 773 data = this.rename_keys(data, OutputArea.mime_map_r);
770 774 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
771 775 }
772 776
773 777 this.append_output(data);
774 778 }
775 779 };
776 780
777 781
778 782 OutputArea.prototype.toJSON = function () {
779 783 var outputs = [];
780 784 var len = this.outputs.length;
781 785 var data;
782 786 for (var i=0; i<len; i++) {
783 787 data = this.outputs[i];
784 788 var msg_type = data.output_type;
785 789 if (msg_type === "display_data" || msg_type === "pyout") {
786 790 // convert mime keys to short keys
787 791 data = this.rename_keys(data, OutputArea.mime_map);
788 792 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
789 793 }
790 794 outputs[i] = data;
791 795 }
792 796 return outputs;
793 797 };
794 798
795 799 /**
796 800 * Class properties
797 801 **/
798 802
799 803 /**
800 804 * Threshold to trigger autoscroll when the OutputArea is resized,
801 805 * typically when new outputs are added.
802 806 *
803 807 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
804 808 * unless it is < 0, in which case autoscroll will never be triggered
805 809 *
806 810 * @property auto_scroll_threshold
807 811 * @type Number
808 812 * @default 100
809 813 *
810 814 **/
811 815 OutputArea.auto_scroll_threshold = 100;
812 816
813 817 /**
814 818 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
815 819 * shorter than this are never scrolled.
816 820 *
817 821 * @property minimum_scroll_threshold
818 822 * @type Number
819 823 * @default 20
820 824 *
821 825 **/
822 826 OutputArea.minimum_scroll_threshold = 20;
823 827
824 828
825 829
826 830 OutputArea.mime_map = {
827 831 "text/plain" : "text",
828 832 "text/html" : "html",
829 833 "image/svg+xml" : "svg",
830 834 "image/png" : "png",
831 835 "image/jpeg" : "jpeg",
832 836 "text/latex" : "latex",
833 837 "application/json" : "json",
834 838 "application/javascript" : "javascript",
835 839 };
836 840
837 841 OutputArea.mime_map_r = {
838 842 "text" : "text/plain",
839 843 "html" : "text/html",
840 844 "svg" : "image/svg+xml",
841 845 "png" : "image/png",
842 846 "jpeg" : "image/jpeg",
843 847 "latex" : "text/latex",
844 848 "json" : "application/json",
845 849 "javascript" : "application/javascript",
846 850 };
847 851
848 852 OutputArea.display_order = [
849 853 'application/javascript',
850 854 'text/html',
851 855 'text/latex',
852 856 'image/svg+xml',
853 857 'image/png',
854 858 'image/jpeg',
855 859 'application/pdf',
856 860 'text/plain'
857 861 ];
858 862
859 863 OutputArea.append_map = {
860 864 "text/plain" : append_text,
861 865 "text/html" : append_html,
862 866 "image/svg+xml" : append_svg,
863 867 "image/png" : append_png,
864 868 "image/jpeg" : append_jpeg,
865 869 "text/latex" : append_latex,
866 870 "application/javascript" : append_javascript,
867 871 "application/pdf" : append_pdf
868 872 };
869 873
870 874 IPython.OutputArea = OutputArea;
871 875
872 876 return IPython;
873 877
874 878 }(IPython));
@@ -1,391 +1,387 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7 //============================================================================
8 8 // Tooltip
9 9 //============================================================================
10 10 //
11 11 // you can set the autocall time by setting `IPython.tooltip.time_before_tooltip` in ms
12 12 //
13 13 // you can configure the differents action of pressing tab several times in a row by
14 14 // setting/appending different fonction in the array
15 15 // IPython.tooltip.tabs_functions
16 16 //
17 17 // eg :
18 18 // IPython.tooltip.tabs_functions[4] = function (){console.log('this is the action of the 4th tab pressing')}
19 19 //
20 20 var IPython = (function (IPython) {
21 21 "use strict";
22 22
23 23 var utils = IPython.utils;
24 24
25 25 // tooltip constructor
26 26 var Tooltip = function () {
27 27 var that = this;
28 28 this.time_before_tooltip = 1200;
29 29
30 30 // handle to html
31 31 this.tooltip = $('#tooltip');
32 32 this._hidden = true;
33 33
34 34 // variable for consecutive call
35 35 this._old_cell = null;
36 36 this._old_request = null;
37 37 this._consecutive_counter = 0;
38 38
39 39 // 'sticky ?'
40 40 this._sticky = false;
41 41
42 42 // display tooltip if the docstring is empty?
43 43 this._hide_if_no_docstring = false;
44 44
45 45 // contain the button in the upper right corner
46 46 this.buttons = $('<div/>').addClass('tooltipbuttons');
47 47
48 48 // will contain the docstring
49 49 this.text = $('<div/>').addClass('tooltiptext').addClass('smalltooltip');
50 50
51 51 // build the buttons menu on the upper right
52 52 // expand the tooltip to see more
53 53 var expandlink = $('<a/>').attr('href', "#").addClass("ui-corner-all") //rounded corner
54 54 .attr('role', "button").attr('id', 'expanbutton').attr('title', 'Grow the tooltip vertically (press tab 2 times)').click(function () {
55 55 that.expand();
56 56 }).append(
57 57 $('<span/>').text('Expand').addClass('ui-icon').addClass('ui-icon-plus'));
58 58
59 59 // open in pager
60 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 61 var morespan = $('<span/>').text('Open in Pager').addClass('ui-icon').addClass('ui-icon-arrowstop-l-n');
62 62 morelink.append(morespan);
63 63 morelink.click(function () {
64 64 that.showInPager(that._old_cell);
65 65 });
66 66
67 67 // close the tooltip
68 68 var closelink = $('<a/>').attr('href', "#").attr('role', "button").addClass('ui-button');
69 69 var closespan = $('<span/>').text('Close').addClass('ui-icon').addClass('ui-icon-close');
70 70 closelink.append(closespan);
71 71 closelink.click(function () {
72 72 that.remove_and_cancel_tooltip(true);
73 73 });
74 74
75 75 this._clocklink = $('<a/>').attr('href', "#");
76 76 this._clocklink.attr('role', "button");
77 77 this._clocklink.addClass('ui-button');
78 78 this._clocklink.attr('title', 'Tootip is not dismissed while typing for 10 seconds');
79 79 var clockspan = $('<span/>').text('Close');
80 80 clockspan.addClass('ui-icon');
81 81 clockspan.addClass('ui-icon-clock');
82 82 this._clocklink.append(clockspan);
83 83 this._clocklink.click(function () {
84 84 that.cancel_stick();
85 85 });
86 86
87 87
88 88
89 89
90 90 //construct the tooltip
91 91 // add in the reverse order you want them to appear
92 92 this.buttons.append(closelink);
93 93 this.buttons.append(expandlink);
94 94 this.buttons.append(morelink);
95 95 this.buttons.append(this._clocklink);
96 96 this._clocklink.hide();
97 97
98 98
99 99 // we need a phony element to make the small arrow
100 100 // of the tooltip in css
101 101 // we will move the arrow later
102 102 this.arrow = $('<div/>').addClass('pretooltiparrow');
103 103 this.tooltip.append(this.buttons);
104 104 this.tooltip.append(this.arrow);
105 105 this.tooltip.append(this.text);
106 106
107 107 // function that will be called if you press tab 1, 2, 3... times in a row
108 108 this.tabs_functions = [function (cell, text) {
109 109 that._request_tooltip(cell, text);
110 110 }, function () {
111 111 that.expand();
112 112 }, function () {
113 113 that.stick();
114 114 }, function (cell) {
115 115 that.cancel_stick();
116 116 that.showInPager(cell);
117 117 }];
118 118 // call after all the tabs function above have bee call to clean their effects
119 119 // if necessary
120 120 this.reset_tabs_function = function (cell, text) {
121 121 this._old_cell = (cell) ? cell : null;
122 122 this._old_request = (text) ? text : null;
123 123 this._consecutive_counter = 0;
124 124 };
125 125 };
126 126
127 127 Tooltip.prototype.is_visible = function () {
128 128 return !this._hidden;
129 129 };
130 130
131 131 Tooltip.prototype.showInPager = function (cell) {
132 132 // reexecute last call in pager by appending ? to show back in pager
133 133 var that = this;
134 var empty = function () {};
135 cell.kernel.execute(
136 that.name + '?', {
137 'execute_reply': empty,
138 'output': empty,
139 'clear_output': empty,
140 'cell': cell
141 }, {
142 'silent': false,
143 'store_history': true
144 });
134 var callbacks = {'shell' : {
135 'payload' : {
136 'page' : $.proxy(cell._open_with_pager, cell)
137 }
138 }
139 };
140 cell.kernel.execute(that.name + '?', callbacks, {'silent': false, 'store_history': true});
145 141 this.remove_and_cancel_tooltip();
146 142 };
147 143
148 144 // grow the tooltip verticaly
149 145 Tooltip.prototype.expand = function () {
150 146 this.text.removeClass('smalltooltip');
151 147 this.text.addClass('bigtooltip');
152 148 $('#expanbutton').hide('slow');
153 149 };
154 150
155 151 // deal with all the logic of hiding the tooltip
156 152 // and reset it's status
157 153 Tooltip.prototype._hide = function () {
158 154 this._hidden = true;
159 155 this.tooltip.fadeOut('fast');
160 156 $('#expanbutton').show('slow');
161 157 this.text.removeClass('bigtooltip');
162 158 this.text.addClass('smalltooltip');
163 159 // keep scroll top to be sure to always see the first line
164 160 this.text.scrollTop(0);
165 161 this.code_mirror = null;
166 162 };
167 163
168 164 // return true on successfully removing a visible tooltip; otherwise return
169 165 // false.
170 166 Tooltip.prototype.remove_and_cancel_tooltip = function (force) {
171 167 // note that we don't handle closing directly inside the calltip
172 168 // as in the completer, because it is not focusable, so won't
173 169 // get the event.
174 170 this.cancel_pending();
175 171 if (!this._hidden) {
176 172 if (force || !this._sticky) {
177 173 this.cancel_stick();
178 174 this._hide();
179 175 }
180 176 this.reset_tabs_function();
181 177 return true;
182 178 } else {
183 179 return false;
184 180 }
185 181 };
186 182
187 183 // cancel autocall done after '(' for example.
188 184 Tooltip.prototype.cancel_pending = function () {
189 185 if (this._tooltip_timeout !== null) {
190 186 clearTimeout(this._tooltip_timeout);
191 187 this._tooltip_timeout = null;
192 188 }
193 189 };
194 190
195 191 // will trigger tooltip after timeout
196 192 Tooltip.prototype.pending = function (cell, hide_if_no_docstring) {
197 193 var that = this;
198 194 this._tooltip_timeout = setTimeout(function () {
199 195 that.request(cell, hide_if_no_docstring);
200 196 }, that.time_before_tooltip);
201 197 };
202 198
203 199 // easy access for julia monkey patching.
204 200 Tooltip.last_token_re = /[a-z_][0-9a-z._]*$/gi;
205 201
206 202 Tooltip.prototype.extract_oir_token = function(line){
207 203 // use internally just to make the request to the kernel
208 204 // Feel free to shorten this logic if you are better
209 205 // than me in regEx
210 206 // basicaly you shoul be able to get xxx.xxx.xxx from
211 207 // something(range(10), kwarg=smth) ; xxx.xxx.xxx( firstarg, rand(234,23), kwarg1=2,
212 208 // remove everything between matchin bracket (need to iterate)
213 209 var matchBracket = /\([^\(\)]+\)/g;
214 210 var endBracket = /\([^\(]*$/g;
215 211 var oldline = line;
216 212
217 213 line = line.replace(matchBracket, "");
218 214 while (oldline != line) {
219 215 oldline = line;
220 216 line = line.replace(matchBracket, "");
221 217 }
222 218 // remove everything after last open bracket
223 219 line = line.replace(endBracket, "");
224 220 // reset the regex object
225 221 Tooltip.last_token_re.lastIndex = 0;
226 222 return Tooltip.last_token_re.exec(line);
227 223 };
228 224
229 225 Tooltip.prototype._request_tooltip = function (cell, line) {
230 226 var callbacks = $.proxy(this._show, this);
231 227 var oir_token = this.extract_oir_token(line);
232 228 var msg_id = cell.kernel.object_info(oir_token, callbacks);
233 229 };
234 230
235 231 // make an imediate completion request
236 232 Tooltip.prototype.request = function (cell, hide_if_no_docstring) {
237 233 // request(codecell)
238 234 // Deal with extracting the text from the cell and counting
239 235 // call in a row
240 236 this.cancel_pending();
241 237 var editor = cell.code_mirror;
242 238 var cursor = editor.getCursor();
243 239 var text = editor.getRange({
244 240 line: cursor.line,
245 241 ch: 0
246 242 }, cursor).trim();
247 243
248 244 this._hide_if_no_docstring = hide_if_no_docstring;
249 245
250 246 if(editor.somethingSelected()){
251 247 text = editor.getSelection();
252 248 }
253 249
254 250 // need a permanent handel to code_mirror for future auto recall
255 251 this.code_mirror = editor;
256 252
257 253 // now we treat the different number of keypress
258 254 // first if same cell, same text, increment counter by 1
259 255 if (this._old_cell == cell && this._old_request == text && this._hidden === false) {
260 256 this._consecutive_counter++;
261 257 } else {
262 258 // else reset
263 259 this.cancel_stick();
264 260 this.reset_tabs_function (cell, text);
265 261 }
266 262
267 263 // don't do anything if line beggin with '(' or is empty
268 264 if (text === "" || text === "(") {
269 265 return;
270 266 }
271 267
272 268 this.tabs_functions[this._consecutive_counter](cell, text);
273 269
274 270 // then if we are at the end of list function, reset
275 271 if (this._consecutive_counter == this.tabs_functions.length) {
276 272 this.reset_tabs_function (cell, text);
277 273 }
278 274
279 275 return;
280 276 };
281 277
282 278 // cancel the option of having the tooltip to stick
283 279 Tooltip.prototype.cancel_stick = function () {
284 280 clearTimeout(this._stick_timeout);
285 281 this._stick_timeout = null;
286 282 this._clocklink.hide('slow');
287 283 this._sticky = false;
288 284 };
289 285
290 286 // put the tooltip in a sicky state for 10 seconds
291 287 // it won't be removed by remove_and_cancell() unless you called with
292 288 // the first parameter set to true.
293 289 // remove_and_cancell_tooltip(true)
294 290 Tooltip.prototype.stick = function (time) {
295 291 time = (time !== undefined) ? time : 10;
296 292 var that = this;
297 293 this._sticky = true;
298 294 this._clocklink.show('slow');
299 295 this._stick_timeout = setTimeout(function () {
300 296 that._sticky = false;
301 297 that._clocklink.hide('slow');
302 298 }, time * 1000);
303 299 };
304 300
305 301 // should be called with the kernel reply to actually show the tooltip
306 302 Tooltip.prototype._show = function (reply) {
307 303 // move the bubble if it is not hidden
308 304 // otherwise fade it
309 305 var content = reply.content;
310 306 if (!content.found) {
311 307 // object not found, nothing to show
312 308 return;
313 309 }
314 310 this.name = content.name;
315 311
316 312 // do some math to have the tooltip arrow on more or less on left or right
317 313 // width of the editor
318 314 var w = $(this.code_mirror.getScrollerElement()).width();
319 315 // ofset of the editor
320 316 var o = $(this.code_mirror.getScrollerElement()).offset();
321 317
322 318 // whatever anchor/head order but arrow at mid x selection
323 319 var anchor = this.code_mirror.cursorCoords(false);
324 320 var head = this.code_mirror.cursorCoords(true);
325 321 var xinit = (head.left+anchor.left)/2;
326 322 var xinter = o.left + (xinit - o.left) / w * (w - 450);
327 323 var posarrowleft = xinit - xinter;
328 324
329 325 if (this._hidden === false) {
330 326 this.tooltip.animate({
331 327 'left': xinter - 30 + 'px',
332 328 'top': (head.bottom + 10) + 'px'
333 329 });
334 330 } else {
335 331 this.tooltip.css({
336 332 'left': xinter - 30 + 'px'
337 333 });
338 334 this.tooltip.css({
339 335 'top': (head.bottom + 10) + 'px'
340 336 });
341 337 }
342 338 this.arrow.animate({
343 339 'left': posarrowleft + 'px'
344 340 });
345 341
346 342 // build docstring
347 343 var defstring = content.call_def;
348 344 if (!defstring) {
349 345 defstring = content.init_definition;
350 346 }
351 347 if (!defstring) {
352 348 defstring = content.definition;
353 349 }
354 350
355 351 var docstring = content.call_docstring;
356 352 if (!docstring) {
357 353 docstring = content.init_docstring;
358 354 }
359 355 if (!docstring) {
360 356 docstring = content.docstring;
361 357 }
362 358
363 359 if (!docstring) {
364 360 // For reals this time, no docstring
365 361 if (this._hide_if_no_docstring) {
366 362 return;
367 363 } else {
368 364 docstring = "<empty docstring>";
369 365 }
370 366 }
371 367
372 368 this._hidden = false;
373 369 this.tooltip.fadeIn('fast');
374 370 this.text.children().remove();
375 371
376 372 // Any HTML within the docstring is escaped by the fixConsole() method.
377 373 var pre = $('<pre/>').html(utils.fixConsole(docstring));
378 374 if (defstring) {
379 375 var defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
380 376 this.text.append(defstring_html);
381 377 }
382 378 this.text.append(pre);
383 379 // keep scroll top to be sure to always see the first line
384 380 this.text.scrollTop(0);
385 381 };
386 382
387 383 IPython.Tooltip = Tooltip;
388 384
389 385 return IPython;
390 386
391 387 }(IPython));
@@ -1,54 +1,62 b''
1 1 div.cell {
2 2 border: 1px solid transparent;
3 3 .vbox();
4 4
5 5 &.selected {
6 6 .corner-all;
7 7 border : thin @border_color solid;
8 8 }
9 9
10 10 &.edit_mode {
11 11 .corner-all;
12 12 border : thin green solid;
13 13 }
14 14 }
15 15
16 16 div.cell {
17 17 width: 100%;
18 18 padding: 5px 5px 5px 0px;
19 19 /* This acts as a spacer between cells, that is outside the border */
20 20 margin: 0px;
21 21 outline: none;
22 22 }
23 23
24 24 div.prompt {
25 25 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
26 26 min-width: 11ex;
27 27 /* This padding is tuned to match the padding on the CodeMirror editor. */
28 28 padding: @code_padding;
29 29 margin: 0px;
30 30 font-family: @monoFontFamily;
31 31 text-align: right;
32 32 /* This has to match that of the the CodeMirror class line-height below */
33 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 44 div.inner_cell {
37 45 .vbox();
38 46 .box-flex1();
39 47 }
40 48
41 49 /* input_area and input_prompt must match in top border and margin for alignment */
42 50 div.input_area {
43 51 border: 1px solid @light_border_color;
44 52 .corner-all;
45 53 background: @cell_background;
46 54 }
47 55
48 56 /* This is needed so that empty prompt areas can collapse to zero height when there
49 57 is no content in the output_subarea and the prompt. The main purpose of this is
50 58 to make sure that empty JavaScript output_subareas have no height. */
51 59 div.prompt:empty {
52 60 padding-top: 0;
53 61 padding-bottom: 0;
54 62 }
@@ -1,40 +1,46 b''
1 1 div.code_cell {
2 2 }
3 3
4 4 /* any special styling for code cells that are currently running goes here */
5 5 div.code_cell.running {
6 6 }
7 7
8 8 div.input {
9 9 page-break-inside: avoid;
10 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 20 /* input_area and input_prompt must match in top border and margin for alignment */
14 21 div.input_prompt {
15 22 color: navy;
16 23 border-top: 1px solid transparent;
17 24 }
18 25
19
20 26 // The styles related to div.highlight are for nbconvert HTML output only. This works
21 27 // because the .highlight div isn't present in the live notebook. We could put this into
22 28 // nbconvert, but it easily falls out of sync, can't use our less variables and doesn't
23 29 // help the basic template when paired with our CSS.
24 30
25 31 div.input_area > div.highlight {
26 32 margin: @code_padding;
27 33 border: none;
28 34 padding: 0px;
29 35 background-color: transparent;
30 36 }
31 37
32 38 div.input_area > div.highlight > pre {
33 39 margin: 0px;
34 40 border: 0px;
35 41 padding: 0px;
36 42 background-color: transparent;
37 43 font-size: @notebook_font_size;
38 44 line-height: @code_line_height;
39 45 }
40 46
@@ -1,69 +1,77 b''
1 1
2 2 body {
3 3 background-color: @bodyBackground;
4 4 }
5 5
6 6 body.notebook_app {
7 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 18 span#notebook_name {
11 19 height: 1em;
12 20 line-height: 1em;
13 21 padding: 3px;
14 22 border: none;
15 23 font-size: 146.5%;
16 24 }
17 25
18 26 div#notebook_panel {
19 27 margin: 0px 0px 0px 0px;
20 28 padding: 0px;
21 29 .box-shadow(0 -1px 10px rgba(0,0,0,.1));
22 30 }
23 31 div#notebook {
24 32 font-size: @notebook_font_size;
25 33 line-height: @notebook_line_height;
26 34 overflow-y: scroll;
27 35 overflow-x: auto;
28 36 width: 100%;
29 37 /* This spaces the cell away from the edge of the notebook area */
30 38 padding: 1em 0 1em 0;
31 39 margin: 0px;
32 40 border-top: 1px solid @border_color;
33 41 outline: none;
34 42 .border-box-sizing();
35 43 }
36 44
37 45 div.ui-widget-content {
38 46 border: 1px solid @border_color;
39 47 outline: none;
40 48 }
41 49
42 50 pre.dialog {
43 51 background-color: @cell_background;
44 52 border: 1px solid #ddd;
45 53 .corner-all;
46 54 padding: 0.4em;
47 55 padding-left: 2em;
48 56 }
49 57
50 58 p.dialog {
51 59 padding : 0.2em;
52 60 }
53 61
54 62 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
55 63 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
56 64 */
57 65 pre, code, kbd, samp { white-space: pre-wrap; }
58 66
59 67 #fonttest {
60 68 font-family: @monoFontFamily;
61 69 }
62 70
63 71 p {
64 72 margin-bottom:0;
65 73 }
66 74
67 75 .end_space {
68 76 height: 200px;
69 77 }
@@ -1,169 +1,176 b''
1 1 div.output_wrapper {
2 2 /* this position must be relative to enable descendents to be absolute within it */
3 3 position: relative;
4 4 .vbox()
5 5 }
6 6
7 7 /* class for the output area when it should be height-limited */
8 8 div.output_scroll {
9 9 /* ideally, this would be max-height, but FF barfs all over that */
10 10 height: 24em;
11 11 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
12 12 width: 100%;
13 13
14 14 overflow: auto;
15 15 .corner-all;
16 16 .box-shadow(inset 0 2px 8px rgba(0, 0, 0, .8));
17 17 display: block;
18 18 }
19 19
20 20 /* output div while it is collapsed */
21 21 div.output_collapsed {
22 22 margin: 0px;
23 23 padding: 0px;
24 24 .vbox();
25 25 }
26 26
27 27 div.out_prompt_overlay {
28 28 height: 100%;
29 29 padding: 0px @code_padding;
30 30 position: absolute;
31 31 .corner-all;
32 32 }
33 33
34 34 div.out_prompt_overlay:hover {
35 35 /* use inner shadow to get border that is computed the same on WebKit/FF */
36 36 .box-shadow(inset 0 0 1px #000);
37 37 background: rgba(240, 240, 240, 0.5);
38 38 }
39 39
40 40 div.output_prompt {
41 41 color: darkred;
42 42 }
43 43
44 44 /* This class is the outer container of all output sections. */
45 45 div.output_area {
46 46 padding: 0px;
47 47 page-break-inside: avoid;
48 48 .hbox();
49 49
50 50 .MathJax_Display {
51 51 // Inside a CodeCell, elements are left justified
52 52 text-align: left !important;
53 53 }
54 54
55 55 .rendered_html {
56 56 // Inside a CodeCell, elements are left justified
57 57 table {
58 58 margin-left: 0;
59 59 margin-right: 0;
60 60 }
61 61
62 62 img {
63 63 margin-left: 0;
64 64 margin-right: 0;
65 65 }
66 66 }
67 67 }
68 68
69 69 /* This is needed to protect the pre formating from global settings such
70 70 as that of bootstrap */
71 71 .output {
72 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 82 div.output_area pre {
76 83 margin: 0;
77 84 padding: 0;
78 85 border: 0;
79 86 font-size: 100%;
80 87 vertical-align: baseline;
81 88 color: black;
82 89 background-color: transparent;
83 90 .border-radius(0);
84 91 line-height: inherit;
85 92 }
86 93
87 94 /* This class is for the output subarea inside the output_area and after
88 95 the prompt div. */
89 96 div.output_subarea {
90 97 padding: @code_padding @code_padding 0.0em @code_padding;
91 98 .box-flex1();
92 99 }
93 100
94 101 /* The rest of the output_* classes are for special styling of the different
95 102 output types */
96 103
97 104 /* all text output has this class: */
98 105 div.output_text {
99 106 text-align: left;
100 107 color: @textColor;
101 108 /* This has to match that of the the CodeMirror class line-height below */
102 109 line-height: @code_line_height;
103 110 }
104 111
105 112 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
106 113 div.output_stream {
107 114 }
108 115
109 116 div.output_stdout {
110 117 }
111 118
112 119 div.output_stderr {
113 120 background: #fdd; /* very light red background for stderr */
114 121 }
115 122
116 123 div.output_latex {
117 124 text-align: left;
118 125 }
119 126
120 127 div.output_html {
121 128 }
122 129
123 130 div.output_png {
124 131 }
125 132
126 133 div.output_jpeg {
127 134 }
128 135
129 136 /* Empty output_javascript divs should have no height */
130 137 div.output_javascript:empty {
131 138 padding: 0;
132 139 }
133 140
134 141 .js-error {
135 142 color: darkred;
136 143 }
137 144
138 145 /* raw_input styles */
139 146
140 147 div.raw_input_container {
141 148 font-family: @monoFontFamily;
142 149 // for some reason, em padding doesn't compute the same for raw_input
143 150 // that is not the first input, but px does
144 151 padding-top: 5px;
145 152 }
146 153
147 154 span.raw_input_prompt {
148 155 /* nothing needed here */
149 156 }
150 157
151 158 input.raw_input {
152 159 font-family: inherit;
153 160 font-size: inherit;
154 161 color: inherit;
155 162 width: auto;
156 163 /* make sure input baseline aligns with prompt */
157 164 vertical-align: baseline;
158 165 /* padding + margin = 0.5em between prompt and cursor */
159 166 padding: 0em 0.25em;
160 167 margin: 0em 0.25em;
161 168 }
162 169
163 170 input.raw_input:focus {
164 171 box-shadow: none;
165 172 }
166 173
167 174 p.p-space {
168 175 margin-bottom: 10px;
169 176 }
@@ -1,30 +1,36 b''
1 1 div.text_cell {
2 2 padding: 5px 5px 5px 0px;
3 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 12 div.text_cell_render {
7 13 /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
8 14 outline: none;
9 15 resize: none;
10 16 width: inherit;
11 17 border-style: none;
12 18 padding: 0.5em 0.5em 0.5em @code_padding;
13 19 color: @textColor;
14 20 }
15 21
16 22 a.anchor-link:link {
17 23 text-decoration: none;
18 24 padding: 0px 20px;
19 25 visibility: hidden;
20 26 }
21 27
22 28 h1,h2,h3,h4,h5,h6 {
23 29 &:hover .anchor-link {
24 30 visibility: visible;
25 31 }
26 32 }
27 33
28 34 div.cell.text_cell.rendered {
29 35 padding: 0px;
30 36 }
@@ -1,199 +1,199 b''
1 1 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
2 2 .clearfix:after{clear:both}
3 3 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
4 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 5 code{color:#000}
6 6 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
7 7 .corner-all{border-radius:4px}
8 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 9 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
10 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 11 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
12 12 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
13 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 14 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
15 15 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
16 16 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
17 17 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
18 18 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
19 19 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
20 20 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
21 21 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
22 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 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 24 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
25 25 div.error{margin:2em;text-align:center}
26 26 div.error>h1{font-size:500%;line-height:normal}
27 27 div.error>p{font-size:200%;line-height:normal}
28 28 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
29 29 .center-nav{display:inline-block;margin-bottom:-4px}
30 30 .alternate_upload{background-color:none;display:inline}
31 31 .alternate_upload.form{padding:0;margin:0}
32 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 33 ul#tabs{margin-bottom:4px}
34 34 ul#tabs a{padding-top:4px;padding-bottom:4px}
35 35 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
36 36 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
37 37 ul.breadcrumb span{color:#5e5e5e}
38 38 .list_toolbar{padding:4px 0 4px 0}
39 39 .list_toolbar [class*="span"]{min-height:26px}
40 40 .list_header{font-weight:bold}
41 41 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
42 42 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
43 43 .list_container>div:last-child{border:none}
44 44 .list_item:hover .list_item{background-color:#ddd}
45 45 .list_item a{text-decoration:none}
46 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 47 .item_name{line-height:22px;height:26px}
48 48 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
49 49 .item_buttons{line-height:1em}
50 50 .toolbar_info{height:26px;line-height:26px}
51 51 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
52 52 input.engine_num_input{width:60px}
53 53 .highlight_text{color:#00f}
54 54 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
55 55 .ansibold{font-weight:bold}
56 56 .ansiblack{color:#000}
57 57 .ansired{color:#8b0000}
58 58 .ansigreen{color:#006400}
59 59 .ansiyellow{color:#a52a2a}
60 60 .ansiblue{color:#00008b}
61 61 .ansipurple{color:#9400d3}
62 62 .ansicyan{color:#4682b4}
63 63 .ansigray{color:#808080}
64 64 .ansibgblack{background-color:#000}
65 65 .ansibgred{background-color:#f00}
66 66 .ansibggreen{background-color:#008000}
67 67 .ansibgyellow{background-color:#ff0}
68 68 .ansibgblue{background-color:#00f}
69 69 .ansibgpurple{background-color:#f0f}
70 70 .ansibgcyan{background-color:#0ff}
71 71 .ansibggray{background-color:#808080}
72 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 73 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
74 74 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
75 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 77 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
78 78 div.prompt:empty{padding-top:0;padding-bottom:0}
79 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 81 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
82 82 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
83 83 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
84 84 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
85 85 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
86 86 .CodeMirror-linenumber{padding:0 8px 0 4px}
87 87 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
88 88 .CodeMirror pre{padding:0;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
89 89 pre code{display:block;padding:.5em}
90 90 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
91 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 92 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
93 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 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 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 96 .highlight-builtin,pre .built_in{color:#008000}
97 97 pre .markdown .emphasis{font-style:italic}
98 98 pre .nginx .built_in{font-weight:normal}
99 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 100 .cm-s-ipython span.cm-variable{color:#000}
101 101 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
102 102 .cm-s-ipython span.cm-number{color:#080}
103 103 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
104 104 .cm-s-ipython span.cm-string{color:#ba2121}
105 105 .cm-s-ipython span.cm-builtin{color:#008000}
106 106 .cm-s-ipython span.cm-error{color:#f00}
107 107 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
108 108 .cm-s-ipython span.cm-meta{color:#a2f}
109 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 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 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 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 113 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
114 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 115 div.output_prompt{color:#8b0000}
116 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 117 div.output_area .rendered_html table{margin-left:0;margin-right:0}
118 118 div.output_area .rendered_html img{margin-left:0;margin-right:0}
119 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 121 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
122 122 div.output_text{text-align:left;color:#000;line-height:1.21429em}
123 123 div.output_stderr{background:#fdd;}
124 124 div.output_latex{text-align:left}
125 125 div.output_javascript:empty{padding:0}
126 126 .js-error{color:#8b0000}
127 127 div.raw_input_container{font-family:monospace;padding-top:5px}
128 128 span.raw_input_prompt{}
129 129 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
130 130 input.raw_input:focus{box-shadow:none}
131 131 p.p-space{margin-bottom:10px}
132 132 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
133 133 .rendered_html strong{font-weight:bold}
134 134 .rendered_html u{text-decoration:underline}
135 135 .rendered_html :link{text-decoration:underline}
136 136 .rendered_html :visited{text-decoration:underline}
137 137 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
138 138 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
139 139 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
140 140 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
141 141 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
142 142 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
143 143 .rendered_html h1:first-child{margin-top:.538em}
144 144 .rendered_html h2:first-child{margin-top:.636em}
145 145 .rendered_html h3:first-child{margin-top:.777em}
146 146 .rendered_html h4:first-child{margin-top:1em}
147 147 .rendered_html h5:first-child{margin-top:1em}
148 148 .rendered_html h6:first-child{margin-top:1em}
149 149 .rendered_html ul{list-style:disc;margin:0 2em}
150 150 .rendered_html ul ul{list-style:square;margin:0 2em}
151 151 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
152 152 .rendered_html ol{list-style:decimal;margin:0 2em}
153 153 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
154 154 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
155 155 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
156 156 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
157 157 .rendered_html *+ul{margin-top:1em}
158 158 .rendered_html *+ol{margin-top:1em}
159 159 .rendered_html hr{color:#000;background-color:#000}
160 160 .rendered_html pre{margin:1em 2em}
161 161 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
162 162 .rendered_html blockquote{margin:1em 2em}
163 163 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
164 164 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
165 165 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
166 166 .rendered_html th{font-weight:bold}
167 167 .rendered_html *+table{margin-top:1em}
168 168 .rendered_html p{text-align:justify}
169 169 .rendered_html *+p{margin-top:1em}
170 170 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
171 171 .rendered_html *+img{margin-top:1em}
172 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 174 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
175 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 176 div.cell.text_cell.rendered{padding:0}
177 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 178 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
179 179 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
180 180 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
181 181 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
182 182 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
183 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 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 185 .widget-text{width:350px;margin:0 !important}
186 186 .widget-listbox{width:364px;margin-bottom:0}
187 187 .widget-numeric-text{width:150px;margin:0 !important}
188 188 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
189 189 .widget-combo-btn{min-width:138px;}
190 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 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 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 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 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 195 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
196 196 .widget-modal-body{max-height:none !important}
197 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 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 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 1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
2 2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
3 3 audio:not([controls]){display:none}
4 4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
5 5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
6 6 a:hover,a:active{outline:0}
7 7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}
8 8 sup{top:-0.5em}
9 9 sub{bottom:-0.25em}
10 10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}
11 11 #map_canvas img,.google-maps img{max-width:none}
12 12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}
13 13 button,input{*overflow:visible;line-height:normal}
14 14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
15 15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
16 16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}
17 17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}
18 18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
19 19 textarea{overflow:auto;vertical-align:top}
20 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 21 a{color:#08c;text-decoration:none}
22 22 a:hover,a:focus{color:#005580;text-decoration:underline}
23 23 .img-rounded{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
24 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 25 .img-circle{border-radius:500px;-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}
26 26 .row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0}
27 27 .row:after{clear:both}
28 28 [class*="span"]{float:left;min-height:1px;margin-left:20px}
29 29 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
30 30 .span12{width:940px}
31 31 .span11{width:860px}
32 32 .span10{width:780px}
33 33 .span9{width:700px}
34 34 .span8{width:620px}
35 35 .span7{width:540px}
36 36 .span6{width:460px}
37 37 .span5{width:380px}
38 38 .span4{width:300px}
39 39 .span3{width:220px}
40 40 .span2{width:140px}
41 41 .span1{width:60px}
42 42 .offset12{margin-left:980px}
43 43 .offset11{margin-left:900px}
44 44 .offset10{margin-left:820px}
45 45 .offset9{margin-left:740px}
46 46 .offset8{margin-left:660px}
47 47 .offset7{margin-left:580px}
48 48 .offset6{margin-left:500px}
49 49 .offset5{margin-left:420px}
50 50 .offset4{margin-left:340px}
51 51 .offset3{margin-left:260px}
52 52 .offset2{margin-left:180px}
53 53 .offset1{margin-left:100px}
54 54 .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0}
55 55 .row-fluid:after{clear:both}
56 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 57 .row-fluid [class*="span"]:first-child{margin-left:0}
58 58 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}
59 59 .row-fluid .span12{width:100%;*width:99.94680851063829%}
60 60 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}
61 61 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}
62 62 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}
63 63 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}
64 64 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}
65 65 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}
66 66 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}
67 67 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}
68 68 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}
69 69 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}
70 70 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}
71 71 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}
72 72 .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}
73 73 .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}
74 74 .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}
75 75 .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}
76 76 .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}
77 77 .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}
78 78 .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}
79 79 .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}
80 80 .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}
81 81 .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}
82 82 .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}
83 83 .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}
84 84 .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}
85 85 .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}
86 86 .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}
87 87 .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}
88 88 .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}
89 89 .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}
90 90 .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}
91 91 .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}
92 92 .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}
93 93 .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}
94 94 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}
95 95 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none}
96 96 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}
97 97 .container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:"";line-height:0}
98 98 .container:after{clear:both}
99 99 .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0}
100 100 .container-fluid:after{clear:both}
101 101 p{margin:0 0 10px}
102 102 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px}
103 103 small{font-size:85%}
104 104 strong{font-weight:bold}
105 105 em{font-style:italic}
106 106 cite{font-style:normal}
107 107 .muted{color:#999}
108 108 a.muted:hover,a.muted:focus{color:#808080}
109 109 .text-warning{color:#c09853}
110 110 a.text-warning:hover,a.text-warning:focus{color:#a47e3c}
111 111 .text-error{color:#b94a48}
112 112 a.text-error:hover,a.text-error:focus{color:#953b39}
113 113 .text-info{color:#3a87ad}
114 114 a.text-info:hover,a.text-info:focus{color:#2d6987}
115 115 .text-success{color:#468847}
116 116 a.text-success:hover,a.text-success:focus{color:#356635}
117 117 .text-left{text-align:left}
118 118 .text-right{text-align:right}
119 119 .text-center{text-align:center}
120 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 121 h1,h2,h3{line-height:40px}
122 122 h1{font-size:35.75px}
123 123 h2{font-size:29.25px}
124 124 h3{font-size:22.75px}
125 125 h4{font-size:16.25px}
126 126 h5{font-size:13px}
127 127 h6{font-size:11.049999999999999px}
128 128 h1 small{font-size:22.75px}
129 129 h2 small{font-size:16.25px}
130 130 h3 small{font-size:13px}
131 131 h4 small{font-size:13px}
132 132 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}
133 133 ul,ol{padding:0;margin:0 0 10px 25px}
134 134 ul ul,ul ol,ol ol,ol ul{margin-bottom:0}
135 135 li{line-height:20px}
136 136 ul.unstyled,ol.unstyled{margin-left:0;list-style:none}
137 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 138 dl{margin-bottom:20px}
139 139 dt,dd{line-height:20px}
140 140 dt{font-weight:bold}
141 141 dd{margin-left:10px}
142 142 .dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0}
143 143 .dl-horizontal:after{clear:both}
144 144 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
145 145 .dl-horizontal dd{margin-left:180px}
146 146 hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}
147 147 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}
148 148 abbr.initialism{font-size:90%;text-transform:uppercase}
149 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 150 blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}
151 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 152 blockquote.pull-right small:before{content:''}
153 153 blockquote.pull-right small:after{content:'\00A0 \2014'}
154 154 q:before,q:after,blockquote:before,blockquote:after{content:""}
155 155 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}
156 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 157 code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}
158 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 159 pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}
160 160 .pre-scrollable{max-height:340px;overflow-y:scroll}
161 161 form{margin:0 0 20px}
162 162 fieldset{padding:0;margin:0;border:0}
163 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 164 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px}
165 165 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}
166 166 label{display:block;margin-bottom:5px}
167 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 168 input,textarea,.uneditable-input{width:206px}
169 169 textarea{height:auto}
170 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 171 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal}
172 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 173 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}
174 174 select{width:220px;border:1px solid #ccc;background-color:#fff}
175 175 select[multiple],select[size]{height:auto}
176 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 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 178 .uneditable-input{overflow:hidden;white-space:nowrap}
179 179 .uneditable-textarea{width:auto;height:auto}
180 180 input:-moz-placeholder,textarea:-moz-placeholder{color:#999}
181 181 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}
182 182 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}
183 183 .radio,.checkbox{min-height:20px;padding-left:20px}
184 184 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}
185 185 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}
186 186 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}
187 187 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}
188 188 .input-mini{width:60px}
189 189 .input-small{width:90px}
190 190 .input-medium{width:150px}
191 191 .input-large{width:210px}
192 192 .input-xlarge{width:270px}
193 193 .input-xxlarge{width:530px}
194 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 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 196 input,textarea,.uneditable-input{margin-left:0}
197 197 .controls-row [class*="span"]+[class*="span"]{margin-left:20px}
198 198 input.span12,textarea.span12,.uneditable-input.span12{width:926px}
199 199 input.span11,textarea.span11,.uneditable-input.span11{width:846px}
200 200 input.span10,textarea.span10,.uneditable-input.span10{width:766px}
201 201 input.span9,textarea.span9,.uneditable-input.span9{width:686px}
202 202 input.span8,textarea.span8,.uneditable-input.span8{width:606px}
203 203 input.span7,textarea.span7,.uneditable-input.span7{width:526px}
204 204 input.span6,textarea.span6,.uneditable-input.span6{width:446px}
205 205 input.span5,textarea.span5,.uneditable-input.span5{width:366px}
206 206 input.span4,textarea.span4,.uneditable-input.span4{width:286px}
207 207 input.span3,textarea.span3,.uneditable-input.span3{width:206px}
208 208 input.span2,textarea.span2,.uneditable-input.span2{width:126px}
209 209 input.span1,textarea.span1,.uneditable-input.span1{width:46px}
210 210 .controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0}
211 211 .controls-row:after{clear:both}
212 212 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}
213 213 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}
214 214 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}
215 215 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}
216 216 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}
217 217 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}
218 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 219 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}
220 220 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}
221 221 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}
222 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 223 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}
224 224 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}
225 225 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}
226 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 227 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}
228 228 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}
229 229 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}
230 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 231 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}
232 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 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 234 .form-actions:after{clear:both}
235 235 .help-block,.help-inline{color:#262626}
236 236 .help-block{display:block;margin-bottom:10px}
237 237 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px}
238 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 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 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 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 242 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}
243 243 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px}
244 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 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 246 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}
247 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 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 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 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 251 .input-prepend.input-append .btn-group:first-child{margin-left:0}
252 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 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 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 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 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 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 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 259 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}
260 260 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}
261 261 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}
262 262 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}
263 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 264 .control-group{margin-bottom:10px}
265 265 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}
266 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 267 .form-horizontal .control-group:after{clear:both}
268 268 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}
269 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 270 .form-horizontal .help-block{margin-bottom:0}
271 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 272 .form-horizontal .form-actions{padding-left:180px}
273 273 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}
274 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 275 .table th{font-weight:bold}
276 276 .table thead th{vertical-align:bottom}
277 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 278 .table tbody+tbody{border-top:2px solid #ddd}
279 279 .table .table{background-color:#fff}
280 280 .table-condensed th,.table-condensed td{padding:4px 5px}
281 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 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 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 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 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 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 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 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 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 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 291 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
292 292 .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}
293 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 294 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0}
295 295 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0}
296 296 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0}
297 297 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0}
298 298 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0}
299 299 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0}
300 300 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0}
301 301 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0}
302 302 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0}
303 303 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0}
304 304 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0}
305 305 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0}
306 306 .table tbody tr.success>td{background-color:#dff0d8}
307 307 .table tbody tr.error>td{background-color:#f2dede}
308 308 .table tbody tr.warning>td{background-color:#fcf8e3}
309 309 .table tbody tr.info>td{background-color:#d9edf7}
310 310 .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}
311 311 .table-hover tbody tr.error:hover>td{background-color:#ebcccc}
312 312 .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}
313 313 .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}
314 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 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 316 .icon-glass{background-position:0 0}
317 317 .icon-music{background-position:-24px 0}
318 318 .icon-search{background-position:-48px 0}
319 319 .icon-envelope{background-position:-72px 0}
320 320 .icon-heart{background-position:-96px 0}
321 321 .icon-star{background-position:-120px 0}
322 322 .icon-star-empty{background-position:-144px 0}
323 323 .icon-user{background-position:-168px 0}
324 324 .icon-film{background-position:-192px 0}
325 325 .icon-th-large{background-position:-216px 0}
326 326 .icon-th{background-position:-240px 0}
327 327 .icon-th-list{background-position:-264px 0}
328 328 .icon-ok{background-position:-288px 0}
329 329 .icon-remove{background-position:-312px 0}
330 330 .icon-zoom-in{background-position:-336px 0}
331 331 .icon-zoom-out{background-position:-360px 0}
332 332 .icon-off{background-position:-384px 0}
333 333 .icon-signal{background-position:-408px 0}
334 334 .icon-cog{background-position:-432px 0}
335 335 .icon-trash{background-position:-456px 0}
336 336 .icon-home{background-position:0 -24px}
337 337 .icon-file{background-position:-24px -24px}
338 338 .icon-time{background-position:-48px -24px}
339 339 .icon-road{background-position:-72px -24px}
340 340 .icon-download-alt{background-position:-96px -24px}
341 341 .icon-download{background-position:-120px -24px}
342 342 .icon-upload{background-position:-144px -24px}
343 343 .icon-inbox{background-position:-168px -24px}
344 344 .icon-play-circle{background-position:-192px -24px}
345 345 .icon-repeat{background-position:-216px -24px}
346 346 .icon-refresh{background-position:-240px -24px}
347 347 .icon-list-alt{background-position:-264px -24px}
348 348 .icon-lock{background-position:-287px -24px}
349 349 .icon-flag{background-position:-312px -24px}
350 350 .icon-headphones{background-position:-336px -24px}
351 351 .icon-volume-off{background-position:-360px -24px}
352 352 .icon-volume-down{background-position:-384px -24px}
353 353 .icon-volume-up{background-position:-408px -24px}
354 354 .icon-qrcode{background-position:-432px -24px}
355 355 .icon-barcode{background-position:-456px -24px}
356 356 .icon-tag{background-position:0 -48px}
357 357 .icon-tags{background-position:-25px -48px}
358 358 .icon-book{background-position:-48px -48px}
359 359 .icon-bookmark{background-position:-72px -48px}
360 360 .icon-print{background-position:-96px -48px}
361 361 .icon-camera{background-position:-120px -48px}
362 362 .icon-font{background-position:-144px -48px}
363 363 .icon-bold{background-position:-167px -48px}
364 364 .icon-italic{background-position:-192px -48px}
365 365 .icon-text-height{background-position:-216px -48px}
366 366 .icon-text-width{background-position:-240px -48px}
367 367 .icon-align-left{background-position:-264px -48px}
368 368 .icon-align-center{background-position:-288px -48px}
369 369 .icon-align-right{background-position:-312px -48px}
370 370 .icon-align-justify{background-position:-336px -48px}
371 371 .icon-list{background-position:-360px -48px}
372 372 .icon-indent-left{background-position:-384px -48px}
373 373 .icon-indent-right{background-position:-408px -48px}
374 374 .icon-facetime-video{background-position:-432px -48px}
375 375 .icon-picture{background-position:-456px -48px}
376 376 .icon-pencil{background-position:0 -72px}
377 377 .icon-map-marker{background-position:-24px -72px}
378 378 .icon-adjust{background-position:-48px -72px}
379 379 .icon-tint{background-position:-72px -72px}
380 380 .icon-edit{background-position:-96px -72px}
381 381 .icon-share{background-position:-120px -72px}
382 382 .icon-check{background-position:-144px -72px}
383 383 .icon-move{background-position:-168px -72px}
384 384 .icon-step-backward{background-position:-192px -72px}
385 385 .icon-fast-backward{background-position:-216px -72px}
386 386 .icon-backward{background-position:-240px -72px}
387 387 .icon-play{background-position:-264px -72px}
388 388 .icon-pause{background-position:-288px -72px}
389 389 .icon-stop{background-position:-312px -72px}
390 390 .icon-forward{background-position:-336px -72px}
391 391 .icon-fast-forward{background-position:-360px -72px}
392 392 .icon-step-forward{background-position:-384px -72px}
393 393 .icon-eject{background-position:-408px -72px}
394 394 .icon-chevron-left{background-position:-432px -72px}
395 395 .icon-chevron-right{background-position:-456px -72px}
396 396 .icon-plus-sign{background-position:0 -96px}
397 397 .icon-minus-sign{background-position:-24px -96px}
398 398 .icon-remove-sign{background-position:-48px -96px}
399 399 .icon-ok-sign{background-position:-72px -96px}
400 400 .icon-question-sign{background-position:-96px -96px}
401 401 .icon-info-sign{background-position:-120px -96px}
402 402 .icon-screenshot{background-position:-144px -96px}
403 403 .icon-remove-circle{background-position:-168px -96px}
404 404 .icon-ok-circle{background-position:-192px -96px}
405 405 .icon-ban-circle{background-position:-216px -96px}
406 406 .icon-arrow-left{background-position:-240px -96px}
407 407 .icon-arrow-right{background-position:-264px -96px}
408 408 .icon-arrow-up{background-position:-289px -96px}
409 409 .icon-arrow-down{background-position:-312px -96px}
410 410 .icon-share-alt{background-position:-336px -96px}
411 411 .icon-resize-full{background-position:-360px -96px}
412 412 .icon-resize-small{background-position:-384px -96px}
413 413 .icon-plus{background-position:-408px -96px}
414 414 .icon-minus{background-position:-433px -96px}
415 415 .icon-asterisk{background-position:-456px -96px}
416 416 .icon-exclamation-sign{background-position:0 -120px}
417 417 .icon-gift{background-position:-24px -120px}
418 418 .icon-leaf{background-position:-48px -120px}
419 419 .icon-fire{background-position:-72px -120px}
420 420 .icon-eye-open{background-position:-96px -120px}
421 421 .icon-eye-close{background-position:-120px -120px}
422 422 .icon-warning-sign{background-position:-144px -120px}
423 423 .icon-plane{background-position:-168px -120px}
424 424 .icon-calendar{background-position:-192px -120px}
425 425 .icon-random{background-position:-216px -120px;width:16px}
426 426 .icon-comment{background-position:-240px -120px}
427 427 .icon-magnet{background-position:-264px -120px}
428 428 .icon-chevron-up{background-position:-288px -120px}
429 429 .icon-chevron-down{background-position:-313px -119px}
430 430 .icon-retweet{background-position:-336px -120px}
431 431 .icon-shopping-cart{background-position:-360px -120px}
432 432 .icon-folder-close{background-position:-384px -120px;width:16px}
433 433 .icon-folder-open{background-position:-408px -120px;width:16px}
434 434 .icon-resize-vertical{background-position:-432px -119px}
435 435 .icon-resize-horizontal{background-position:-456px -118px}
436 436 .icon-hdd{background-position:0 -144px}
437 437 .icon-bullhorn{background-position:-24px -144px}
438 438 .icon-bell{background-position:-48px -144px}
439 439 .icon-certificate{background-position:-72px -144px}
440 440 .icon-thumbs-up{background-position:-96px -144px}
441 441 .icon-thumbs-down{background-position:-120px -144px}
442 442 .icon-hand-right{background-position:-144px -144px}
443 443 .icon-hand-left{background-position:-168px -144px}
444 444 .icon-hand-up{background-position:-192px -144px}
445 445 .icon-hand-down{background-position:-216px -144px}
446 446 .icon-circle-arrow-right{background-position:-240px -144px}
447 447 .icon-circle-arrow-left{background-position:-264px -144px}
448 448 .icon-circle-arrow-up{background-position:-288px -144px}
449 449 .icon-circle-arrow-down{background-position:-312px -144px}
450 450 .icon-globe{background-position:-336px -144px}
451 451 .icon-wrench{background-position:-360px -144px}
452 452 .icon-tasks{background-position:-384px -144px}
453 453 .icon-filter{background-position:-408px -144px}
454 454 .icon-briefcase{background-position:-432px -144px}
455 455 .icon-fullscreen{background-position:-456px -144px}
456 456 .dropup,.dropdown{position:relative}
457 457 .dropdown-toggle{*margin-bottom:-3px}
458 458 .dropdown-toggle:active,.open .dropdown-toggle{outline:0}
459 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 460 .dropdown .caret{margin-top:8px;margin-left:2px}
461 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 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 463 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}
464 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 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 466 .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
467 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 468 .open{*z-index:1000}.open>.dropdown-menu{display:block}
469 469 .dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}
470 470 .pull-right>.dropdown-menu{right:0;left:auto}
471 471 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}
472 472 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}
473 473 .dropdown-submenu{position:relative}
474 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 475 .dropdown-submenu:hover>.dropdown-menu{display:block}
476 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 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 478 .dropdown-submenu:hover>a:after{border-left-color:#fff}
479 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 480 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}
481 481 .typeahead{z-index:1051;margin-top:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
482 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 483 .well-large{padding:24px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
484 484 .well-small{padding:9px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
485 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 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 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 488 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}
489 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 490 .btn:active,.btn.active{background-color:#ccc \9}
491 491 .btn:first-child{*margin-left:0}
492 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 493 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
494 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 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 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 497 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}
498 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 499 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}
500 500 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}
501 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 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 503 .btn-block+.btn-block{margin-top:5px}
504 504 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}
505 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 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 507 .btn-primary:active,.btn-primary.active{background-color:#039 \9}
508 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 509 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9}
510 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 511 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9}
512 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 513 .btn-success:active,.btn-success.active{background-color:#408140 \9}
514 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 515 .btn-info:active,.btn-info.active{background-color:#24748c \9}
516 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 517 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}
518 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 519 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}
520 520 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}
521 521 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}
522 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 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 524 .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}
525 525 .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}
526 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 527 .btn-group+.btn-group{margin-left:5px}
528 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 529 .btn-group>.btn{position:relative;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
530 530 .btn-group>.btn+.btn{margin-left:-1px}
531 531 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px}
532 532 .btn-group>.btn-mini{font-size:9.75px}
533 533 .btn-group>.btn-small{font-size:11.049999999999999px}
534 534 .btn-group>.btn-large{font-size:16.25px}
535 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 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 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 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 539 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}
540 540 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}
541 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 542 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px}
543 543 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}
544 544 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px}
545 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 546 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}
547 547 .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}
548 548 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}
549 549 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}
550 550 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}
551 551 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}
552 552 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}
553 553 .btn .caret{margin-top:8px;margin-left:0}
554 554 .btn-large .caret{margin-top:6px}
555 555 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}
556 556 .btn-mini .caret,.btn-small .caret{margin-top:8px}
557 557 .dropup .btn-large .caret{border-bottom-width:5px}
558 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 559 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}
560 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 561 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}
562 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 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 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 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 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 567 .alert,.alert h4{color:#c09853}
568 568 .alert h4{margin:0}
569 569 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}
570 570 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}
571 571 .alert-success h4{color:#468847}
572 572 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}
573 573 .alert-danger h4,.alert-error h4{color:#b94a48}
574 574 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}
575 575 .alert-info h4{color:#3a87ad}
576 576 .alert-block{padding-top:14px;padding-bottom:14px}
577 577 .alert-block>p,.alert-block>ul{margin-bottom:0}
578 578 .alert-block p+p{margin-top:5px}
579 579 .nav{margin-left:0;margin-bottom:20px;list-style:none}
580 580 .nav>li>a{display:block}
581 581 .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
582 582 .nav>li>a>img{max-width:none}
583 583 .nav>.pull-right{float:right}
584 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 585 .nav li+.nav-header{margin-top:9px}
586 586 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}
587 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 588 .nav-list>li>a{padding:3px 15px}
589 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 590 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}
591 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 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 593 .nav-tabs:after,.nav-pills:after{clear:both}
594 594 .nav-tabs>li,.nav-pills>li{float:left}
595 595 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}
596 596 .nav-tabs{border-bottom:1px solid #ddd}
597 597 .nav-tabs>li{margin-bottom:-1px}
598 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 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 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 601 .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}
602 602 .nav-stacked>li{float:none}
603 603 .nav-stacked>li>a{margin-right:0}
604 604 .nav-tabs.nav-stacked{border-bottom:0}
605 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 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 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 608 .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2}
609 609 .nav-pills.nav-stacked>li>a{margin-bottom:3px}
610 610 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}
611 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 612 .nav-pills .dropdown-menu{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
613 613 .nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}
614 614 .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}
615 615 .nav-tabs .dropdown-toggle .caret{margin-top:8px}
616 616 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
617 617 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
618 618 .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}
619 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 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 621 .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}
622 622 .tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0}
623 623 .tabbable:after{clear:both}
624 624 .tab-content{overflow:auto}
625 625 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}
626 626 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
627 627 .tab-content>.active,.pill-content>.active{display:block}
628 628 .tabs-below>.nav-tabs{border-top:1px solid #ddd}
629 629 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}
630 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 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 632 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}
633 633 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}
634 634 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}
635 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 636 .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}
637 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 638 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}
639 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 640 .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}
641 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 642 .nav>.disabled>a{color:#999}
643 643 .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default}
644 644 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2}
645 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 646 .navbar-inner:after{clear:both}
647 647 .navbar .container{width:auto}
648 648 .nav-collapse.collapse{height:auto;overflow:visible}
649 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 650 .navbar-text{margin-bottom:0;line-height:36px;color:#777}
651 651 .navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}
652 652 .navbar .divider-vertical{height:36px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}
653 653 .navbar .btn,.navbar .btn-group{margin-top:3px}
654 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 655 .navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0}
656 656 .navbar-form:after{clear:both}
657 657 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:3px}
658 658 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}
659 659 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}
660 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 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 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 663 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}
664 664 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}
665 665 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}
666 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 667 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
668 668 .navbar-fixed-top{top:0}
669 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 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 671 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}
672 672 .navbar .nav.pull-right{float:right;margin-right:0}
673 673 .navbar .nav>li{float:left}
674 674 .navbar .nav>li>a{float:none;padding:8px 15px 8px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}
675 675 .navbar .nav .dropdown-toggle .caret{margin-top:8px}
676 676 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}
677 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 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 679 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}
680 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 681 .btn-navbar .icon-bar+.icon-bar{margin-top:3px}
682 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 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 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 685 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}
686 686 .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}
687 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 688 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}
689 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 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 691 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px}
692 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 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 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 695 .navbar-inverse .brand{color:#999}
696 696 .navbar-inverse .navbar-text{color:#999}
697 697 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}
698 698 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}
699 699 .navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}
700 700 .navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}
701 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 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 703 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}
704 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 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 706 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}
707 707 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}
708 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 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 710 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}
711 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 712 .breadcrumb>.active{color:#999}
713 713 .pagination{margin:20px 0}
714 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 715 .pagination ul>li{display:inline}
716 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 717 .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}
718 718 .pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}
719 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 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 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 722 .pagination-centered{text-align:center}
723 723 .pagination-right{text-align:right}
724 724 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px}
725 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 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 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 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 729 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px}
730 730 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px}
731 731 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1}.pager:before,.pager:after{display:table;content:"";line-height:0}
732 732 .pager:after{clear:both}
733 733 .pager li{display:inline}
734 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 735 .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}
736 736 .pager .next>a,.pager .next>span{float:right}
737 737 .pager .previous>a,.pager .previous>span{float:left}
738 738 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}
739 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 740 .modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}
741 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 742 .modal.fade.in{top:10%}
743 743 .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}
744 744 .modal-header h3{margin:0;line-height:30px}
745 745 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px}
746 746 .modal-form{margin-bottom:0}
747 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 748 .modal-footer:after{clear:both}
749 749 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}
750 750 .modal-footer .btn-group .btn+.btn{margin-left:-1px}
751 751 .modal-footer .btn-block+.btn-block{margin-left:0}
752 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 753 .tooltip.top{margin-top:-3px;padding:5px 0}
754 754 .tooltip.right{margin-left:3px;padding:0 5px}
755 755 .tooltip.bottom{margin-top:3px;padding:5px 0}
756 756 .tooltip.left{margin-left:-3px;padding:0 5px}
757 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 758 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}
759 759 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}
760 760 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}
761 761 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}
762 762 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}
763 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 764 .popover.right{margin-left:10px}
765 765 .popover.bottom{margin-top:10px}
766 766 .popover.left{margin-left:-10px}
767 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 768 .popover-content{padding:9px 14px}
769 769 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}
770 770 .popover .arrow{border-width:11px}
771 771 .popover .arrow:after{border-width:10px;content:""}
772 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 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 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 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 776 .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0}
777 777 .thumbnails:after{clear:both}
778 778 .row-fluid .thumbnails{margin-left:0}
779 779 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}
780 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 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 782 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}
783 783 .thumbnail .caption{padding:9px;color:#555}
784 784 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1}
785 785 .media,.media .media{margin-top:15px}
786 786 .media:first-child{margin-top:0}
787 787 .media-object{display:block}
788 788 .media-heading{margin:0 0 5px}
789 789 .media>.pull-left{margin-right:10px}
790 790 .media>.pull-right{margin-left:10px}
791 791 .media-list{margin-left:0;list-style:none}
792 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 793 .label{border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
794 794 .badge{padding-left:9px;padding-right:9px;border-radius:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}
795 795 .label:empty,.badge:empty{display:none}
796 796 a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
797 797 .label-important,.badge-important{background-color:#b94a48}
798 798 .label-important[href],.badge-important[href]{background-color:#953b39}
799 799 .label-warning,.badge-warning{background-color:#f89406}
800 800 .label-warning[href],.badge-warning[href]{background-color:#c67605}
801 801 .label-success,.badge-success{background-color:#468847}
802 802 .label-success[href],.badge-success[href]{background-color:#356635}
803 803 .label-info,.badge-info{background-color:#3a87ad}
804 804 .label-info[href],.badge-info[href]{background-color:#2d6987}
805 805 .label-inverse,.badge-inverse{background-color:#333}
806 806 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}
807 807 .btn .label,.btn .badge{position:relative;top:-1px}
808 808 .btn-mini .label,.btn-mini .badge{top:0}
809 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 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 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 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 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 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 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 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 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 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 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 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 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 822 .accordion{margin-bottom:20px}
823 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 824 .accordion-heading{border-bottom:0}
825 825 .accordion-heading .accordion-toggle{display:block;padding:8px 15px}
826 826 .accordion-toggle{cursor:pointer}
827 827 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}
828 828 .carousel{position:relative;margin-bottom:20px;line-height:1}
829 829 .carousel-inner{overflow:hidden;width:100%;position:relative}
830 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 831 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}
832 832 .carousel-inner>.active{left:0}
833 833 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}
834 834 .carousel-inner>.next{left:100%}
835 835 .carousel-inner>.prev{left:-100%}
836 836 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}
837 837 .carousel-inner>.active.left{left:-100%}
838 838 .carousel-inner>.active.right{left:100%}
839 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 840 .carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}
841 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 842 .carousel-indicators .active{background-color:#fff}
843 843 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}
844 844 .carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}
845 845 .carousel-caption h4{margin:0 0 5px}
846 846 .carousel-caption p{margin-bottom:0}
847 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 848 .hero-unit li{line-height:30px}
849 849 .pull-right{float:right}
850 850 .pull-left{float:left}
851 851 .hide{display:none}
852 852 .show{display:block}
853 853 .invisible{visibility:hidden}
854 854 .affix{position:fixed}
855 855 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
856 856 .clearfix:after{clear:both}
857 857 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
858 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 859 @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}
860 860 .visible-phone{display:none !important}
861 861 .visible-tablet{display:none !important}
862 862 .hidden-desktop{display:none !important}
863 863 .visible-desktop{display:inherit !important}
864 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 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 866 [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}
867 867 .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}
868 868 a [class^="icon-"],a [class*=" icon-"]{display:inline}
869 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 870 .icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}
871 871 .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}
872 872 [class^="icon-"].hide,[class*=" icon-"].hide{display:none}
873 873 .icon-muted{color:#eee}
874 874 .icon-light{color:#fff}
875 875 .icon-dark{color:#333}
876 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 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 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 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 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 881 .pull-right{float:right}
882 882 .pull-left{float:left}
883 883 [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}
884 884 [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}
885 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 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 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 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 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 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 891 .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}
892 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 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 894 .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}
895 895 .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}
896 896 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}
897 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 898 .icon-stack .icon-stack-base{font-size:2em;*line-height:1em}
899 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 900 a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}
901 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 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 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 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 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 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 907 .icon-glass:before{content:"\f000"}
908 908 .icon-music:before{content:"\f001"}
909 909 .icon-search:before{content:"\f002"}
910 910 .icon-envelope-alt:before{content:"\f003"}
911 911 .icon-heart:before{content:"\f004"}
912 912 .icon-star:before{content:"\f005"}
913 913 .icon-star-empty:before{content:"\f006"}
914 914 .icon-user:before{content:"\f007"}
915 915 .icon-film:before{content:"\f008"}
916 916 .icon-th-large:before{content:"\f009"}
917 917 .icon-th:before{content:"\f00a"}
918 918 .icon-th-list:before{content:"\f00b"}
919 919 .icon-ok:before{content:"\f00c"}
920 920 .icon-remove:before{content:"\f00d"}
921 921 .icon-zoom-in:before{content:"\f00e"}
922 922 .icon-zoom-out:before{content:"\f010"}
923 923 .icon-power-off:before,.icon-off:before{content:"\f011"}
924 924 .icon-signal:before{content:"\f012"}
925 925 .icon-gear:before,.icon-cog:before{content:"\f013"}
926 926 .icon-trash:before{content:"\f014"}
927 927 .icon-home:before{content:"\f015"}
928 928 .icon-file-alt:before{content:"\f016"}
929 929 .icon-time:before{content:"\f017"}
930 930 .icon-road:before{content:"\f018"}
931 931 .icon-download-alt:before{content:"\f019"}
932 932 .icon-download:before{content:"\f01a"}
933 933 .icon-upload:before{content:"\f01b"}
934 934 .icon-inbox:before{content:"\f01c"}
935 935 .icon-play-circle:before{content:"\f01d"}
936 936 .icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}
937 937 .icon-refresh:before{content:"\f021"}
938 938 .icon-list-alt:before{content:"\f022"}
939 939 .icon-lock:before{content:"\f023"}
940 940 .icon-flag:before{content:"\f024"}
941 941 .icon-headphones:before{content:"\f025"}
942 942 .icon-volume-off:before{content:"\f026"}
943 943 .icon-volume-down:before{content:"\f027"}
944 944 .icon-volume-up:before{content:"\f028"}
945 945 .icon-qrcode:before{content:"\f029"}
946 946 .icon-barcode:before{content:"\f02a"}
947 947 .icon-tag:before{content:"\f02b"}
948 948 .icon-tags:before{content:"\f02c"}
949 949 .icon-book:before{content:"\f02d"}
950 950 .icon-bookmark:before{content:"\f02e"}
951 951 .icon-print:before{content:"\f02f"}
952 952 .icon-camera:before{content:"\f030"}
953 953 .icon-font:before{content:"\f031"}
954 954 .icon-bold:before{content:"\f032"}
955 955 .icon-italic:before{content:"\f033"}
956 956 .icon-text-height:before{content:"\f034"}
957 957 .icon-text-width:before{content:"\f035"}
958 958 .icon-align-left:before{content:"\f036"}
959 959 .icon-align-center:before{content:"\f037"}
960 960 .icon-align-right:before{content:"\f038"}
961 961 .icon-align-justify:before{content:"\f039"}
962 962 .icon-list:before{content:"\f03a"}
963 963 .icon-indent-left:before{content:"\f03b"}
964 964 .icon-indent-right:before{content:"\f03c"}
965 965 .icon-facetime-video:before{content:"\f03d"}
966 966 .icon-picture:before{content:"\f03e"}
967 967 .icon-pencil:before{content:"\f040"}
968 968 .icon-map-marker:before{content:"\f041"}
969 969 .icon-adjust:before{content:"\f042"}
970 970 .icon-tint:before{content:"\f043"}
971 971 .icon-edit:before{content:"\f044"}
972 972 .icon-share:before{content:"\f045"}
973 973 .icon-check:before{content:"\f046"}
974 974 .icon-move:before{content:"\f047"}
975 975 .icon-step-backward:before{content:"\f048"}
976 976 .icon-fast-backward:before{content:"\f049"}
977 977 .icon-backward:before{content:"\f04a"}
978 978 .icon-play:before{content:"\f04b"}
979 979 .icon-pause:before{content:"\f04c"}
980 980 .icon-stop:before{content:"\f04d"}
981 981 .icon-forward:before{content:"\f04e"}
982 982 .icon-fast-forward:before{content:"\f050"}
983 983 .icon-step-forward:before{content:"\f051"}
984 984 .icon-eject:before{content:"\f052"}
985 985 .icon-chevron-left:before{content:"\f053"}
986 986 .icon-chevron-right:before{content:"\f054"}
987 987 .icon-plus-sign:before{content:"\f055"}
988 988 .icon-minus-sign:before{content:"\f056"}
989 989 .icon-remove-sign:before{content:"\f057"}
990 990 .icon-ok-sign:before{content:"\f058"}
991 991 .icon-question-sign:before{content:"\f059"}
992 992 .icon-info-sign:before{content:"\f05a"}
993 993 .icon-screenshot:before{content:"\f05b"}
994 994 .icon-remove-circle:before{content:"\f05c"}
995 995 .icon-ok-circle:before{content:"\f05d"}
996 996 .icon-ban-circle:before{content:"\f05e"}
997 997 .icon-arrow-left:before{content:"\f060"}
998 998 .icon-arrow-right:before{content:"\f061"}
999 999 .icon-arrow-up:before{content:"\f062"}
1000 1000 .icon-arrow-down:before{content:"\f063"}
1001 1001 .icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}
1002 1002 .icon-resize-full:before{content:"\f065"}
1003 1003 .icon-resize-small:before{content:"\f066"}
1004 1004 .icon-plus:before{content:"\f067"}
1005 1005 .icon-minus:before{content:"\f068"}
1006 1006 .icon-asterisk:before{content:"\f069"}
1007 1007 .icon-exclamation-sign:before{content:"\f06a"}
1008 1008 .icon-gift:before{content:"\f06b"}
1009 1009 .icon-leaf:before{content:"\f06c"}
1010 1010 .icon-fire:before{content:"\f06d"}
1011 1011 .icon-eye-open:before{content:"\f06e"}
1012 1012 .icon-eye-close:before{content:"\f070"}
1013 1013 .icon-warning-sign:before{content:"\f071"}
1014 1014 .icon-plane:before{content:"\f072"}
1015 1015 .icon-calendar:before{content:"\f073"}
1016 1016 .icon-random:before{content:"\f074"}
1017 1017 .icon-comment:before{content:"\f075"}
1018 1018 .icon-magnet:before{content:"\f076"}
1019 1019 .icon-chevron-up:before{content:"\f077"}
1020 1020 .icon-chevron-down:before{content:"\f078"}
1021 1021 .icon-retweet:before{content:"\f079"}
1022 1022 .icon-shopping-cart:before{content:"\f07a"}
1023 1023 .icon-folder-close:before{content:"\f07b"}
1024 1024 .icon-folder-open:before{content:"\f07c"}
1025 1025 .icon-resize-vertical:before{content:"\f07d"}
1026 1026 .icon-resize-horizontal:before{content:"\f07e"}
1027 1027 .icon-bar-chart:before{content:"\f080"}
1028 1028 .icon-twitter-sign:before{content:"\f081"}
1029 1029 .icon-facebook-sign:before{content:"\f082"}
1030 1030 .icon-camera-retro:before{content:"\f083"}
1031 1031 .icon-key:before{content:"\f084"}
1032 1032 .icon-gears:before,.icon-cogs:before{content:"\f085"}
1033 1033 .icon-comments:before{content:"\f086"}
1034 1034 .icon-thumbs-up-alt:before{content:"\f087"}
1035 1035 .icon-thumbs-down-alt:before{content:"\f088"}
1036 1036 .icon-star-half:before{content:"\f089"}
1037 1037 .icon-heart-empty:before{content:"\f08a"}
1038 1038 .icon-signout:before{content:"\f08b"}
1039 1039 .icon-linkedin-sign:before{content:"\f08c"}
1040 1040 .icon-pushpin:before{content:"\f08d"}
1041 1041 .icon-external-link:before{content:"\f08e"}
1042 1042 .icon-signin:before{content:"\f090"}
1043 1043 .icon-trophy:before{content:"\f091"}
1044 1044 .icon-github-sign:before{content:"\f092"}
1045 1045 .icon-upload-alt:before{content:"\f093"}
1046 1046 .icon-lemon:before{content:"\f094"}
1047 1047 .icon-phone:before{content:"\f095"}
1048 1048 .icon-unchecked:before,.icon-check-empty:before{content:"\f096"}
1049 1049 .icon-bookmark-empty:before{content:"\f097"}
1050 1050 .icon-phone-sign:before{content:"\f098"}
1051 1051 .icon-twitter:before{content:"\f099"}
1052 1052 .icon-facebook:before{content:"\f09a"}
1053 1053 .icon-github:before{content:"\f09b"}
1054 1054 .icon-unlock:before{content:"\f09c"}
1055 1055 .icon-credit-card:before{content:"\f09d"}
1056 1056 .icon-rss:before{content:"\f09e"}
1057 1057 .icon-hdd:before{content:"\f0a0"}
1058 1058 .icon-bullhorn:before{content:"\f0a1"}
1059 1059 .icon-bell:before{content:"\f0a2"}
1060 1060 .icon-certificate:before{content:"\f0a3"}
1061 1061 .icon-hand-right:before{content:"\f0a4"}
1062 1062 .icon-hand-left:before{content:"\f0a5"}
1063 1063 .icon-hand-up:before{content:"\f0a6"}
1064 1064 .icon-hand-down:before{content:"\f0a7"}
1065 1065 .icon-circle-arrow-left:before{content:"\f0a8"}
1066 1066 .icon-circle-arrow-right:before{content:"\f0a9"}
1067 1067 .icon-circle-arrow-up:before{content:"\f0aa"}
1068 1068 .icon-circle-arrow-down:before{content:"\f0ab"}
1069 1069 .icon-globe:before{content:"\f0ac"}
1070 1070 .icon-wrench:before{content:"\f0ad"}
1071 1071 .icon-tasks:before{content:"\f0ae"}
1072 1072 .icon-filter:before{content:"\f0b0"}
1073 1073 .icon-briefcase:before{content:"\f0b1"}
1074 1074 .icon-fullscreen:before{content:"\f0b2"}
1075 1075 .icon-group:before{content:"\f0c0"}
1076 1076 .icon-link:before{content:"\f0c1"}
1077 1077 .icon-cloud:before{content:"\f0c2"}
1078 1078 .icon-beaker:before{content:"\f0c3"}
1079 1079 .icon-cut:before{content:"\f0c4"}
1080 1080 .icon-copy:before{content:"\f0c5"}
1081 1081 .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}
1082 1082 .icon-save:before{content:"\f0c7"}
1083 1083 .icon-sign-blank:before{content:"\f0c8"}
1084 1084 .icon-reorder:before{content:"\f0c9"}
1085 1085 .icon-list-ul:before{content:"\f0ca"}
1086 1086 .icon-list-ol:before{content:"\f0cb"}
1087 1087 .icon-strikethrough:before{content:"\f0cc"}
1088 1088 .icon-underline:before{content:"\f0cd"}
1089 1089 .icon-table:before{content:"\f0ce"}
1090 1090 .icon-magic:before{content:"\f0d0"}
1091 1091 .icon-truck:before{content:"\f0d1"}
1092 1092 .icon-pinterest:before{content:"\f0d2"}
1093 1093 .icon-pinterest-sign:before{content:"\f0d3"}
1094 1094 .icon-google-plus-sign:before{content:"\f0d4"}
1095 1095 .icon-google-plus:before{content:"\f0d5"}
1096 1096 .icon-money:before{content:"\f0d6"}
1097 1097 .icon-caret-down:before{content:"\f0d7"}
1098 1098 .icon-caret-up:before{content:"\f0d8"}
1099 1099 .icon-caret-left:before{content:"\f0d9"}
1100 1100 .icon-caret-right:before{content:"\f0da"}
1101 1101 .icon-columns:before{content:"\f0db"}
1102 1102 .icon-sort:before{content:"\f0dc"}
1103 1103 .icon-sort-down:before{content:"\f0dd"}
1104 1104 .icon-sort-up:before{content:"\f0de"}
1105 1105 .icon-envelope:before{content:"\f0e0"}
1106 1106 .icon-linkedin:before{content:"\f0e1"}
1107 1107 .icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}
1108 1108 .icon-legal:before{content:"\f0e3"}
1109 1109 .icon-dashboard:before{content:"\f0e4"}
1110 1110 .icon-comment-alt:before{content:"\f0e5"}
1111 1111 .icon-comments-alt:before{content:"\f0e6"}
1112 1112 .icon-bolt:before{content:"\f0e7"}
1113 1113 .icon-sitemap:before{content:"\f0e8"}
1114 1114 .icon-umbrella:before{content:"\f0e9"}
1115 1115 .icon-paste:before{content:"\f0ea"}
1116 1116 .icon-lightbulb:before{content:"\f0eb"}
1117 1117 .icon-exchange:before{content:"\f0ec"}
1118 1118 .icon-cloud-download:before{content:"\f0ed"}
1119 1119 .icon-cloud-upload:before{content:"\f0ee"}
1120 1120 .icon-user-md:before{content:"\f0f0"}
1121 1121 .icon-stethoscope:before{content:"\f0f1"}
1122 1122 .icon-suitcase:before{content:"\f0f2"}
1123 1123 .icon-bell-alt:before{content:"\f0f3"}
1124 1124 .icon-coffee:before{content:"\f0f4"}
1125 1125 .icon-food:before{content:"\f0f5"}
1126 1126 .icon-file-text-alt:before{content:"\f0f6"}
1127 1127 .icon-building:before{content:"\f0f7"}
1128 1128 .icon-hospital:before{content:"\f0f8"}
1129 1129 .icon-ambulance:before{content:"\f0f9"}
1130 1130 .icon-medkit:before{content:"\f0fa"}
1131 1131 .icon-fighter-jet:before{content:"\f0fb"}
1132 1132 .icon-beer:before{content:"\f0fc"}
1133 1133 .icon-h-sign:before{content:"\f0fd"}
1134 1134 .icon-plus-sign-alt:before{content:"\f0fe"}
1135 1135 .icon-double-angle-left:before{content:"\f100"}
1136 1136 .icon-double-angle-right:before{content:"\f101"}
1137 1137 .icon-double-angle-up:before{content:"\f102"}
1138 1138 .icon-double-angle-down:before{content:"\f103"}
1139 1139 .icon-angle-left:before{content:"\f104"}
1140 1140 .icon-angle-right:before{content:"\f105"}
1141 1141 .icon-angle-up:before{content:"\f106"}
1142 1142 .icon-angle-down:before{content:"\f107"}
1143 1143 .icon-desktop:before{content:"\f108"}
1144 1144 .icon-laptop:before{content:"\f109"}
1145 1145 .icon-tablet:before{content:"\f10a"}
1146 1146 .icon-mobile-phone:before{content:"\f10b"}
1147 1147 .icon-circle-blank:before{content:"\f10c"}
1148 1148 .icon-quote-left:before{content:"\f10d"}
1149 1149 .icon-quote-right:before{content:"\f10e"}
1150 1150 .icon-spinner:before{content:"\f110"}
1151 1151 .icon-circle:before{content:"\f111"}
1152 1152 .icon-mail-reply:before,.icon-reply:before{content:"\f112"}
1153 1153 .icon-github-alt:before{content:"\f113"}
1154 1154 .icon-folder-close-alt:before{content:"\f114"}
1155 1155 .icon-folder-open-alt:before{content:"\f115"}
1156 1156 .icon-expand-alt:before{content:"\f116"}
1157 1157 .icon-collapse-alt:before{content:"\f117"}
1158 1158 .icon-smile:before{content:"\f118"}
1159 1159 .icon-frown:before{content:"\f119"}
1160 1160 .icon-meh:before{content:"\f11a"}
1161 1161 .icon-gamepad:before{content:"\f11b"}
1162 1162 .icon-keyboard:before{content:"\f11c"}
1163 1163 .icon-flag-alt:before{content:"\f11d"}
1164 1164 .icon-flag-checkered:before{content:"\f11e"}
1165 1165 .icon-terminal:before{content:"\f120"}
1166 1166 .icon-code:before{content:"\f121"}
1167 1167 .icon-reply-all:before{content:"\f122"}
1168 1168 .icon-mail-reply-all:before{content:"\f122"}
1169 1169 .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}
1170 1170 .icon-location-arrow:before{content:"\f124"}
1171 1171 .icon-crop:before{content:"\f125"}
1172 1172 .icon-code-fork:before{content:"\f126"}
1173 1173 .icon-unlink:before{content:"\f127"}
1174 1174 .icon-question:before{content:"\f128"}
1175 1175 .icon-info:before{content:"\f129"}
1176 1176 .icon-exclamation:before{content:"\f12a"}
1177 1177 .icon-superscript:before{content:"\f12b"}
1178 1178 .icon-subscript:before{content:"\f12c"}
1179 1179 .icon-eraser:before{content:"\f12d"}
1180 1180 .icon-puzzle-piece:before{content:"\f12e"}
1181 1181 .icon-microphone:before{content:"\f130"}
1182 1182 .icon-microphone-off:before{content:"\f131"}
1183 1183 .icon-shield:before{content:"\f132"}
1184 1184 .icon-calendar-empty:before{content:"\f133"}
1185 1185 .icon-fire-extinguisher:before{content:"\f134"}
1186 1186 .icon-rocket:before{content:"\f135"}
1187 1187 .icon-maxcdn:before{content:"\f136"}
1188 1188 .icon-chevron-sign-left:before{content:"\f137"}
1189 1189 .icon-chevron-sign-right:before{content:"\f138"}
1190 1190 .icon-chevron-sign-up:before{content:"\f139"}
1191 1191 .icon-chevron-sign-down:before{content:"\f13a"}
1192 1192 .icon-html5:before{content:"\f13b"}
1193 1193 .icon-css3:before{content:"\f13c"}
1194 1194 .icon-anchor:before{content:"\f13d"}
1195 1195 .icon-unlock-alt:before{content:"\f13e"}
1196 1196 .icon-bullseye:before{content:"\f140"}
1197 1197 .icon-ellipsis-horizontal:before{content:"\f141"}
1198 1198 .icon-ellipsis-vertical:before{content:"\f142"}
1199 1199 .icon-rss-sign:before{content:"\f143"}
1200 1200 .icon-play-sign:before{content:"\f144"}
1201 1201 .icon-ticket:before{content:"\f145"}
1202 1202 .icon-minus-sign-alt:before{content:"\f146"}
1203 1203 .icon-check-minus:before{content:"\f147"}
1204 1204 .icon-level-up:before{content:"\f148"}
1205 1205 .icon-level-down:before{content:"\f149"}
1206 1206 .icon-check-sign:before{content:"\f14a"}
1207 1207 .icon-edit-sign:before{content:"\f14b"}
1208 1208 .icon-external-link-sign:before{content:"\f14c"}
1209 1209 .icon-share-sign:before{content:"\f14d"}
1210 1210 .icon-compass:before{content:"\f14e"}
1211 1211 .icon-collapse:before{content:"\f150"}
1212 1212 .icon-collapse-top:before{content:"\f151"}
1213 1213 .icon-expand:before{content:"\f152"}
1214 1214 .icon-euro:before,.icon-eur:before{content:"\f153"}
1215 1215 .icon-gbp:before{content:"\f154"}
1216 1216 .icon-dollar:before,.icon-usd:before{content:"\f155"}
1217 1217 .icon-rupee:before,.icon-inr:before{content:"\f156"}
1218 1218 .icon-yen:before,.icon-jpy:before{content:"\f157"}
1219 1219 .icon-renminbi:before,.icon-cny:before{content:"\f158"}
1220 1220 .icon-won:before,.icon-krw:before{content:"\f159"}
1221 1221 .icon-bitcoin:before,.icon-btc:before{content:"\f15a"}
1222 1222 .icon-file:before{content:"\f15b"}
1223 1223 .icon-file-text:before{content:"\f15c"}
1224 1224 .icon-sort-by-alphabet:before{content:"\f15d"}
1225 1225 .icon-sort-by-alphabet-alt:before{content:"\f15e"}
1226 1226 .icon-sort-by-attributes:before{content:"\f160"}
1227 1227 .icon-sort-by-attributes-alt:before{content:"\f161"}
1228 1228 .icon-sort-by-order:before{content:"\f162"}
1229 1229 .icon-sort-by-order-alt:before{content:"\f163"}
1230 1230 .icon-thumbs-up:before{content:"\f164"}
1231 1231 .icon-thumbs-down:before{content:"\f165"}
1232 1232 .icon-youtube-sign:before{content:"\f166"}
1233 1233 .icon-youtube:before{content:"\f167"}
1234 1234 .icon-xing:before{content:"\f168"}
1235 1235 .icon-xing-sign:before{content:"\f169"}
1236 1236 .icon-youtube-play:before{content:"\f16a"}
1237 1237 .icon-dropbox:before{content:"\f16b"}
1238 1238 .icon-stackexchange:before{content:"\f16c"}
1239 1239 .icon-instagram:before{content:"\f16d"}
1240 1240 .icon-flickr:before{content:"\f16e"}
1241 1241 .icon-adn:before{content:"\f170"}
1242 1242 .icon-bitbucket:before{content:"\f171"}
1243 1243 .icon-bitbucket-sign:before{content:"\f172"}
1244 1244 .icon-tumblr:before{content:"\f173"}
1245 1245 .icon-tumblr-sign:before{content:"\f174"}
1246 1246 .icon-long-arrow-down:before{content:"\f175"}
1247 1247 .icon-long-arrow-up:before{content:"\f176"}
1248 1248 .icon-long-arrow-left:before{content:"\f177"}
1249 1249 .icon-long-arrow-right:before{content:"\f178"}
1250 1250 .icon-apple:before{content:"\f179"}
1251 1251 .icon-windows:before{content:"\f17a"}
1252 1252 .icon-android:before{content:"\f17b"}
1253 1253 .icon-linux:before{content:"\f17c"}
1254 1254 .icon-dribbble:before{content:"\f17d"}
1255 1255 .icon-skype:before{content:"\f17e"}
1256 1256 .icon-foursquare:before{content:"\f180"}
1257 1257 .icon-trello:before{content:"\f181"}
1258 1258 .icon-female:before{content:"\f182"}
1259 1259 .icon-male:before{content:"\f183"}
1260 1260 .icon-gittip:before{content:"\f184"}
1261 1261 .icon-sun:before{content:"\f185"}
1262 1262 .icon-moon:before{content:"\f186"}
1263 1263 .icon-archive:before{content:"\f187"}
1264 1264 .icon-bug:before{content:"\f188"}
1265 1265 .icon-vk:before{content:"\f189"}
1266 1266 .icon-weibo:before{content:"\f18a"}
1267 1267 .icon-renren:before{content:"\f18b"}
1268 1268 code{color:#000}
1269 1269 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1270 1270 .corner-all{border-radius:4px}
1271 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 1272 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1273 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 1274 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1275 1275 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1276 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 1277 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1278 1278 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1279 1279 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1280 1280 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
1281 1281 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
1282 1282 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
1283 1283 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
1284 1284 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
1285 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 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 1287 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
1288 1288 div.error{margin:2em;text-align:center}
1289 1289 div.error>h1{font-size:500%;line-height:normal}
1290 1290 div.error>p{font-size:200%;line-height:normal}
1291 1291 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
1292 1292 body{background-color:#fff;position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}
1293 1293 div#header{display:none}
1294 1294 #ipython_notebook{padding-left:16px}
1295 1295 #noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:#f00;font-weight:bold}
1296 1296 #ipython_notebook img{font-family:Verdana,"Helvetica Neue",Arial,Helvetica,Geneva,sans-serif;height:24px;text-decoration:none;color:#000}
1297 1297 #site{width:100%;display:none}
1298 1298 .ui-button .ui-button-text{padding:.2em .8em;font-size:77%}
1299 1299 input.ui-button{padding:.3em .9em}
1300 1300 .navbar span{margin-top:3px}
1301 1301 span#login_widget{float:right}
1302 1302 .nav-header{text-transform:none}
1303 1303 .navbar-nobg{background-color:transparent;background-image:none}
1304 1304 #header>span{margin-top:10px}
1305 1305 .modal-body{max-height:500px}
1306 1306 @media (min-width:768px){.modal{width:700px;margin-left:-350px}}.center-nav{display:inline-block;margin-bottom:-4px}
1307 1307 .alternate_upload{background-color:none;display:inline}
1308 1308 .alternate_upload.form{padding:0;margin:0}
1309 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 1310 ul#tabs{margin-bottom:4px}
1311 1311 ul#tabs a{padding-top:4px;padding-bottom:4px}
1312 1312 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
1313 1313 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
1314 1314 ul.breadcrumb span{color:#5e5e5e}
1315 1315 .list_toolbar{padding:4px 0 4px 0}
1316 1316 .list_toolbar [class*="span"]{min-height:26px}
1317 1317 .list_header{font-weight:bold}
1318 1318 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
1319 1319 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
1320 1320 .list_container>div:last-child{border:none}
1321 1321 .list_item:hover .list_item{background-color:#ddd}
1322 1322 .list_item a{text-decoration:none}
1323 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 1324 .item_name{line-height:22px;height:26px}
1325 1325 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
1326 1326 .item_buttons{line-height:1em}
1327 1327 .toolbar_info{height:26px;line-height:26px}
1328 1328 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
1329 1329 input.engine_num_input{width:60px}
1330 1330 .highlight_text{color:#00f}
1331 1331 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
1332 1332 .ansibold{font-weight:bold}
1333 1333 .ansiblack{color:#000}
1334 1334 .ansired{color:#8b0000}
1335 1335 .ansigreen{color:#006400}
1336 1336 .ansiyellow{color:#a52a2a}
1337 1337 .ansiblue{color:#00008b}
1338 1338 .ansipurple{color:#9400d3}
1339 1339 .ansicyan{color:#4682b4}
1340 1340 .ansigray{color:#808080}
1341 1341 .ansibgblack{background-color:#000}
1342 1342 .ansibgred{background-color:#f00}
1343 1343 .ansibggreen{background-color:#008000}
1344 1344 .ansibgyellow{background-color:#ff0}
1345 1345 .ansibgblue{background-color:#00f}
1346 1346 .ansibgpurple{background-color:#f0f}
1347 1347 .ansibgcyan{background-color:#0ff}
1348 1348 .ansibggray{background-color:#808080}
1349 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 1350 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
1351 1351 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
1352 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 1354 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1355 1355 div.prompt:empty{padding-top:0;padding-bottom:0}
1356 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 1358 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
1359 1359 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
1360 1360 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
1361 1361 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
1362 1362 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
1363 1363 .CodeMirror-linenumber{padding:0 8px 0 4px}
1364 1364 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
1365 1365 .CodeMirror pre{padding:0;border:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
1366 1366 pre code{display:block;padding:.5em}
1367 1367 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
1368 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 1369 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
1370 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 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 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 1373 .highlight-builtin,pre .built_in{color:#008000}
1374 1374 pre .markdown .emphasis{font-style:italic}
1375 1375 pre .nginx .built_in{font-weight:normal}
1376 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 1377 .cm-s-ipython span.cm-variable{color:#000}
1378 1378 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
1379 1379 .cm-s-ipython span.cm-number{color:#080}
1380 1380 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
1381 1381 .cm-s-ipython span.cm-string{color:#ba2121}
1382 1382 .cm-s-ipython span.cm-builtin{color:#008000}
1383 1383 .cm-s-ipython span.cm-error{color:#f00}
1384 1384 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
1385 1385 .cm-s-ipython span.cm-meta{color:#a2f}
1386 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 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 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 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 1390 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
1391 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 1392 div.output_prompt{color:#8b0000}
1393 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 1394 div.output_area .rendered_html table{margin-left:0;margin-right:0}
1395 1395 div.output_area .rendered_html img{margin-left:0;margin-right:0}
1396 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 1398 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1399 1399 div.output_text{text-align:left;color:#000;line-height:1.21429em}
1400 1400 div.output_stderr{background:#fdd;}
1401 1401 div.output_latex{text-align:left}
1402 1402 div.output_javascript:empty{padding:0}
1403 1403 .js-error{color:#8b0000}
1404 1404 div.raw_input_container{font-family:monospace;padding-top:5px}
1405 1405 span.raw_input_prompt{}
1406 1406 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
1407 1407 input.raw_input:focus{box-shadow:none}
1408 1408 p.p-space{margin-bottom:10px}
1409 1409 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
1410 1410 .rendered_html strong{font-weight:bold}
1411 1411 .rendered_html u{text-decoration:underline}
1412 1412 .rendered_html :link{text-decoration:underline}
1413 1413 .rendered_html :visited{text-decoration:underline}
1414 1414 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
1415 1415 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
1416 1416 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
1417 1417 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
1418 1418 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1419 1419 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1420 1420 .rendered_html h1:first-child{margin-top:.538em}
1421 1421 .rendered_html h2:first-child{margin-top:.636em}
1422 1422 .rendered_html h3:first-child{margin-top:.777em}
1423 1423 .rendered_html h4:first-child{margin-top:1em}
1424 1424 .rendered_html h5:first-child{margin-top:1em}
1425 1425 .rendered_html h6:first-child{margin-top:1em}
1426 1426 .rendered_html ul{list-style:disc;margin:0 2em}
1427 1427 .rendered_html ul ul{list-style:square;margin:0 2em}
1428 1428 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
1429 1429 .rendered_html ol{list-style:decimal;margin:0 2em}
1430 1430 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
1431 1431 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
1432 1432 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
1433 1433 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
1434 1434 .rendered_html *+ul{margin-top:1em}
1435 1435 .rendered_html *+ol{margin-top:1em}
1436 1436 .rendered_html hr{color:#000;background-color:#000}
1437 1437 .rendered_html pre{margin:1em 2em}
1438 1438 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
1439 1439 .rendered_html blockquote{margin:1em 2em}
1440 1440 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
1441 1441 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
1442 1442 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
1443 1443 .rendered_html th{font-weight:bold}
1444 1444 .rendered_html *+table{margin-top:1em}
1445 1445 .rendered_html p{text-align:justify}
1446 1446 .rendered_html *+p{margin-top:1em}
1447 1447 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
1448 1448 .rendered_html *+img{margin-top:1em}
1449 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 1451 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
1452 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 1453 div.cell.text_cell.rendered{padding:0}
1454 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 1455 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
1456 1456 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
1457 1457 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
1458 1458 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
1459 1459 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
1460 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 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 1462 .widget-text{width:350px;margin:0 !important}
1463 1463 .widget-listbox{width:364px;margin-bottom:0}
1464 1464 .widget-numeric-text{width:150px;margin:0 !important}
1465 1465 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
1466 1466 .widget-combo-btn{min-width:138px;}
1467 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 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 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 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 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 1472 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
1473 1473 .widget-modal-body{max-height:none !important}
1474 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 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 1476 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
1477 1477 body{background-color:#fff}
1478 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 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 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 1482 div.ui-widget-content{border:1px solid #ababab;outline:none}
1483 1483 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:.4em;padding-left:2em}
1484 1484 p.dialog{padding:.2em}
1485 1485 pre,code,kbd,samp{white-space:pre-wrap}
1486 1486 #fonttest{font-family:monospace}
1487 1487 p{margin-bottom:0}
1488 1488 .end_space{height:200px}
1489 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 1490 .ctb_hideshow{display:none;vertical-align:bottom;padding-right:2px}
1491 1491 .celltoolbar>div{padding-top:0}
1492 1492 .ctb_global_show .ctb_show.ctb_hideshow{display:block}
1493 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 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 1495 .celltoolbar label{display:inline-block;height:15px;line-height:15px;vertical-align:top}
1496 1496 .celltoolbar label span{font-size:85%}
1497 1497 .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px}
1498 1498 .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px}
1499 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 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 1501 .completions select option.context{color:#0064cd}
1502 1502 #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px}
1503 1503 #menubar .navbar{margin-bottom:8px}
1504 1504 .nav-wrapper{border-bottom:1px solid #d4d4d4}
1505 1505 #menubar li.dropdown{line-height:12px}
1506 1506 i.menu-icon{padding-top:4px}
1507 1507 ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}
1508 1508 #notification_area{z-index:10}
1509 1509 .indicator_area{color:#777;padding:4px 3px;margin:0;width:11px;z-index:10;text-align:center}
1510 1510 #kernel_indicator{margin-right:-16px}
1511 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 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 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 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 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 1516 div#pager_splitter{height:8px}
1517 1517 #pager-container{position:relative;padding:15px 0}
1518 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 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 1520 .shortcut_key{display:inline-block;width:20ex;text-align:right;font-family:monospace}
1521 1521 .shortcut_descr{display:inline-block;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1522 1522 span#save_widget{padding:0 5px;margin-top:12px}
1523 1523 span#checkpoint_status,span#autosave_status{font-size:small}
1524 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 1525 .toolbar .btn{padding:2px 8px}
1526 1526 .toolbar .btn-group{margin-top:0}
1527 1527 .toolbar-inner{border:none !important;-webkit-box-shadow:none !important;-moz-box-shadow:none !important;box-shadow:none !important}
1528 1528 #maintoolbar{margin-bottom:0}
1529 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 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 1531 .tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}
1532 1532 .tooltiptext{padding-right:30px}
1533 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 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 1535 .pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}
1536 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 1 {% extends "page.html" %}
2 2
3 3 {% block stylesheet %}
4 4
5 5 {% if mathjax_url %}
6 6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
7 7 {% endif %}
8 8 <script type="text/javascript">
9 9 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 10 // where it will be undefined, and should prompt a dialog later.
11 11 window.mathjax_url = "{{mathjax_url}}";
12 12 </script>
13 13
14 14 <link rel="stylesheet" href="{{ static_url("components/bootstrap-tour/build/css/bootstrap-tour.min.css") }}" type="text/css" />
15 15 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
16 16
17 17 {{super()}}
18 18
19 19 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
20 20
21 21 {% endblock %}
22 22
23 23 {% block params %}
24 24
25 25 data-project="{{project}}"
26 26 data-base-url="{{base_url}}"
27 27 data-notebook-name="{{notebook_name}}"
28 28 data-notebook-path="{{notebook_path}}"
29 29 class="notebook_app"
30 30
31 31 {% endblock %}
32 32
33 33
34 34 {% block header %}
35 35
36 36 <span id="save_widget" class="nav pull-left">
37 37 <span id="notebook_name"></span>
38 38 <span id="checkpoint_status"></span>
39 39 <span id="autosave_status"></span>
40 40 </span>
41 41
42 42 {% endblock %}
43 43
44 44
45 45 {% block site %}
46 46
47 47 <div id="menubar-container" class="container">
48 48 <div id="menubar">
49 49 <div class="navbar">
50 50 <div class="navbar-inner">
51 51 <div class="container">
52 52 <ul id="menus" class="nav">
53 53 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
54 54 <ul id="file_menu" class="dropdown-menu">
55 55 <li id="new_notebook"
56 56 title="Make a new notebook (Opens a new window)">
57 57 <a href="#">New</a></li>
58 58 <li id="open_notebook"
59 59 title="Opens a new window with the Dashboard view">
60 60 <a href="#">Open...</a></li>
61 61 <!-- <hr/> -->
62 62 <li class="divider"></li>
63 63 <li id="copy_notebook"
64 64 title="Open a copy of this notebook's contents and start a new kernel">
65 65 <a href="#">Make a Copy...</a></li>
66 66 <li id="rename_notebook"><a href="#">Rename...</a></li>
67 67 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
68 68 <!-- <hr/> -->
69 69 <li class="divider"></li>
70 70 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
71 71 <ul class="dropdown-menu">
72 72 <li><a href="#"></a></li>
73 73 <li><a href="#"></a></li>
74 74 <li><a href="#"></a></li>
75 75 <li><a href="#"></a></li>
76 76 <li><a href="#"></a></li>
77 77 </ul>
78 78 </li>
79 79 <li class="divider"></li>
80 80 <li id="print_preview"><a href="#">Print Preview</a></li>
81 81 <li class="dropdown-submenu"><a href="#">Download as</a>
82 82 <ul class="dropdown-menu">
83 83 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
84 84 <li id="download_py"><a href="#">Python (.py)</a></li>
85 85 <li id="download_html"><a href="#">HTML (.html)</a></li>
86 86 <li id="download_rst"><a href="#">reST (.rst)</a></li>
87 87 </ul>
88 88 </li>
89 89 <li class="divider"></li>
90 90 <li id="trust_notebook"
91 91 title="Trust the output of this notebook">
92 92 <a href="#" >Trust Notebook</a></li>
93 93 <li class="divider"></li>
94 94 <li id="kill_and_exit"
95 95 title="Shutdown this notebook's kernel, and close this window">
96 96 <a href="#" >Close and halt</a></li>
97 97 </ul>
98 98 </li>
99 99 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
100 100 <ul id="edit_menu" class="dropdown-menu">
101 101 <li id="cut_cell"><a href="#">Cut Cell</a></li>
102 102 <li id="copy_cell"><a href="#">Copy Cell</a></li>
103 103 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
104 104 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
105 105 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
106 106 <li id="delete_cell"><a href="#">Delete Cell</a></li>
107 107 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
108 108 <li class="divider"></li>
109 109 <li id="split_cell"><a href="#">Split Cell</a></li>
110 110 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
111 111 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
112 112 <li class="divider"></li>
113 113 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
114 114 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
115 115 <li class="divider"></li>
116 116 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
117 117 </ul>
118 118 </li>
119 119 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
120 120 <ul id="view_menu" class="dropdown-menu">
121 121 <li id="toggle_header"
122 122 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
123 123 <a href="#">Toggle Header</a></li>
124 124 <li id="toggle_toolbar"
125 125 title="Show/Hide the action icons (below menu bar)">
126 126 <a href="#">Toggle Toolbar</a></li>
127 127 </ul>
128 128 </li>
129 129 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
130 130 <ul id="insert_menu" class="dropdown-menu">
131 131 <li id="insert_cell_above"
132 132 title="Insert an empty Code cell above the currently active cell">
133 133 <a href="#">Insert Cell Above</a></li>
134 134 <li id="insert_cell_below"
135 135 title="Insert an empty Code cell below the currently active cell">
136 136 <a href="#">Insert Cell Below</a></li>
137 137 </ul>
138 138 </li>
139 139 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
140 140 <ul id="cell_menu" class="dropdown-menu">
141 141 <li id="run_cell" title="Run this cell, and move cursor to the next one">
142 142 <a href="#">Run</a></li>
143 143 <li id="run_cell_select_below" title="Run this cell, select below">
144 144 <a href="#">Run and Select Below</a></li>
145 145 <li id="run_cell_insert_below" title="Run this cell, insert below">
146 146 <a href="#">Run and Insert Below</a></li>
147 147 <li id="run_all_cells" title="Run all cells in the notebook">
148 148 <a href="#">Run All</a></li>
149 149 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
150 150 <a href="#">Run All Above</a></li>
151 151 <li id="run_all_cells_below" title="Run this cell and all cells below it">
152 152 <a href="#">Run All Below</a></li>
153 153 <li class="divider"></li>
154 154 <li id="change_cell_type" class="dropdown-submenu"
155 155 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
156 156 <a href="#">Cell Type</a>
157 157 <ul class="dropdown-menu">
158 158 <li id="to_code"
159 159 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
160 160 <a href="#">Code</a></li>
161 161 <li id="to_markdown"
162 162 title="Contents will be rendered as HTML and serve as explanatory text">
163 163 <a href="#">Markdown</a></li>
164 164 <li id="to_raw"
165 165 title="Contents will pass through nbconvert unmodified">
166 166 <a href="#">Raw NBConvert</a></li>
167 167 <li id="to_heading1"><a href="#">Heading 1</a></li>
168 168 <li id="to_heading2"><a href="#">Heading 2</a></li>
169 169 <li id="to_heading3"><a href="#">Heading 3</a></li>
170 170 <li id="to_heading4"><a href="#">Heading 4</a></li>
171 171 <li id="to_heading5"><a href="#">Heading 5</a></li>
172 172 <li id="to_heading6"><a href="#">Heading 6</a></li>
173 173 </ul>
174 174 </li>
175 175 <li class="divider"></li>
176 176 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
177 177 <ul class="dropdown-menu">
178 178 <li id="toggle_current_output"
179 179 title="Hide/Show the output of the current cell">
180 180 <a href="#">Toggle</a>
181 181 </li>
182 182 <li id="toggle_current_output_scroll"
183 183 title="Scroll the output of the current cell">
184 184 <a href="#">Toggle Scrolling</a>
185 185 </li>
186 186 <li id="clear_current_output"
187 187 title="Clear the output of the current cell">
188 188 <a href="#">Clear</a>
189 189 </li>
190 190 </ul>
191 191 </li>
192 192 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
193 193 <ul class="dropdown-menu">
194 194 <li id="toggle_all_output"
195 195 title="Hide/Show the output of all cells">
196 196 <a href="#">Toggle</a>
197 197 </li>
198 198 <li id="toggle_all_output_scroll"
199 199 title="Scroll the output of all cells">
200 200 <a href="#">Toggle Scrolling</a>
201 201 </li>
202 202 <li id="clear_all_output"
203 203 title="Clear the output of all cells">
204 204 <a href="#">Clear</a>
205 205 </li>
206 206 </ul>
207 207 </li>
208 208 </ul>
209 209 </li>
210 210 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
211 211 <ul id="kernel_menu" class="dropdown-menu">
212 212 <li id="int_kernel"
213 213 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
214 214 <a href="#">Interrupt</a></li>
215 215 <li id="restart_kernel"
216 216 title="Restart the Kernel">
217 217 <a href="#">Restart</a></li>
218 218 </ul>
219 219 </li>
220 220 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
221 221 <ul id="help_menu" class="dropdown-menu">
222 222 <li id="notebook_tour" title="A quick tour of the notebook user interface"><a href="#">User Interface Tour</a></li>
223 223 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
224 224 <li class="divider"></li>
225 225 {% set
226 226 sections = (
227 227 (
228 228 ("http://ipython.org/documentation.html","IPython Help",True),
229 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),
231 ("http://ipython.org/ipython-doc/dev/interactive/cm_keyboard.html","Editor Shortcuts",True),
230 ("http://ipython.org/ipython-doc/2/notebook/notebook.html","Notebook Help",True),
231 ("http://ipython.org/ipython-doc/2/notebook/cm_keyboard.html","Editor Shortcuts",True),
232 232 ),(
233 233 ("http://docs.python.org","Python",True),
234 234 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
235 235 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
236 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 238 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
239 239 )
240 240 )
241 241 %}
242 242
243 243 {% for helplinks in sections %}
244 244 {% for link in helplinks %}
245 245 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
246 246 {{'<i class="icon-external-link menu-icon pull-right"></i>' if link[2]}}
247 247 {{link[1]}}
248 248 </a></li>
249 249 {% endfor %}
250 250 {% if not loop.last %}
251 251 <li class="divider"></li>
252 252 {% endif %}
253 253 {% endfor %}
254 254 </li>
255 255 </ul>
256 256 </li>
257 257 </ul>
258 258 <div id="kernel_indicator" class="indicator_area pull-right">
259 259 <i id="kernel_indicator_icon"></i>
260 260 </div>
261 261 <div id="modal_indicator" class="indicator_area pull-right">
262 262 <i id="modal_indicator_icon"></i>
263 263 </div>
264 264 <div id="notification_area"></div>
265 265 </div>
266 266 </div>
267 267 </div>
268 268 </div>
269 269 <div id="maintoolbar" class="navbar">
270 270 <div class="toolbar-inner navbar-inner navbar-nobg">
271 271 <div id="maintoolbar-container" class="container"></div>
272 272 </div>
273 273 </div>
274 274 </div>
275 275
276 276 <div id="ipython-main-app">
277 277
278 278 <div id="notebook_panel">
279 279 <div id="notebook"></div>
280 280 <div id="pager_splitter"></div>
281 281 <div id="pager">
282 282 <div id='pager_button_area'>
283 283 </div>
284 284 <div id="pager-container" class="container"></div>
285 285 </div>
286 286 </div>
287 287
288 288 </div>
289 289 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
290 290
291 291
292 292 {% endblock %}
293 293
294 294
295 295 {% block script %}
296 296
297 297 {{super()}}
298 298
299 299 <script src="{{ static_url("components/google-caja/html-css-sanitizer-minified.js") }}" charset="utf-8"></script>
300 300 <script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
301 301 <script type="text/javascript">
302 302 CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js", include_version=False) }}";
303 303 </script>
304 304 <script src="{{ static_url("components/codemirror/addon/mode/loadmode.js") }}" charset="utf-8"></script>
305 305 <script src="{{ static_url("components/codemirror/addon/mode/multiplex.js") }}" charset="utf-8"></script>
306 306 <script src="{{ static_url("components/codemirror/addon/mode/overlay.js") }}" charset="utf-8"></script>
307 307 <script src="{{ static_url("components/codemirror/addon/edit/matchbrackets.js") }}" charset="utf-8"></script>
308 308 <script src="{{ static_url("components/codemirror/addon/edit/closebrackets.js") }}" charset="utf-8"></script>
309 309 <script src="{{ static_url("components/codemirror/addon/comment/comment.js") }}" charset="utf-8"></script>
310 310 <script src="{{ static_url("components/codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
311 311 <script src="{{ static_url("components/codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
312 312 <script src="{{ static_url("components/codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
313 313 <script src="{{ static_url("components/codemirror/mode/css/css.js") }}" charset="utf-8"></script>
314 314 <script src="{{ static_url("components/codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
315 315 <script src="{{ static_url("components/codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
316 316 <script src="{{ static_url("components/codemirror/mode/gfm/gfm.js") }}" charset="utf-8"></script>
317 317 <script src="{{ static_url("components/codemirror/mode/python/python.js") }}" charset="utf-8"></script>
318 318 <script src="{{ static_url("notebook/js/codemirror-ipython.js") }}" charset="utf-8"></script>
319 319
320 320 <script src="{{ static_url("components/highlight.js/build/highlight.pack.js") }}" charset="utf-8"></script>
321 321
322 322 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
323 323
324 324 <script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
325 325 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
326 326 <script src="{{ static_url("base/js/keyboard.js") }}" type="text/javascript" charset="utf-8"></script>
327 327 <script src="{{ static_url("base/js/security.js") }}" type="text/javascript" charset="utf-8"></script>
328 328 <script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
329 329 <script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
330 330 <script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
331 331 <script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
332 332 <script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
333 333 <script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
334 334 <script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
335 335 <script src="{{ static_url("notebook/js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
336 336 <script src="{{ static_url("notebook/js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
337 337 <script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
338 338 <script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
339 339 <script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
340 340 <script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
341 341 <script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
342 342 <script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
343 343 <script src="{{ static_url("notebook/js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
344 344 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
345 345 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
346 346 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
347 347 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
348 348 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
349 349 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
350 350 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
351 351 <script src="{{ static_url("notebook/js/tour.js") }}" type="text/javascript" charset="utf-8"></script>
352 352
353 353 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
354 354 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
355 355
356 356 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
357 357
358 358 <script src="{{ static_url("notebook/js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
359 359 <script src="{{ static_url("notebook/js/celltoolbarpresets/rawcell.js") }}" type="text/javascript" charset="utf-8"></script>
360 360 <script src="{{ static_url("notebook/js/celltoolbarpresets/slideshow.js") }}" type="text/javascript" charset="utf-8"></script>
361 361
362 362 {% endblock %}
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
1 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
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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
1 NO CONTENT: file was removed, binary diff hidden
1 NO CONTENT: file was removed, binary diff hidden
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
The requested commit or file is too big and content was truncated. Show full diff
1 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
1 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
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