##// END OF EJS Templates
Merge branch 'master' of github.com:ipython/ipython
Brian E. Granger -
r15980:8eca9149 merge
parent child Browse files
Show More
@@ -1,566 +1,552 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Cell
9 // Cell
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * An extendable module that provide base functionnality to create cell for notebook.
12 * An extendable module that provide base functionnality to create cell for notebook.
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule Cell
15 * @submodule Cell
16 */
16 */
17
17
18 var IPython = (function (IPython) {
18 var IPython = (function (IPython) {
19 "use strict";
19 "use strict";
20
20
21 var utils = IPython.utils;
21 var utils = IPython.utils;
22 var keycodes = IPython.keyboard.keycodes;
22 var keycodes = IPython.keyboard.keycodes;
23
23
24 /**
24 /**
25 * The Base `Cell` class from which to inherit
25 * The Base `Cell` class from which to inherit
26 * @class Cell
26 * @class Cell
27 **/
27 **/
28
28
29 /*
29 /*
30 * @constructor
30 * @constructor
31 *
31 *
32 * @param {object|undefined} [options]
32 * @param {object|undefined} [options]
33 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend default parameters
33 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend default parameters
34 */
34 */
35 var Cell = function (options) {
35 var Cell = function (options) {
36
36
37 options = this.mergeopt(Cell, options);
37 options = this.mergeopt(Cell, options);
38 // superclass default overwrite our default
38 // superclass default overwrite our default
39
39
40 this.placeholder = options.placeholder || '';
40 this.placeholder = options.placeholder || '';
41 this.read_only = options.cm_config.readOnly;
41 this.read_only = options.cm_config.readOnly;
42 this.selected = false;
42 this.selected = false;
43 this.rendered = false;
43 this.rendered = false;
44 this.mode = 'command';
44 this.mode = 'command';
45 this.metadata = {};
45 this.metadata = {};
46 // load this from metadata later ?
46 // load this from metadata later ?
47 this.user_highlight = 'auto';
47 this.user_highlight = 'auto';
48 this.cm_config = options.cm_config;
48 this.cm_config = options.cm_config;
49 this.cell_id = utils.uuid();
49 this.cell_id = utils.uuid();
50 this._options = options;
50 this._options = options;
51
51
52 // For JS VM engines optimization, attributes should be all set (even
52 // For JS VM engines optimization, attributes should be all set (even
53 // to null) in the constructor, and if possible, if different subclass
53 // to null) in the constructor, and if possible, if different subclass
54 // have new attributes with same name, they should be created in the
54 // have new attributes with same name, they should be created in the
55 // same order. Easiest is to create and set to null in parent class.
55 // same order. Easiest is to create and set to null in parent class.
56
56
57 this.element = null;
57 this.element = null;
58 this.cell_type = this.cell_type || null;
58 this.cell_type = this.cell_type || null;
59 this.code_mirror = null;
59 this.code_mirror = null;
60
60
61 this.create_element();
61 this.create_element();
62 if (this.element !== null) {
62 if (this.element !== null) {
63 this.element.data("cell", this);
63 this.element.data("cell", this);
64 this.bind_events();
64 this.bind_events();
65 this.init_classes();
65 this.init_classes();
66 }
66 }
67 };
67 };
68
68
69 Cell.options_default = {
69 Cell.options_default = {
70 cm_config : {
70 cm_config : {
71 indentUnit : 4,
71 indentUnit : 4,
72 readOnly: false,
72 readOnly: false,
73 theme: "default"
73 theme: "default"
74 }
74 }
75 };
75 };
76
76
77 // FIXME: Workaround CM Bug #332 (Safari segfault on drag)
77 // FIXME: Workaround CM Bug #332 (Safari segfault on drag)
78 // by disabling drag/drop altogether on Safari
78 // by disabling drag/drop altogether on Safari
79 // https://github.com/marijnh/CodeMirror/issues/332
79 // https://github.com/marijnh/CodeMirror/issues/332
80 if (utils.browser[0] == "Safari") {
80 if (utils.browser[0] == "Safari") {
81 Cell.options_default.cm_config.dragDrop = false;
81 Cell.options_default.cm_config.dragDrop = false;
82 }
82 }
83
83
84 Cell.prototype.mergeopt = function(_class, options, overwrite){
84 Cell.prototype.mergeopt = function(_class, options, overwrite){
85 options = options || {};
85 options = options || {};
86 overwrite = overwrite || {};
86 overwrite = overwrite || {};
87 return $.extend(true, {}, _class.options_default, options, overwrite);
87 return $.extend(true, {}, _class.options_default, options, overwrite);
88 };
88 };
89
89
90 /**
90 /**
91 * Empty. Subclasses must implement create_element.
91 * Empty. Subclasses must implement create_element.
92 * This should contain all the code to create the DOM element in notebook
92 * This should contain all the code to create the DOM element in notebook
93 * and will be called by Base Class constructor.
93 * and will be called by Base Class constructor.
94 * @method create_element
94 * @method create_element
95 */
95 */
96 Cell.prototype.create_element = function () {
96 Cell.prototype.create_element = function () {
97 };
97 };
98
98
99 Cell.prototype.init_classes = function () {
99 Cell.prototype.init_classes = function () {
100 // Call after this.element exists to initialize the css classes
100 // Call after this.element exists to initialize the css classes
101 // related to selected, rendered and mode.
101 // related to selected, rendered and mode.
102 if (this.selected) {
102 if (this.selected) {
103 this.element.addClass('selected');
103 this.element.addClass('selected');
104 } else {
104 } else {
105 this.element.addClass('unselected');
105 this.element.addClass('unselected');
106 }
106 }
107 if (this.rendered) {
107 if (this.rendered) {
108 this.element.addClass('rendered');
108 this.element.addClass('rendered');
109 } else {
109 } else {
110 this.element.addClass('unrendered');
110 this.element.addClass('unrendered');
111 }
111 }
112 if (this.mode === 'edit') {
112 if (this.mode === 'edit') {
113 this.element.addClass('edit_mode');
113 this.element.addClass('edit_mode');
114 } else {
114 } else {
115 this.element.addClass('command_mode');
115 this.element.addClass('command_mode');
116 }
116 }
117 };
117 };
118
118
119 /**
119 /**
120 * Subclasses can implement override bind_events.
120 * Subclasses can implement override bind_events.
121 * Be carefull to call the parent method when overwriting as it fires event.
121 * Be carefull to call the parent method when overwriting as it fires event.
122 * this will be triggerd after create_element in constructor.
122 * this will be triggerd after create_element in constructor.
123 * @method bind_events
123 * @method bind_events
124 */
124 */
125 Cell.prototype.bind_events = function () {
125 Cell.prototype.bind_events = function () {
126 var that = this;
126 var that = this;
127 // We trigger events so that Cell doesn't have to depend on Notebook.
127 // We trigger events so that Cell doesn't have to depend on Notebook.
128 that.element.click(function (event) {
128 that.element.click(function (event) {
129 if (!that.selected) {
129 if (!that.selected) {
130 $([IPython.events]).trigger('select.Cell', {'cell':that});
130 $([IPython.events]).trigger('select.Cell', {'cell':that});
131 }
131 }
132 });
132 });
133 that.element.focusin(function (event) {
133 that.element.focusin(function (event) {
134 if (!that.selected) {
134 if (!that.selected) {
135 $([IPython.events]).trigger('select.Cell', {'cell':that});
135 $([IPython.events]).trigger('select.Cell', {'cell':that});
136 }
136 }
137 });
137 });
138 if (this.code_mirror) {
138 if (this.code_mirror) {
139 this.code_mirror.on("change", function(cm, change) {
139 this.code_mirror.on("change", function(cm, change) {
140 $([IPython.events]).trigger("set_dirty.Notebook", {value: true});
140 $([IPython.events]).trigger("set_dirty.Notebook", {value: true});
141 });
141 });
142 }
142 }
143 if (this.code_mirror) {
143 if (this.code_mirror) {
144 this.code_mirror.on('focus', function(cm, change) {
144 this.code_mirror.on('focus', function(cm, change) {
145 $([IPython.events]).trigger('edit_mode.Cell', {cell: that});
145 $([IPython.events]).trigger('edit_mode.Cell', {cell: that});
146 });
146 });
147 }
147 }
148 if (this.code_mirror) {
148 if (this.code_mirror) {
149 this.code_mirror.on('blur', function(cm, change) {
149 this.code_mirror.on('blur', function(cm, change) {
150 // Check if this unfocus event is legit.
150 $([IPython.events]).trigger('command_mode.Cell', {cell: that});
151 if (!that.should_cancel_blur()) {
152 $([IPython.events]).trigger('command_mode.Cell', {cell: that});
153 }
154 });
151 });
155 }
152 }
156 };
153 };
157
154
158 /**
155 /**
159 * This method gets called in CodeMirror's onKeyDown/onKeyPress
156 * This method gets called in CodeMirror's onKeyDown/onKeyPress
160 * handlers and is used to provide custom key handling.
157 * handlers and is used to provide custom key handling.
161 *
158 *
162 * To have custom handling, subclasses should override this method, but still call it
159 * To have custom handling, subclasses should override this method, but still call it
163 * in order to process the Edit mode keyboard shortcuts.
160 * in order to process the Edit mode keyboard shortcuts.
164 *
161 *
165 * @method handle_codemirror_keyevent
162 * @method handle_codemirror_keyevent
166 * @param {CodeMirror} editor - The codemirror instance bound to the cell
163 * @param {CodeMirror} editor - The codemirror instance bound to the cell
167 * @param {event} event - key press event which either should or should not be handled by CodeMirror
164 * @param {event} event - key press event which either should or should not be handled by CodeMirror
168 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
165 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
169 */
166 */
170 Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
167 Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
171 var that = this;
168 var that = this;
172 var shortcuts = IPython.keyboard_manager.edit_shortcuts;
169 var shortcuts = IPython.keyboard_manager.edit_shortcuts;
173
170
174 // if this is an edit_shortcuts shortcut, the global keyboard/shortcut
171 // if this is an edit_shortcuts shortcut, the global keyboard/shortcut
175 // manager will handle it
172 // manager will handle it
176 if (shortcuts.handles(event)) { return true; }
173 if (shortcuts.handles(event)) { return true; }
177
174
178 return false;
175 return false;
179 };
176 };
180
177
181
178
182 /**
179 /**
183 * Triger typsetting of math by mathjax on current cell element
180 * Triger typsetting of math by mathjax on current cell element
184 * @method typeset
181 * @method typeset
185 */
182 */
186 Cell.prototype.typeset = function () {
183 Cell.prototype.typeset = function () {
187 if (window.MathJax) {
184 if (window.MathJax) {
188 var cell_math = this.element.get(0);
185 var cell_math = this.element.get(0);
189 MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
186 MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
190 }
187 }
191 };
188 };
192
189
193 /**
190 /**
194 * handle cell level logic when a cell is selected
191 * handle cell level logic when a cell is selected
195 * @method select
192 * @method select
196 * @return is the action being taken
193 * @return is the action being taken
197 */
194 */
198 Cell.prototype.select = function () {
195 Cell.prototype.select = function () {
199 if (!this.selected) {
196 if (!this.selected) {
200 this.element.addClass('selected');
197 this.element.addClass('selected');
201 this.element.removeClass('unselected');
198 this.element.removeClass('unselected');
202 this.selected = true;
199 this.selected = true;
203 return true;
200 return true;
204 } else {
201 } else {
205 return false;
202 return false;
206 }
203 }
207 };
204 };
208
205
209 /**
206 /**
210 * handle cell level logic when a cell is unselected
207 * handle cell level logic when a cell is unselected
211 * @method unselect
208 * @method unselect
212 * @return is the action being taken
209 * @return is the action being taken
213 */
210 */
214 Cell.prototype.unselect = function () {
211 Cell.prototype.unselect = function () {
215 if (this.selected) {
212 if (this.selected) {
216 this.element.addClass('unselected');
213 this.element.addClass('unselected');
217 this.element.removeClass('selected');
214 this.element.removeClass('selected');
218 this.selected = false;
215 this.selected = false;
219 return true;
216 return true;
220 } else {
217 } else {
221 return false;
218 return false;
222 }
219 }
223 };
220 };
224
221
225 /**
222 /**
226 * handle cell level logic when a cell is rendered
223 * handle cell level logic when a cell is rendered
227 * @method render
224 * @method render
228 * @return is the action being taken
225 * @return is the action being taken
229 */
226 */
230 Cell.prototype.render = function () {
227 Cell.prototype.render = function () {
231 if (!this.rendered) {
228 if (!this.rendered) {
232 this.element.addClass('rendered');
229 this.element.addClass('rendered');
233 this.element.removeClass('unrendered');
230 this.element.removeClass('unrendered');
234 this.rendered = true;
231 this.rendered = true;
235 return true;
232 return true;
236 } else {
233 } else {
237 return false;
234 return false;
238 }
235 }
239 };
236 };
240
237
241 /**
238 /**
242 * handle cell level logic when a cell is unrendered
239 * handle cell level logic when a cell is unrendered
243 * @method unrender
240 * @method unrender
244 * @return is the action being taken
241 * @return is the action being taken
245 */
242 */
246 Cell.prototype.unrender = function () {
243 Cell.prototype.unrender = function () {
247 if (this.rendered) {
244 if (this.rendered) {
248 this.element.addClass('unrendered');
245 this.element.addClass('unrendered');
249 this.element.removeClass('rendered');
246 this.element.removeClass('rendered');
250 this.rendered = false;
247 this.rendered = false;
251 return true;
248 return true;
252 } else {
249 } else {
253 return false;
250 return false;
254 }
251 }
255 };
252 };
256
253
257 /**
254 /**
258 * Delegates keyboard shortcut handling to either IPython keyboard
255 * Delegates keyboard shortcut handling to either IPython keyboard
259 * manager when in command mode, or CodeMirror when in edit mode
256 * manager when in command mode, or CodeMirror when in edit mode
260 *
257 *
261 * @method handle_keyevent
258 * @method handle_keyevent
262 * @param {CodeMirror} editor - The codemirror instance bound to the cell
259 * @param {CodeMirror} editor - The codemirror instance bound to the cell
263 * @param {event} - key event to be handled
260 * @param {event} - key event to be handled
264 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
261 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
265 */
262 */
266 Cell.prototype.handle_keyevent = function (editor, event) {
263 Cell.prototype.handle_keyevent = function (editor, event) {
267
264
268 // console.log('CM', this.mode, event.which, event.type)
265 // console.log('CM', this.mode, event.which, event.type)
269
266
270 if (this.mode === 'command') {
267 if (this.mode === 'command') {
271 return true;
268 return true;
272 } else if (this.mode === 'edit') {
269 } else if (this.mode === 'edit') {
273 return this.handle_codemirror_keyevent(editor, event);
270 return this.handle_codemirror_keyevent(editor, event);
274 }
271 }
275 };
272 };
276
273
277 /**
274 /**
278 * @method at_top
275 * @method at_top
279 * @return {Boolean}
276 * @return {Boolean}
280 */
277 */
281 Cell.prototype.at_top = function () {
278 Cell.prototype.at_top = function () {
282 var cm = this.code_mirror;
279 var cm = this.code_mirror;
283 var cursor = cm.getCursor();
280 var cursor = cm.getCursor();
284 if (cursor.line === 0 && cursor.ch === 0) {
281 if (cursor.line === 0 && cursor.ch === 0) {
285 return true;
282 return true;
286 }
283 }
287 return false;
284 return false;
288 };
285 };
289
286
290 /**
287 /**
291 * @method at_bottom
288 * @method at_bottom
292 * @return {Boolean}
289 * @return {Boolean}
293 * */
290 * */
294 Cell.prototype.at_bottom = function () {
291 Cell.prototype.at_bottom = function () {
295 var cm = this.code_mirror;
292 var cm = this.code_mirror;
296 var cursor = cm.getCursor();
293 var cursor = cm.getCursor();
297 if (cursor.line === (cm.lineCount()-1) && cursor.ch === cm.getLine(cursor.line).length) {
294 if (cursor.line === (cm.lineCount()-1) && cursor.ch === cm.getLine(cursor.line).length) {
298 return true;
295 return true;
299 }
296 }
300 return false;
297 return false;
301 };
298 };
302
299
303 /**
300 /**
304 * enter the command mode for the cell
301 * enter the command mode for the cell
305 * @method command_mode
302 * @method command_mode
306 * @return is the action being taken
303 * @return is the action being taken
307 */
304 */
308 Cell.prototype.command_mode = function () {
305 Cell.prototype.command_mode = function () {
309 if (this.mode !== 'command') {
306 if (this.mode !== 'command') {
310 this.element.addClass('command_mode');
307 this.element.addClass('command_mode');
311 this.element.removeClass('edit_mode');
308 this.element.removeClass('edit_mode');
312 this.mode = 'command';
309 this.mode = 'command';
313 return true;
310 return true;
314 } else {
311 } else {
315 return false;
312 return false;
316 }
313 }
317 };
314 };
318
315
319 /**
316 /**
320 * enter the edit mode for the cell
317 * enter the edit mode for the cell
321 * @method command_mode
318 * @method command_mode
322 * @return is the action being taken
319 * @return is the action being taken
323 */
320 */
324 Cell.prototype.edit_mode = function () {
321 Cell.prototype.edit_mode = function () {
325 if (this.mode !== 'edit') {
322 if (this.mode !== 'edit') {
326 this.element.addClass('edit_mode');
323 this.element.addClass('edit_mode');
327 this.element.removeClass('command_mode');
324 this.element.removeClass('command_mode');
328 this.mode = 'edit';
325 this.mode = 'edit';
329 return true;
326 return true;
330 } else {
327 } else {
331 return false;
328 return false;
332 }
329 }
333 };
330 };
334
331
335 /**
336 * Determine whether or not the unfocus event should be aknowledged.
337 *
338 * @method should_cancel_blur
339 *
340 * @return results {bool} Whether or not to ignore the cell's blur event.
341 **/
342 Cell.prototype.should_cancel_blur = function () {
343 return false;
344 };
345
346 /**
332 /**
347 * Focus the cell in the DOM sense
333 * Focus the cell in the DOM sense
348 * @method focus_cell
334 * @method focus_cell
349 */
335 */
350 Cell.prototype.focus_cell = function () {
336 Cell.prototype.focus_cell = function () {
351 this.element.focus();
337 this.element.focus();
352 };
338 };
353
339
354 /**
340 /**
355 * Focus the editor area so a user can type
341 * Focus the editor area so a user can type
356 *
342 *
357 * NOTE: If codemirror is focused via a mouse click event, you don't want to
343 * NOTE: If codemirror is focused via a mouse click event, you don't want to
358 * call this because it will cause a page jump.
344 * call this because it will cause a page jump.
359 * @method focus_editor
345 * @method focus_editor
360 */
346 */
361 Cell.prototype.focus_editor = function () {
347 Cell.prototype.focus_editor = function () {
362 this.refresh();
348 this.refresh();
363 this.code_mirror.focus();
349 this.code_mirror.focus();
364 };
350 };
365
351
366 /**
352 /**
367 * Refresh codemirror instance
353 * Refresh codemirror instance
368 * @method refresh
354 * @method refresh
369 */
355 */
370 Cell.prototype.refresh = function () {
356 Cell.prototype.refresh = function () {
371 this.code_mirror.refresh();
357 this.code_mirror.refresh();
372 };
358 };
373
359
374 /**
360 /**
375 * should be overritten by subclass
361 * should be overritten by subclass
376 * @method get_text
362 * @method get_text
377 */
363 */
378 Cell.prototype.get_text = function () {
364 Cell.prototype.get_text = function () {
379 };
365 };
380
366
381 /**
367 /**
382 * should be overritten by subclass
368 * should be overritten by subclass
383 * @method set_text
369 * @method set_text
384 * @param {string} text
370 * @param {string} text
385 */
371 */
386 Cell.prototype.set_text = function (text) {
372 Cell.prototype.set_text = function (text) {
387 };
373 };
388
374
389 /**
375 /**
390 * should be overritten by subclass
376 * should be overritten by subclass
391 * serialise cell to json.
377 * serialise cell to json.
392 * @method toJSON
378 * @method toJSON
393 **/
379 **/
394 Cell.prototype.toJSON = function () {
380 Cell.prototype.toJSON = function () {
395 var data = {};
381 var data = {};
396 data.metadata = this.metadata;
382 data.metadata = this.metadata;
397 data.cell_type = this.cell_type;
383 data.cell_type = this.cell_type;
398 return data;
384 return data;
399 };
385 };
400
386
401
387
402 /**
388 /**
403 * should be overritten by subclass
389 * should be overritten by subclass
404 * @method fromJSON
390 * @method fromJSON
405 **/
391 **/
406 Cell.prototype.fromJSON = function (data) {
392 Cell.prototype.fromJSON = function (data) {
407 if (data.metadata !== undefined) {
393 if (data.metadata !== undefined) {
408 this.metadata = data.metadata;
394 this.metadata = data.metadata;
409 }
395 }
410 this.celltoolbar.rebuild();
396 this.celltoolbar.rebuild();
411 };
397 };
412
398
413
399
414 /**
400 /**
415 * can the cell be split into two cells
401 * can the cell be split into two cells
416 * @method is_splittable
402 * @method is_splittable
417 **/
403 **/
418 Cell.prototype.is_splittable = function () {
404 Cell.prototype.is_splittable = function () {
419 return true;
405 return true;
420 };
406 };
421
407
422
408
423 /**
409 /**
424 * can the cell be merged with other cells
410 * can the cell be merged with other cells
425 * @method is_mergeable
411 * @method is_mergeable
426 **/
412 **/
427 Cell.prototype.is_mergeable = function () {
413 Cell.prototype.is_mergeable = function () {
428 return true;
414 return true;
429 };
415 };
430
416
431
417
432 /**
418 /**
433 * @return {String} - the text before the cursor
419 * @return {String} - the text before the cursor
434 * @method get_pre_cursor
420 * @method get_pre_cursor
435 **/
421 **/
436 Cell.prototype.get_pre_cursor = function () {
422 Cell.prototype.get_pre_cursor = function () {
437 var cursor = this.code_mirror.getCursor();
423 var cursor = this.code_mirror.getCursor();
438 var text = this.code_mirror.getRange({line:0, ch:0}, cursor);
424 var text = this.code_mirror.getRange({line:0, ch:0}, cursor);
439 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
425 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
440 return text;
426 return text;
441 };
427 };
442
428
443
429
444 /**
430 /**
445 * @return {String} - the text after the cursor
431 * @return {String} - the text after the cursor
446 * @method get_post_cursor
432 * @method get_post_cursor
447 **/
433 **/
448 Cell.prototype.get_post_cursor = function () {
434 Cell.prototype.get_post_cursor = function () {
449 var cursor = this.code_mirror.getCursor();
435 var cursor = this.code_mirror.getCursor();
450 var last_line_num = this.code_mirror.lineCount()-1;
436 var last_line_num = this.code_mirror.lineCount()-1;
451 var last_line_len = this.code_mirror.getLine(last_line_num).length;
437 var last_line_len = this.code_mirror.getLine(last_line_num).length;
452 var end = {line:last_line_num, ch:last_line_len};
438 var end = {line:last_line_num, ch:last_line_len};
453 var text = this.code_mirror.getRange(cursor, end);
439 var text = this.code_mirror.getRange(cursor, end);
454 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
440 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
455 return text;
441 return text;
456 };
442 };
457
443
458 /**
444 /**
459 * Show/Hide CodeMirror LineNumber
445 * Show/Hide CodeMirror LineNumber
460 * @method show_line_numbers
446 * @method show_line_numbers
461 *
447 *
462 * @param value {Bool} show (true), or hide (false) the line number in CodeMirror
448 * @param value {Bool} show (true), or hide (false) the line number in CodeMirror
463 **/
449 **/
464 Cell.prototype.show_line_numbers = function (value) {
450 Cell.prototype.show_line_numbers = function (value) {
465 this.code_mirror.setOption('lineNumbers', value);
451 this.code_mirror.setOption('lineNumbers', value);
466 this.code_mirror.refresh();
452 this.code_mirror.refresh();
467 };
453 };
468
454
469 /**
455 /**
470 * Toggle CodeMirror LineNumber
456 * Toggle CodeMirror LineNumber
471 * @method toggle_line_numbers
457 * @method toggle_line_numbers
472 **/
458 **/
473 Cell.prototype.toggle_line_numbers = function () {
459 Cell.prototype.toggle_line_numbers = function () {
474 var val = this.code_mirror.getOption('lineNumbers');
460 var val = this.code_mirror.getOption('lineNumbers');
475 this.show_line_numbers(!val);
461 this.show_line_numbers(!val);
476 };
462 };
477
463
478 /**
464 /**
479 * Force codemirror highlight mode
465 * Force codemirror highlight mode
480 * @method force_highlight
466 * @method force_highlight
481 * @param {object} - CodeMirror mode
467 * @param {object} - CodeMirror mode
482 **/
468 **/
483 Cell.prototype.force_highlight = function(mode) {
469 Cell.prototype.force_highlight = function(mode) {
484 this.user_highlight = mode;
470 this.user_highlight = mode;
485 this.auto_highlight();
471 this.auto_highlight();
486 };
472 };
487
473
488 /**
474 /**
489 * Try to autodetect cell highlight mode, or use selected mode
475 * Try to autodetect cell highlight mode, or use selected mode
490 * @methods _auto_highlight
476 * @methods _auto_highlight
491 * @private
477 * @private
492 * @param {String|object|undefined} - CodeMirror mode | 'auto'
478 * @param {String|object|undefined} - CodeMirror mode | 'auto'
493 **/
479 **/
494 Cell.prototype._auto_highlight = function (modes) {
480 Cell.prototype._auto_highlight = function (modes) {
495 //Here we handle manually selected modes
481 //Here we handle manually selected modes
496 var mode;
482 var mode;
497 if( this.user_highlight !== undefined && this.user_highlight != 'auto' )
483 if( this.user_highlight !== undefined && this.user_highlight != 'auto' )
498 {
484 {
499 mode = this.user_highlight;
485 mode = this.user_highlight;
500 CodeMirror.autoLoadMode(this.code_mirror, mode);
486 CodeMirror.autoLoadMode(this.code_mirror, mode);
501 this.code_mirror.setOption('mode', mode);
487 this.code_mirror.setOption('mode', mode);
502 return;
488 return;
503 }
489 }
504 var current_mode = this.code_mirror.getOption('mode', mode);
490 var current_mode = this.code_mirror.getOption('mode', mode);
505 var first_line = this.code_mirror.getLine(0);
491 var first_line = this.code_mirror.getLine(0);
506 // loop on every pairs
492 // loop on every pairs
507 for(mode in modes) {
493 for(mode in modes) {
508 var regs = modes[mode].reg;
494 var regs = modes[mode].reg;
509 // only one key every time but regexp can't be keys...
495 // only one key every time but regexp can't be keys...
510 for(var i=0; i<regs.length; i++) {
496 for(var i=0; i<regs.length; i++) {
511 // here we handle non magic_modes
497 // here we handle non magic_modes
512 if(first_line.match(regs[i]) !== null) {
498 if(first_line.match(regs[i]) !== null) {
513 if(current_mode == mode){
499 if(current_mode == mode){
514 return;
500 return;
515 }
501 }
516 if (mode.search('magic_') !== 0) {
502 if (mode.search('magic_') !== 0) {
517 this.code_mirror.setOption('mode', mode);
503 this.code_mirror.setOption('mode', mode);
518 CodeMirror.autoLoadMode(this.code_mirror, mode);
504 CodeMirror.autoLoadMode(this.code_mirror, mode);
519 return;
505 return;
520 }
506 }
521 var open = modes[mode].open || "%%";
507 var open = modes[mode].open || "%%";
522 var close = modes[mode].close || "%%end";
508 var close = modes[mode].close || "%%end";
523 var mmode = mode;
509 var mmode = mode;
524 mode = mmode.substr(6);
510 mode = mmode.substr(6);
525 if(current_mode == mode){
511 if(current_mode == mode){
526 return;
512 return;
527 }
513 }
528 CodeMirror.autoLoadMode(this.code_mirror, mode);
514 CodeMirror.autoLoadMode(this.code_mirror, mode);
529 // create on the fly a mode that swhitch between
515 // create on the fly a mode that swhitch between
530 // plain/text and smth else otherwise `%%` is
516 // plain/text and smth else otherwise `%%` is
531 // source of some highlight issues.
517 // source of some highlight issues.
532 // we use patchedGetMode to circumvent a bug in CM
518 // we use patchedGetMode to circumvent a bug in CM
533 CodeMirror.defineMode(mmode , function(config) {
519 CodeMirror.defineMode(mmode , function(config) {
534 return CodeMirror.multiplexingMode(
520 return CodeMirror.multiplexingMode(
535 CodeMirror.patchedGetMode(config, 'text/plain'),
521 CodeMirror.patchedGetMode(config, 'text/plain'),
536 // always set someting on close
522 // always set someting on close
537 {open: open, close: close,
523 {open: open, close: close,
538 mode: CodeMirror.patchedGetMode(config, mode),
524 mode: CodeMirror.patchedGetMode(config, mode),
539 delimStyle: "delimit"
525 delimStyle: "delimit"
540 }
526 }
541 );
527 );
542 });
528 });
543 this.code_mirror.setOption('mode', mmode);
529 this.code_mirror.setOption('mode', mmode);
544 return;
530 return;
545 }
531 }
546 }
532 }
547 }
533 }
548 // fallback on default
534 // fallback on default
549 var default_mode;
535 var default_mode;
550 try {
536 try {
551 default_mode = this._options.cm_config.mode;
537 default_mode = this._options.cm_config.mode;
552 } catch(e) {
538 } catch(e) {
553 default_mode = 'text/plain';
539 default_mode = 'text/plain';
554 }
540 }
555 if( current_mode === default_mode){
541 if( current_mode === default_mode){
556 return;
542 return;
557 }
543 }
558 this.code_mirror.setOption('mode', default_mode);
544 this.code_mirror.setOption('mode', default_mode);
559 };
545 };
560
546
561 IPython.Cell = Cell;
547 IPython.Cell = Cell;
562
548
563 return IPython;
549 return IPython;
564
550
565 }(IPython));
551 }(IPython));
566
552
@@ -1,515 +1,517 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // CodeCell
9 // CodeCell
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * An extendable module that provide base functionnality to create cell for notebook.
12 * An extendable module that provide base functionnality to create cell for notebook.
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule CodeCell
15 * @submodule CodeCell
16 */
16 */
17
17
18
18
19 /* local util for codemirror */
19 /* local util for codemirror */
20 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
20 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
21
21
22 /**
22 /**
23 *
23 *
24 * function to delete until previous non blanking space character
24 * function to delete until previous non blanking space character
25 * or first multiple of 4 tabstop.
25 * or first multiple of 4 tabstop.
26 * @private
26 * @private
27 */
27 */
28 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
28 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
29 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
29 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
30 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
30 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
31 var cur = cm.getCursor(), line = cm.getLine(cur.line);
31 var cur = cm.getCursor(), line = cm.getLine(cur.line);
32 var tabsize = cm.getOption('tabSize');
32 var tabsize = cm.getOption('tabSize');
33 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
33 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
34 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
34 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
35 var select = cm.getRange(from,cur);
35 var select = cm.getRange(from,cur);
36 if( select.match(/^\ +$/) !== null){
36 if( select.match(/^\ +$/) !== null){
37 cm.replaceRange("",from,cur);
37 cm.replaceRange("",from,cur);
38 } else {
38 } else {
39 cm.deleteH(-1,"char");
39 cm.deleteH(-1,"char");
40 }
40 }
41 };
41 };
42
42
43
43
44 var IPython = (function (IPython) {
44 var IPython = (function (IPython) {
45 "use strict";
45 "use strict";
46
46
47 var utils = IPython.utils;
47 var utils = IPython.utils;
48 var keycodes = IPython.keyboard.keycodes;
48 var keycodes = IPython.keyboard.keycodes;
49
49
50 /**
50 /**
51 * A Cell conceived to write code.
51 * A Cell conceived to write code.
52 *
52 *
53 * The kernel doesn't have to be set at creation time, in that case
53 * The kernel doesn't have to be set at creation time, in that case
54 * it will be null and set_kernel has to be called later.
54 * it will be null and set_kernel has to be called later.
55 * @class CodeCell
55 * @class CodeCell
56 * @extends IPython.Cell
56 * @extends IPython.Cell
57 *
57 *
58 * @constructor
58 * @constructor
59 * @param {Object|null} kernel
59 * @param {Object|null} kernel
60 * @param {object|undefined} [options]
60 * @param {object|undefined} [options]
61 * @param [options.cm_config] {object} config to pass to CodeMirror
61 * @param [options.cm_config] {object} config to pass to CodeMirror
62 */
62 */
63 var CodeCell = function (kernel, options) {
63 var CodeCell = function (kernel, options) {
64 this.kernel = kernel || null;
64 this.kernel = kernel || null;
65 this.collapsed = false;
65 this.collapsed = false;
66
66
67 // create all attributed in constructor function
67 // create all attributed in constructor function
68 // even if null for V8 VM optimisation
68 // even if null for V8 VM optimisation
69 this.input_prompt_number = null;
69 this.input_prompt_number = null;
70 this.celltoolbar = null;
70 this.celltoolbar = null;
71 this.output_area = null;
71 this.output_area = null;
72 this.last_msg_id = null;
72 this.last_msg_id = null;
73 this.completer = null;
73 this.completer = null;
74
74
75
75
76 var cm_overwrite_options = {
76 var cm_overwrite_options = {
77 onKeyEvent: $.proxy(this.handle_keyevent,this)
77 onKeyEvent: $.proxy(this.handle_keyevent,this)
78 };
78 };
79
79
80 options = this.mergeopt(CodeCell, options, {cm_config:cm_overwrite_options});
80 options = this.mergeopt(CodeCell, options, {cm_config:cm_overwrite_options});
81
81
82 IPython.Cell.apply(this,[options]);
82 IPython.Cell.apply(this,[options]);
83
83
84 // Attributes we want to override in this subclass.
84 // Attributes we want to override in this subclass.
85 this.cell_type = "code";
85 this.cell_type = "code";
86
86
87 var that = this;
87 var that = this;
88 this.element.focusout(
88 this.element.focusout(
89 function() { that.auto_highlight(); }
89 function() { that.auto_highlight(); }
90 );
90 );
91 };
91 };
92
92
93 CodeCell.options_default = {
93 CodeCell.options_default = {
94 cm_config : {
94 cm_config : {
95 extraKeys: {
95 extraKeys: {
96 "Tab" : "indentMore",
96 "Tab" : "indentMore",
97 "Shift-Tab" : "indentLess",
97 "Shift-Tab" : "indentLess",
98 "Backspace" : "delSpaceToPrevTabStop",
98 "Backspace" : "delSpaceToPrevTabStop",
99 "Cmd-/" : "toggleComment",
99 "Cmd-/" : "toggleComment",
100 "Ctrl-/" : "toggleComment"
100 "Ctrl-/" : "toggleComment"
101 },
101 },
102 mode: 'ipython',
102 mode: 'ipython',
103 theme: 'ipython',
103 theme: 'ipython',
104 matchBrackets: true,
104 matchBrackets: true,
105 // don't auto-close strings because of CodeMirror #2385
105 // don't auto-close strings because of CodeMirror #2385
106 autoCloseBrackets: "()[]{}"
106 autoCloseBrackets: "()[]{}"
107 }
107 }
108 };
108 };
109
109
110 CodeCell.msg_cells = {};
110 CodeCell.msg_cells = {};
111
111
112 CodeCell.prototype = new IPython.Cell();
112 CodeCell.prototype = new IPython.Cell();
113
113
114 /**
114 /**
115 * @method auto_highlight
115 * @method auto_highlight
116 */
116 */
117 CodeCell.prototype.auto_highlight = function () {
117 CodeCell.prototype.auto_highlight = function () {
118 this._auto_highlight(IPython.config.cell_magic_highlight);
118 this._auto_highlight(IPython.config.cell_magic_highlight);
119 };
119 };
120
120
121 /** @method create_element */
121 /** @method create_element */
122 CodeCell.prototype.create_element = function () {
122 CodeCell.prototype.create_element = function () {
123 IPython.Cell.prototype.create_element.apply(this, arguments);
123 IPython.Cell.prototype.create_element.apply(this, arguments);
124
124
125 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell');
125 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell');
126 cell.attr('tabindex','2');
126 cell.attr('tabindex','2');
127
127
128 var input = $('<div></div>').addClass('input');
128 var input = $('<div></div>').addClass('input');
129 var prompt = $('<div/>').addClass('prompt input_prompt');
129 var prompt = $('<div/>').addClass('prompt input_prompt');
130 var inner_cell = $('<div/>').addClass('inner_cell');
130 var inner_cell = $('<div/>').addClass('inner_cell');
131 this.celltoolbar = new IPython.CellToolbar(this);
131 this.celltoolbar = new IPython.CellToolbar(this);
132 inner_cell.append(this.celltoolbar.element);
132 inner_cell.append(this.celltoolbar.element);
133 var input_area = $('<div/>').addClass('input_area');
133 var input_area = $('<div/>').addClass('input_area');
134 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
134 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
135 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
135 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
136 inner_cell.append(input_area);
136 inner_cell.append(input_area);
137 input.append(prompt).append(inner_cell);
137 input.append(prompt).append(inner_cell);
138
138
139 var widget_area = $('<div/>')
139 var widget_area = $('<div/>')
140 .addClass('widget-area')
140 .addClass('widget-area')
141 .hide();
141 .hide();
142 this.widget_area = widget_area;
142 this.widget_area = widget_area;
143 var widget_prompt = $('<div/>')
143 var widget_prompt = $('<div/>')
144 .addClass('prompt')
144 .addClass('prompt')
145 .appendTo(widget_area);
145 .appendTo(widget_area);
146 var widget_subarea = $('<div/>')
146 var widget_subarea = $('<div/>')
147 .addClass('widget-subarea')
147 .addClass('widget-subarea')
148 .appendTo(widget_area);
148 .appendTo(widget_area);
149 this.widget_subarea = widget_subarea;
149 this.widget_subarea = widget_subarea;
150 var widget_clear_buton = $('<button />')
150 var widget_clear_buton = $('<button />')
151 .addClass('close')
151 .addClass('close')
152 .html('&times;')
152 .html('&times;')
153 .click(function() {
153 .click(function() {
154 widget_area.slideUp('', function(){ widget_subarea.html(''); });
154 widget_area.slideUp('', function(){ widget_subarea.html(''); });
155 })
155 })
156 .appendTo(widget_prompt);
156 .appendTo(widget_prompt);
157
157
158 var output = $('<div></div>');
158 var output = $('<div></div>');
159 cell.append(input).append(widget_area).append(output);
159 cell.append(input).append(widget_area).append(output);
160 this.element = cell;
160 this.element = cell;
161 this.output_area = new IPython.OutputArea(output, true);
161 this.output_area = new IPython.OutputArea(output, true);
162 this.completer = new IPython.Completer(this);
162 this.completer = new IPython.Completer(this);
163 };
163 };
164
164
165 /** @method bind_events */
165 /** @method bind_events */
166 CodeCell.prototype.bind_events = function () {
166 CodeCell.prototype.bind_events = function () {
167 IPython.Cell.prototype.bind_events.apply(this);
167 IPython.Cell.prototype.bind_events.apply(this);
168 var that = this;
168 var that = this;
169
169
170 this.element.focusout(
170 this.element.focusout(
171 function() { that.auto_highlight(); }
171 function() { that.auto_highlight(); }
172 );
172 );
173 };
173 };
174
174
175
175
176 /**
176 /**
177 * This method gets called in CodeMirror's onKeyDown/onKeyPress
177 * This method gets called in CodeMirror's onKeyDown/onKeyPress
178 * handlers and is used to provide custom key handling. Its return
178 * handlers and is used to provide custom key handling. Its return
179 * value is used to determine if CodeMirror should ignore the event:
179 * value is used to determine if CodeMirror should ignore the event:
180 * true = ignore, false = don't ignore.
180 * true = ignore, false = don't ignore.
181 * @method handle_codemirror_keyevent
181 * @method handle_codemirror_keyevent
182 */
182 */
183 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
183 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
184
184
185 var that = this;
185 var that = this;
186 // whatever key is pressed, first, cancel the tooltip request before
186 // whatever key is pressed, first, cancel the tooltip request before
187 // they are sent, and remove tooltip if any, except for tab again
187 // they are sent, and remove tooltip if any, except for tab again
188 var tooltip_closed = null;
188 var tooltip_closed = null;
189 if (event.type === 'keydown' && event.which != keycodes.tab ) {
189 if (event.type === 'keydown' && event.which != keycodes.tab ) {
190 tooltip_closed = IPython.tooltip.remove_and_cancel_tooltip();
190 tooltip_closed = IPython.tooltip.remove_and_cancel_tooltip();
191 }
191 }
192
192
193 var cur = editor.getCursor();
193 var cur = editor.getCursor();
194 if (event.keyCode === keycodes.enter){
194 if (event.keyCode === keycodes.enter){
195 this.auto_highlight();
195 this.auto_highlight();
196 }
196 }
197
197
198 if (event.which === keycodes.down && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
198 if (event.which === keycodes.down && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
199 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
199 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
200 // browser and keyboard layout !
200 // browser and keyboard layout !
201 // Pressing '(' , request tooltip, don't forget to reappend it
201 // Pressing '(' , request tooltip, don't forget to reappend it
202 // The second argument says to hide the tooltip if the docstring
202 // The second argument says to hide the tooltip if the docstring
203 // is actually empty
203 // is actually empty
204 IPython.tooltip.pending(that, true);
204 IPython.tooltip.pending(that, true);
205 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
205 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
206 // If tooltip is active, cancel it. The call to
206 // If tooltip is active, cancel it. The call to
207 // remove_and_cancel_tooltip above doesn't pass, force=true.
207 // remove_and_cancel_tooltip above doesn't pass, force=true.
208 // Because of this it won't actually close the tooltip
208 // Because of this it won't actually close the tooltip
209 // if it is in sticky mode. Thus, we have to check again if it is open
209 // if it is in sticky mode. Thus, we have to check again if it is open
210 // and close it with force=true.
210 // and close it with force=true.
211 if (!IPython.tooltip._hidden) {
211 if (!IPython.tooltip._hidden) {
212 IPython.tooltip.remove_and_cancel_tooltip(true);
212 IPython.tooltip.remove_and_cancel_tooltip(true);
213 }
213 }
214 // If we closed the tooltip, don't let CM or the global handlers
214 // If we closed the tooltip, don't let CM or the global handlers
215 // handle this event.
215 // handle this event.
216 event.stop();
216 event.stop();
217 return true;
217 return true;
218 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
218 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
219 if (editor.somethingSelected()){
219 if (editor.somethingSelected()){
220 var anchor = editor.getCursor("anchor");
220 var anchor = editor.getCursor("anchor");
221 var head = editor.getCursor("head");
221 var head = editor.getCursor("head");
222 if( anchor.line != head.line){
222 if( anchor.line != head.line){
223 return false;
223 return false;
224 }
224 }
225 }
225 }
226 IPython.tooltip.request(that);
226 IPython.tooltip.request(that);
227 event.stop();
227 event.stop();
228 return true;
228 return true;
229 } else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
229 } else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
230 // Tab completion.
230 // Tab completion.
231 IPython.tooltip.remove_and_cancel_tooltip();
231 IPython.tooltip.remove_and_cancel_tooltip();
232 if (editor.somethingSelected()) {
232 if (editor.somethingSelected()) {
233 return false;
233 return false;
234 }
234 }
235 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
235 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
236 if (pre_cursor.trim() === "") {
236 if (pre_cursor.trim() === "") {
237 // Don't autocomplete if the part of the line before the cursor
237 // Don't autocomplete if the part of the line before the cursor
238 // is empty. In this case, let CodeMirror handle indentation.
238 // is empty. In this case, let CodeMirror handle indentation.
239 return false;
239 return false;
240 } else {
240 } else {
241 event.stop();
241 event.stop();
242 this.completer.startCompletion();
242 this.completer.startCompletion();
243 return true;
243 return true;
244 }
244 }
245 }
245 }
246
246
247 // keyboard event wasn't one of those unique to code cells, let's see
247 // keyboard event wasn't one of those unique to code cells, let's see
248 // if it's one of the generic ones (i.e. check edit mode shortcuts)
248 // if it's one of the generic ones (i.e. check edit mode shortcuts)
249 return IPython.Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
249 return IPython.Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
250 };
250 };
251
251
252 // Kernel related calls.
252 // Kernel related calls.
253
253
254 CodeCell.prototype.set_kernel = function (kernel) {
254 CodeCell.prototype.set_kernel = function (kernel) {
255 this.kernel = kernel;
255 this.kernel = kernel;
256 };
256 };
257
257
258 /**
258 /**
259 * Execute current code cell to the kernel
259 * Execute current code cell to the kernel
260 * @method execute
260 * @method execute
261 */
261 */
262 CodeCell.prototype.execute = function () {
262 CodeCell.prototype.execute = function () {
263 this.output_area.clear_output();
263 this.output_area.clear_output();
264
264
265 // Clear widget area
265 // Clear widget area
266 this.widget_subarea.html('');
266 this.widget_subarea.html('');
267 this.widget_subarea.height('');
267 this.widget_subarea.height('');
268 this.widget_area.height('');
268 this.widget_area.height('');
269 this.widget_area.hide();
269 this.widget_area.hide();
270
270
271 this.set_input_prompt('*');
271 this.set_input_prompt('*');
272 this.element.addClass("running");
272 this.element.addClass("running");
273 if (this.last_msg_id) {
273 if (this.last_msg_id) {
274 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
274 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
275 }
275 }
276 var callbacks = this.get_callbacks();
276 var callbacks = this.get_callbacks();
277
277
278 var old_msg_id = this.last_msg_id;
278 var old_msg_id = this.last_msg_id;
279 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
279 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
280 if (old_msg_id) {
280 if (old_msg_id) {
281 delete CodeCell.msg_cells[old_msg_id];
281 delete CodeCell.msg_cells[old_msg_id];
282 }
282 }
283 CodeCell.msg_cells[this.last_msg_id] = this;
283 CodeCell.msg_cells[this.last_msg_id] = this;
284 };
284 };
285
285
286 /**
286 /**
287 * Construct the default callbacks for
287 * Construct the default callbacks for
288 * @method get_callbacks
288 * @method get_callbacks
289 */
289 */
290 CodeCell.prototype.get_callbacks = function () {
290 CodeCell.prototype.get_callbacks = function () {
291 return {
291 return {
292 shell : {
292 shell : {
293 reply : $.proxy(this._handle_execute_reply, this),
293 reply : $.proxy(this._handle_execute_reply, this),
294 payload : {
294 payload : {
295 set_next_input : $.proxy(this._handle_set_next_input, this),
295 set_next_input : $.proxy(this._handle_set_next_input, this),
296 page : $.proxy(this._open_with_pager, this)
296 page : $.proxy(this._open_with_pager, this)
297 }
297 }
298 },
298 },
299 iopub : {
299 iopub : {
300 output : $.proxy(this.output_area.handle_output, this.output_area),
300 output : $.proxy(this.output_area.handle_output, this.output_area),
301 clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area),
301 clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area),
302 },
302 },
303 input : $.proxy(this._handle_input_request, this)
303 input : $.proxy(this._handle_input_request, this)
304 };
304 };
305 };
305 };
306
306
307 CodeCell.prototype._open_with_pager = function (payload) {
307 CodeCell.prototype._open_with_pager = function (payload) {
308 $([IPython.events]).trigger('open_with_text.Pager', payload);
308 $([IPython.events]).trigger('open_with_text.Pager', payload);
309 };
309 };
310
310
311 /**
311 /**
312 * @method _handle_execute_reply
312 * @method _handle_execute_reply
313 * @private
313 * @private
314 */
314 */
315 CodeCell.prototype._handle_execute_reply = function (msg) {
315 CodeCell.prototype._handle_execute_reply = function (msg) {
316 this.set_input_prompt(msg.content.execution_count);
316 this.set_input_prompt(msg.content.execution_count);
317 this.element.removeClass("running");
317 this.element.removeClass("running");
318 $([IPython.events]).trigger('set_dirty.Notebook', {value: true});
318 $([IPython.events]).trigger('set_dirty.Notebook', {value: true});
319 };
319 };
320
320
321 /**
321 /**
322 * @method _handle_set_next_input
322 * @method _handle_set_next_input
323 * @private
323 * @private
324 */
324 */
325 CodeCell.prototype._handle_set_next_input = function (payload) {
325 CodeCell.prototype._handle_set_next_input = function (payload) {
326 var data = {'cell': this, 'text': payload.text};
326 var data = {'cell': this, 'text': payload.text};
327 $([IPython.events]).trigger('set_next_input.Notebook', data);
327 $([IPython.events]).trigger('set_next_input.Notebook', data);
328 };
328 };
329
329
330 /**
330 /**
331 * @method _handle_input_request
331 * @method _handle_input_request
332 * @private
332 * @private
333 */
333 */
334 CodeCell.prototype._handle_input_request = function (msg) {
334 CodeCell.prototype._handle_input_request = function (msg) {
335 this.output_area.append_raw_input(msg);
335 this.output_area.append_raw_input(msg);
336 };
336 };
337
337
338
338
339 // Basic cell manipulation.
339 // Basic cell manipulation.
340
340
341 CodeCell.prototype.select = function () {
341 CodeCell.prototype.select = function () {
342 var cont = IPython.Cell.prototype.select.apply(this);
342 var cont = IPython.Cell.prototype.select.apply(this);
343 if (cont) {
343 if (cont) {
344 this.code_mirror.refresh();
344 this.code_mirror.refresh();
345 this.auto_highlight();
345 this.auto_highlight();
346 }
346 }
347 return cont;
347 return cont;
348 };
348 };
349
349
350 CodeCell.prototype.render = function () {
350 CodeCell.prototype.render = function () {
351 var cont = IPython.Cell.prototype.render.apply(this);
351 var cont = IPython.Cell.prototype.render.apply(this);
352 // Always execute, even if we are already in the rendered state
352 // Always execute, even if we are already in the rendered state
353 return cont;
353 return cont;
354 };
354 };
355
355
356 CodeCell.prototype.unrender = function () {
356 CodeCell.prototype.unrender = function () {
357 // CodeCell is always rendered
357 // CodeCell is always rendered
358 return false;
358 return false;
359 };
359 };
360
360
361 /**
362 * Determine whether or not the unfocus event should be aknowledged.
363 *
364 * @method should_cancel_blur
365 *
366 * @return results {bool} Whether or not to ignore the cell's blur event.
367 **/
368 CodeCell.prototype.should_cancel_blur = function () {
369 // Cancel this unfocus event if the base wants to cancel or the cell
370 // completer is open or the tooltip is open.
371 return IPython.Cell.prototype.should_cancel_blur.apply(this) ||
372 (this.completer && this.completer.is_visible()) ||
373 (IPython.tooltip && IPython.tooltip.is_visible());
374 };
375
376 CodeCell.prototype.select_all = function () {
361 CodeCell.prototype.select_all = function () {
377 var start = {line: 0, ch: 0};
362 var start = {line: 0, ch: 0};
378 var nlines = this.code_mirror.lineCount();
363 var nlines = this.code_mirror.lineCount();
379 var last_line = this.code_mirror.getLine(nlines-1);
364 var last_line = this.code_mirror.getLine(nlines-1);
380 var end = {line: nlines-1, ch: last_line.length};
365 var end = {line: nlines-1, ch: last_line.length};
381 this.code_mirror.setSelection(start, end);
366 this.code_mirror.setSelection(start, end);
382 };
367 };
383
368
384
369
385 CodeCell.prototype.collapse_output = function () {
370 CodeCell.prototype.collapse_output = function () {
386 this.collapsed = true;
371 this.collapsed = true;
387 this.output_area.collapse();
372 this.output_area.collapse();
388 };
373 };
389
374
390
375
391 CodeCell.prototype.expand_output = function () {
376 CodeCell.prototype.expand_output = function () {
392 this.collapsed = false;
377 this.collapsed = false;
393 this.output_area.expand();
378 this.output_area.expand();
394 this.output_area.unscroll_area();
379 this.output_area.unscroll_area();
395 };
380 };
396
381
397 CodeCell.prototype.scroll_output = function () {
382 CodeCell.prototype.scroll_output = function () {
398 this.output_area.expand();
383 this.output_area.expand();
399 this.output_area.scroll_if_long();
384 this.output_area.scroll_if_long();
400 };
385 };
401
386
402 CodeCell.prototype.toggle_output = function () {
387 CodeCell.prototype.toggle_output = function () {
403 this.collapsed = Boolean(1 - this.collapsed);
388 this.collapsed = Boolean(1 - this.collapsed);
404 this.output_area.toggle_output();
389 this.output_area.toggle_output();
405 };
390 };
406
391
407 CodeCell.prototype.toggle_output_scroll = function () {
392 CodeCell.prototype.toggle_output_scroll = function () {
408 this.output_area.toggle_scroll();
393 this.output_area.toggle_scroll();
409 };
394 };
410
395
411
396
412 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
397 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
413 var ns;
398 var ns;
414 if (prompt_value === undefined) {
399 if (prompt_value === undefined) {
415 ns = "&nbsp;";
400 ns = "&nbsp;";
416 } else {
401 } else {
417 ns = encodeURIComponent(prompt_value);
402 ns = encodeURIComponent(prompt_value);
418 }
403 }
419 return 'In&nbsp;[' + ns + ']:';
404 return 'In&nbsp;[' + ns + ']:';
420 };
405 };
421
406
422 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
407 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
423 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
408 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
424 for(var i=1; i < lines_number; i++) {
409 for(var i=1; i < lines_number; i++) {
425 html.push(['...:']);
410 html.push(['...:']);
426 }
411 }
427 return html.join('<br/>');
412 return html.join('<br/>');
428 };
413 };
429
414
430 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
415 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
431
416
432
417
433 CodeCell.prototype.set_input_prompt = function (number) {
418 CodeCell.prototype.set_input_prompt = function (number) {
434 var nline = 1;
419 var nline = 1;
435 if (this.code_mirror !== undefined) {
420 if (this.code_mirror !== undefined) {
436 nline = this.code_mirror.lineCount();
421 nline = this.code_mirror.lineCount();
437 }
422 }
438 this.input_prompt_number = number;
423 this.input_prompt_number = number;
439 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
424 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
440 // This HTML call is okay because the user contents are escaped.
425 // This HTML call is okay because the user contents are escaped.
441 this.element.find('div.input_prompt').html(prompt_html);
426 this.element.find('div.input_prompt').html(prompt_html);
442 };
427 };
443
428
444
429
445 CodeCell.prototype.clear_input = function () {
430 CodeCell.prototype.clear_input = function () {
446 this.code_mirror.setValue('');
431 this.code_mirror.setValue('');
447 };
432 };
448
433
449
434
450 CodeCell.prototype.get_text = function () {
435 CodeCell.prototype.get_text = function () {
451 return this.code_mirror.getValue();
436 return this.code_mirror.getValue();
452 };
437 };
453
438
454
439
455 CodeCell.prototype.set_text = function (code) {
440 CodeCell.prototype.set_text = function (code) {
456 return this.code_mirror.setValue(code);
441 return this.code_mirror.setValue(code);
457 };
442 };
458
443
459
444
460 CodeCell.prototype.clear_output = function (wait) {
445 CodeCell.prototype.clear_output = function (wait) {
461 this.output_area.clear_output(wait);
446 this.output_area.clear_output(wait);
462 this.set_input_prompt();
447 this.set_input_prompt();
463 };
448 };
464
449
465
450
466 // JSON serialization
451 // JSON serialization
467
452
468 CodeCell.prototype.fromJSON = function (data) {
453 CodeCell.prototype.fromJSON = function (data) {
469 IPython.Cell.prototype.fromJSON.apply(this, arguments);
454 IPython.Cell.prototype.fromJSON.apply(this, arguments);
470 if (data.cell_type === 'code') {
455 if (data.cell_type === 'code') {
471 if (data.input !== undefined) {
456 if (data.input !== undefined) {
472 this.set_text(data.input);
457 this.set_text(data.input);
473 // make this value the starting point, so that we can only undo
458 // make this value the starting point, so that we can only undo
474 // to this state, instead of a blank cell
459 // to this state, instead of a blank cell
475 this.code_mirror.clearHistory();
460 this.code_mirror.clearHistory();
476 this.auto_highlight();
461 this.auto_highlight();
477 }
462 }
478 if (data.prompt_number !== undefined) {
463 if (data.prompt_number !== undefined) {
479 this.set_input_prompt(data.prompt_number);
464 this.set_input_prompt(data.prompt_number);
480 } else {
465 } else {
481 this.set_input_prompt();
466 this.set_input_prompt();
482 }
467 }
483 this.output_area.trusted = data.trusted || false;
468 this.output_area.trusted = data.trusted || false;
484 this.output_area.fromJSON(data.outputs);
469 this.output_area.fromJSON(data.outputs);
485 if (data.collapsed !== undefined) {
470 if (data.collapsed !== undefined) {
486 if (data.collapsed) {
471 if (data.collapsed) {
487 this.collapse_output();
472 this.collapse_output();
488 } else {
473 } else {
489 this.expand_output();
474 this.expand_output();
490 }
475 }
491 }
476 }
492 }
477 }
493 };
478 };
494
479
495
480
496 CodeCell.prototype.toJSON = function () {
481 CodeCell.prototype.toJSON = function () {
497 var data = IPython.Cell.prototype.toJSON.apply(this);
482 var data = IPython.Cell.prototype.toJSON.apply(this);
498 data.input = this.get_text();
483 data.input = this.get_text();
499 // is finite protect against undefined and '*' value
484 // is finite protect against undefined and '*' value
500 if (isFinite(this.input_prompt_number)) {
485 if (isFinite(this.input_prompt_number)) {
501 data.prompt_number = this.input_prompt_number;
486 data.prompt_number = this.input_prompt_number;
502 }
487 }
503 var outputs = this.output_area.toJSON();
488 var outputs = this.output_area.toJSON();
504 data.outputs = outputs;
489 data.outputs = outputs;
505 data.language = 'python';
490 data.language = 'python';
506 data.trusted = this.output_area.trusted;
491 data.trusted = this.output_area.trusted;
507 data.collapsed = this.collapsed;
492 data.collapsed = this.collapsed;
508 return data;
493 return data;
509 };
494 };
510
495
496 /**
497 * handle cell level logic when a cell is unselected
498 * @method unselect
499 * @return is the action being taken
500 */
501 CodeCell.prototype.unselect = function () {
502 var cont = IPython.Cell.prototype.unselect.apply(this);
503 if (cont) {
504 // When a code cell is usnelected, make sure that the corresponding
505 // tooltip and completer to that cell is closed.
506 IPython.tooltip.remove_and_cancel_tooltip(true);
507 if (this.completer !== null) {
508 this.completer.close();
509 }
510 }
511 return cont;
512 };
511
513
512 IPython.CodeCell = CodeCell;
514 IPython.CodeCell = CodeCell;
513
515
514 return IPython;
516 return IPython;
515 }(IPython));
517 }(IPython));
@@ -1,384 +1,369 b''
1 // function completer.
1 // function completer.
2 //
2 //
3 // completer should be a class that takes an cell instance
3 // completer should be a class that takes an cell instance
4 var IPython = (function (IPython) {
4 var IPython = (function (IPython) {
5 // that will prevent us from misspelling
5 // that will prevent us from misspelling
6 "use strict";
6 "use strict";
7
7
8 // easier key mapping
8 // easier key mapping
9 var keycodes = IPython.keyboard.keycodes;
9 var keycodes = IPython.keyboard.keycodes;
10
10
11 function prepend_n_prc(str, n) {
11 function prepend_n_prc(str, n) {
12 for( var i =0 ; i< n ; i++){
12 for( var i =0 ; i< n ; i++){
13 str = '%'+str ;
13 str = '%'+str ;
14 }
14 }
15 return str;
15 return str;
16 }
16 }
17
17
18 function _existing_completion(item, completion_array){
18 function _existing_completion(item, completion_array){
19 for( var c in completion_array ) {
19 for( var c in completion_array ) {
20 if(completion_array[c].trim().substr(-item.length) == item)
20 if(completion_array[c].trim().substr(-item.length) == item)
21 { return true; }
21 { return true; }
22 }
22 }
23 return false;
23 return false;
24 }
24 }
25
25
26 // what is the common start of all completions
26 // what is the common start of all completions
27 function shared_start(B, drop_prct) {
27 function shared_start(B, drop_prct) {
28 if (B.length == 1) {
28 if (B.length == 1) {
29 return B[0];
29 return B[0];
30 }
30 }
31 var A = [];
31 var A = [];
32 var common;
32 var common;
33 var min_lead_prct = 10;
33 var min_lead_prct = 10;
34 for (var i = 0; i < B.length; i++) {
34 for (var i = 0; i < B.length; i++) {
35 var str = B[i].str;
35 var str = B[i].str;
36 var localmin = 0;
36 var localmin = 0;
37 if(drop_prct === true){
37 if(drop_prct === true){
38 while ( str.substr(0, 1) == '%') {
38 while ( str.substr(0, 1) == '%') {
39 localmin = localmin+1;
39 localmin = localmin+1;
40 str = str.substring(1);
40 str = str.substring(1);
41 }
41 }
42 }
42 }
43 min_lead_prct = Math.min(min_lead_prct, localmin);
43 min_lead_prct = Math.min(min_lead_prct, localmin);
44 A.push(str);
44 A.push(str);
45 }
45 }
46
46
47 if (A.length > 1) {
47 if (A.length > 1) {
48 var tem1, tem2, s;
48 var tem1, tem2, s;
49 A = A.slice(0).sort();
49 A = A.slice(0).sort();
50 tem1 = A[0];
50 tem1 = A[0];
51 s = tem1.length;
51 s = tem1.length;
52 tem2 = A.pop();
52 tem2 = A.pop();
53 while (s && tem2.indexOf(tem1) == -1) {
53 while (s && tem2.indexOf(tem1) == -1) {
54 tem1 = tem1.substring(0, --s);
54 tem1 = tem1.substring(0, --s);
55 }
55 }
56 if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
56 if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
57 return {
57 return {
58 str:prepend_n_prc('', min_lead_prct),
58 str:prepend_n_prc('', min_lead_prct),
59 type: "computed",
59 type: "computed",
60 from: B[0].from,
60 from: B[0].from,
61 to: B[0].to
61 to: B[0].to
62 };
62 };
63 }
63 }
64 return {
64 return {
65 str: prepend_n_prc(tem1, min_lead_prct),
65 str: prepend_n_prc(tem1, min_lead_prct),
66 type: "computed",
66 type: "computed",
67 from: B[0].from,
67 from: B[0].from,
68 to: B[0].to
68 to: B[0].to
69 };
69 };
70 }
70 }
71 return null;
71 return null;
72 }
72 }
73
73
74
74
75 var Completer = function (cell) {
75 var Completer = function (cell) {
76 this._visible = false;
77 this.cell = cell;
76 this.cell = cell;
78 this.editor = cell.code_mirror;
77 this.editor = cell.code_mirror;
79 var that = this;
78 var that = this;
80 $([IPython.events]).on('status_busy.Kernel', function () {
79 $([IPython.events]).on('status_busy.Kernel', function () {
81 that.skip_kernel_completion = true;
80 that.skip_kernel_completion = true;
82 });
81 });
83 $([IPython.events]).on('status_idle.Kernel', function () {
82 $([IPython.events]).on('status_idle.Kernel', function () {
84 that.skip_kernel_completion = false;
83 that.skip_kernel_completion = false;
85 });
84 });
86 };
85 };
87
86
88 Completer.prototype.is_visible = function () {
89 // Return whether or not the completer is visible.
90 return this._visible;
91 };
92
93 Completer.prototype.startCompletion = function () {
87 Completer.prototype.startCompletion = function () {
94 // call for a 'first' completion, that will set the editor and do some
88 // call for a 'first' completion, that will set the editor and do some
95 // special behaviour like autopicking if only one completion availlable
89 // special behavior like autopicking if only one completion available.
96 //
97 if (this.editor.somethingSelected()) return;
90 if (this.editor.somethingSelected()) return;
98 this.done = false;
91 this.done = false;
99 // use to get focus back on opera
92 // use to get focus back on opera
100 this.carry_on_completion(true);
93 this.carry_on_completion(true);
101 };
94 };
102
95
103
96
104 // easy access for julia to monkeypatch
97 // easy access for julia to monkeypatch
105 //
98 //
106 Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;
99 Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;
107
100
108 Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
101 Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
109 return Completer.reinvoke_re.test(pre_cursor);
102 return Completer.reinvoke_re.test(pre_cursor);
110 };
103 };
111
104
112 /**
105 /**
113 *
106 *
114 * pass true as parameter if this is the first invocation of the completer
107 * pass true as parameter if this is the first invocation of the completer
115 * this will prevent the completer to dissmiss itself if it is not on a
108 * this will prevent the completer to dissmiss itself if it is not on a
116 * word boundary like pressing tab after a space, and make it autopick the
109 * word boundary like pressing tab after a space, and make it autopick the
117 * only choice if there is only one which prevent from popping the UI. as
110 * only choice if there is only one which prevent from popping the UI. as
118 * well as fast-forwarding the typing if all completion have a common
111 * well as fast-forwarding the typing if all completion have a common
119 * shared start
112 * shared start
120 **/
113 **/
121 Completer.prototype.carry_on_completion = function (first_invocation) {
114 Completer.prototype.carry_on_completion = function (first_invocation) {
122 // Pass true as parameter if you want the completer to autopick when
115 // Pass true as parameter if you want the completer to autopick when
123 // only one completion. This function is automatically reinvoked at
116 // only one completion. This function is automatically reinvoked at
124 // each keystroke with first_invocation = false
117 // each keystroke with first_invocation = false
125 var cur = this.editor.getCursor();
118 var cur = this.editor.getCursor();
126 var line = this.editor.getLine(cur.line);
119 var line = this.editor.getLine(cur.line);
127 var pre_cursor = this.editor.getRange({
120 var pre_cursor = this.editor.getRange({
128 line: cur.line,
121 line: cur.line,
129 ch: cur.ch - 1
122 ch: cur.ch - 1
130 }, cur);
123 }, cur);
131
124
132 // we need to check that we are still on a word boundary
125 // we need to check that we are still on a word boundary
133 // because while typing the completer is still reinvoking itself
126 // because while typing the completer is still reinvoking itself
134 // so dismiss if we are on a "bad" caracter
127 // so dismiss if we are on a "bad" caracter
135 if (!this.reinvoke(pre_cursor) && !first_invocation) {
128 if (!this.reinvoke(pre_cursor) && !first_invocation) {
136 this.close();
129 this.close();
137 return;
130 return;
138 }
131 }
139
132
140 this.autopick = false;
133 this.autopick = false;
141 if (first_invocation) {
134 if (first_invocation) {
142 this.autopick = true;
135 this.autopick = true;
143 }
136 }
144
137
145 // We want a single cursor position.
138 // We want a single cursor position.
146 if (this.editor.somethingSelected()) {
139 if (this.editor.somethingSelected()) {
147 return;
140 return;
148 }
141 }
149
142
150 // one kernel completion came back, finish_completing will be called with the results
143 // one kernel completion came back, finish_completing will be called with the results
151 // we fork here and directly call finish completing if kernel is busy
144 // we fork here and directly call finish completing if kernel is busy
152 if (this.skip_kernel_completion) {
145 if (this.skip_kernel_completion) {
153 this.finish_completing({
146 this.finish_completing({
154 'matches': [],
147 'matches': [],
155 matched_text: ""
148 matched_text: ""
156 });
149 });
157 } else {
150 } else {
158 this.cell.kernel.complete(line, cur.ch, $.proxy(this.finish_completing, this));
151 this.cell.kernel.complete(line, cur.ch, $.proxy(this.finish_completing, this));
159 }
152 }
160 };
153 };
161
154
162 Completer.prototype.finish_completing = function (msg) {
155 Completer.prototype.finish_completing = function (msg) {
163 // let's build a function that wrap all that stuff into what is needed
156 // let's build a function that wrap all that stuff into what is needed
164 // for the new completer:
157 // for the new completer:
165 var content = msg.content;
158 var content = msg.content;
166 var matched_text = content.matched_text;
159 var matched_text = content.matched_text;
167 var matches = content.matches;
160 var matches = content.matches;
168
161
169 var cur = this.editor.getCursor();
162 var cur = this.editor.getCursor();
170 var results = CodeMirror.contextHint(this.editor);
163 var results = CodeMirror.contextHint(this.editor);
171 var filtered_results = [];
164 var filtered_results = [];
172 //remove results from context completion
165 //remove results from context completion
173 //that are already in kernel completion
166 //that are already in kernel completion
174 for (var elm in results) {
167 for (var elm in results) {
175 if (!_existing_completion(results[elm].str, matches)) {
168 if (!_existing_completion(results[elm].str, matches)) {
176 filtered_results.push(results[elm]);
169 filtered_results.push(results[elm]);
177 }
170 }
178 }
171 }
179
172
180 // append the introspection result, in order, at at the beginning of
173 // append the introspection result, in order, at at the beginning of
181 // the table and compute the replacement range from current cursor
174 // the table and compute the replacement range from current cursor
182 // positon and matched_text length.
175 // positon and matched_text length.
183 for (var i = matches.length - 1; i >= 0; --i) {
176 for (var i = matches.length - 1; i >= 0; --i) {
184 filtered_results.unshift({
177 filtered_results.unshift({
185 str: matches[i],
178 str: matches[i],
186 type: "introspection",
179 type: "introspection",
187 from: {
180 from: {
188 line: cur.line,
181 line: cur.line,
189 ch: cur.ch - matched_text.length
182 ch: cur.ch - matched_text.length
190 },
183 },
191 to: {
184 to: {
192 line: cur.line,
185 line: cur.line,
193 ch: cur.ch
186 ch: cur.ch
194 }
187 }
195 });
188 });
196 }
189 }
197
190
198 // one the 2 sources results have been merge, deal with it
191 // one the 2 sources results have been merge, deal with it
199 this.raw_result = filtered_results;
192 this.raw_result = filtered_results;
200
193
201 // if empty result return
194 // if empty result return
202 if (!this.raw_result || !this.raw_result.length) return;
195 if (!this.raw_result || !this.raw_result.length) return;
203
196
204 // When there is only one completion, use it directly.
197 // When there is only one completion, use it directly.
205 if (this.autopick && this.raw_result.length == 1) {
198 if (this.autopick && this.raw_result.length == 1) {
206 this.insert(this.raw_result[0]);
199 this.insert(this.raw_result[0]);
207 return;
200 return;
208 }
201 }
209
202
210 if (this.raw_result.length == 1) {
203 if (this.raw_result.length == 1) {
211 // test if first and only completion totally matches
204 // test if first and only completion totally matches
212 // what is typed, in this case dismiss
205 // what is typed, in this case dismiss
213 var str = this.raw_result[0].str;
206 var str = this.raw_result[0].str;
214 var pre_cursor = this.editor.getRange({
207 var pre_cursor = this.editor.getRange({
215 line: cur.line,
208 line: cur.line,
216 ch: cur.ch - str.length
209 ch: cur.ch - str.length
217 }, cur);
210 }, cur);
218 if (pre_cursor == str) {
211 if (pre_cursor == str) {
219 this.close();
212 this.close();
220 return;
213 return;
221 }
214 }
222 }
215 }
223
216
224 this.complete = $('<div/>').addClass('completions');
217 if (!this.visible) {
225 this.complete.attr('id', 'complete');
218 this.complete = $('<div/>').addClass('completions');
226
219 this.complete.attr('id', 'complete');
227 // Currently webkit doesn't use the size attr correctly. See:
220
228 // https://code.google.com/p/chromium/issues/detail?id=4579
221 // Currently webkit doesn't use the size attr correctly. See:
229 this.sel = $('<select style="width: auto"/>')
222 // https://code.google.com/p/chromium/issues/detail?id=4579
230 .attr('multiple', 'true')
223 this.sel = $('<select/>')
231 .attr('size', Math.min(10, this.raw_result.length));
224 .attr('tabindex', -1)
232 this.complete.append(this.sel);
225 .attr('multiple', 'true');
233 this._visible = true;
226 this.complete.append(this.sel);
234 $('body').append(this.complete);
227 this.visible = true;
228 $('body').append(this.complete);
229
230 //build the container
231 var that = this;
232 this.sel.dblclick(function () {
233 that.pick();
234 });
235 this.sel.focus(function () {
236 that.editor.focus();
237 });
238 this._handle_keydown = function (cm, event) {
239 that.keydown(event);
240 };
241 this.editor.on('keydown', this._handle_keydown);
242 this._handle_keypress = function (cm, event) {
243 that.keypress(event);
244 };
245 this.editor.on('keypress', this._handle_keypress);
246 }
247 this.sel.attr('size', Math.min(10, this.raw_result.length));
235
248
236 // After everything is on the page, compute the postion.
249 // After everything is on the page, compute the postion.
237 // We put it above the code if it is too close to the bottom of the page.
250 // We put it above the code if it is too close to the bottom of the page.
238 cur.ch = cur.ch-matched_text.length;
251 cur.ch = cur.ch-matched_text.length;
239 var pos = this.editor.cursorCoords(cur);
252 var pos = this.editor.cursorCoords(cur);
240 var left = pos.left-3;
253 var left = pos.left-3;
241 var top;
254 var top;
242 var cheight = this.complete.height();
255 var cheight = this.complete.height();
243 var wheight = $(window).height();
256 var wheight = $(window).height();
244 if (pos.bottom+cheight+5 > wheight) {
257 if (pos.bottom+cheight+5 > wheight) {
245 top = pos.top-cheight-4;
258 top = pos.top-cheight-4;
246 } else {
259 } else {
247 top = pos.bottom+1;
260 top = pos.bottom+1;
248 }
261 }
249 this.complete.css('left', left + 'px');
262 this.complete.css('left', left + 'px');
250 this.complete.css('top', top + 'px');
263 this.complete.css('top', top + 'px');
251
264
252
265 // Clear and fill the list.
253 //build the container
266 this.sel.text('');
254 var that = this;
255 this.sel.dblclick(function () {
256 that.pick();
257 });
258 this.sel.blur(this.close);
259 this.sel.keydown(function (event) {
260 that.keydown(event);
261 });
262 this.sel.keypress(function (event) {
263 that.keypress(event);
264 });
265
266 this.build_gui_list(this.raw_result);
267 this.build_gui_list(this.raw_result);
267
268 this.sel.focus();
269 IPython.keyboard_manager.disable();
270 // Opera sometimes ignores focusing a freshly created node
271 if (window.opera) setTimeout(function () {
272 if (!this.done) this.sel.focus();
273 }, 100);
274 return true;
268 return true;
275 };
269 };
276
270
277 Completer.prototype.insert = function (completion) {
271 Completer.prototype.insert = function (completion) {
278 this.editor.replaceRange(completion.str, completion.from, completion.to);
272 this.editor.replaceRange(completion.str, completion.from, completion.to);
279 };
273 };
280
274
281 Completer.prototype.build_gui_list = function (completions) {
275 Completer.prototype.build_gui_list = function (completions) {
282 for (var i = 0; i < completions.length; ++i) {
276 for (var i = 0; i < completions.length; ++i) {
283 var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
277 var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
284 this.sel.append(opt);
278 this.sel.append(opt);
285 }
279 }
286 this.sel.children().first().attr('selected', 'true');
280 this.sel.children().first().attr('selected', 'true');
287 this.sel.scrollTop(0);
281 this.sel.scrollTop(0);
288 };
282 };
289
283
290 Completer.prototype.close = function () {
284 Completer.prototype.close = function () {
291 this._visible = false;
292 if (this.done) return;
293 this.done = true;
285 this.done = true;
294 $('.completions').remove();
286 $('#complete').remove();
295 IPython.keyboard_manager.enable();
287 this.editor.off('keydown', this._handle_keydown);
288 this.editor.off('keypress', this._handle_keypress);
289 this.visible = false;
296 };
290 };
297
291
298 Completer.prototype.pick = function () {
292 Completer.prototype.pick = function () {
299 this.insert(this.raw_result[this.sel[0].selectedIndex]);
293 this.insert(this.raw_result[this.sel[0].selectedIndex]);
300 this.close();
294 this.close();
301 var that = this;
302 setTimeout(function () {
303 that.editor.focus();
304 }, 50);
305 };
295 };
306
296
307 Completer.prototype.keydown = function (event) {
297 Completer.prototype.keydown = function (event) {
308 var code = event.keyCode;
298 var code = event.keyCode;
309 var that = this;
299 var that = this;
310
300
311 // Enter
301 // Enter
312 if (code == keycodes.enter) {
302 if (code == keycodes.enter) {
313 CodeMirror.e_stop(event);
303 CodeMirror.e_stop(event);
314 this.pick();
304 this.pick();
315 }
316 // Escape or backspace
305 // Escape or backspace
317 else if (code == keycodes.esc) {
306 } else if (code == keycodes.esc || code == keycodes.backspace) {
318 CodeMirror.e_stop(event);
307 CodeMirror.e_stop(event);
319 this.close();
308 this.close();
320 this.editor.focus();
321
322 } else if (code == keycodes.backspace) {
323 this.close();
324 this.editor.focus();
325 } else if (code == keycodes.tab) {
309 } else if (code == keycodes.tab) {
326 //all the fastforwarding operation,
310 //all the fastforwarding operation,
327 //Check that shared start is not null which can append with prefixed completion
311 //Check that shared start is not null which can append with prefixed completion
328 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
312 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
329 // to erase py
313 // to erase py
330 var sh = shared_start(this.raw_result, true);
314 var sh = shared_start(this.raw_result, true);
331 if (sh) {
315 if (sh) {
332 this.insert(sh);
316 this.insert(sh);
333 }
317 }
334 this.close();
318 this.close();
335 CodeMirror.e_stop(event);
336 this.editor.focus();
337 //reinvoke self
319 //reinvoke self
338 setTimeout(function () {
320 setTimeout(function () {
339 that.carry_on_completion();
321 that.carry_on_completion();
340 }, 50);
322 }, 50);
341 } else if (code == keycodes.up || code == keycodes.down) {
323 } else if (code == keycodes.up || code == keycodes.down) {
342 // need to do that to be able to move the arrow
324 // need to do that to be able to move the arrow
343 // when on the first or last line ofo a code cell
325 // when on the first or last line ofo a code cell
344 event.stopPropagation();
326 CodeMirror.e_stop(event);
327
328 var options = this.sel.find('option');
329 var index = this.sel[0].selectedIndex;
330 if (code == keycodes.up) {
331 index--;
332 }
333 if (code == keycodes.down) {
334 index++;
335 }
336 index = Math.min(Math.max(index, 0), options.length-1);
337 this.sel[0].selectedIndex = index;
338 } else if (code == keycodes.left || code == keycodes.right) {
339 this.close();
345 }
340 }
346 };
341 };
347
342
348 Completer.prototype.keypress = function (event) {
343 Completer.prototype.keypress = function (event) {
349 // FIXME: This is a band-aid.
344 // FIXME: This is a band-aid.
350 // on keypress, trigger insertion of a single character.
345 // on keypress, trigger insertion of a single character.
351 // This simulates the old behavior of completion as you type,
346 // This simulates the old behavior of completion as you type,
352 // before events were disconnected and CodeMirror stopped
347 // before events were disconnected and CodeMirror stopped
353 // receiving events while the completer is focused.
348 // receiving events while the completer is focused.
354
349
355 var that = this;
350 var that = this;
356 var code = event.keyCode;
351 var code = event.keyCode;
357
352
358 // don't handle keypress if it's not a character (arrows on FF)
353 // don't handle keypress if it's not a character (arrows on FF)
359 // or ENTER/TAB
354 // or ENTER/TAB
360 if (event.charCode === 0 ||
355 if (event.charCode === 0 ||
361 code == keycodes.enter ||
356 code == keycodes.tab ||
362 code == keycodes.tab
357 code == keycodes.enter
363 ) return;
358 ) return;
364
359
365 var cur = this.editor.getCursor();
366 var completion = {
367 str: String.fromCharCode(event.which),
368 type: "introspection",
369 from: cur,
370 to: cur,
371 };
372 this.insert(completion);
373
374 this.close();
360 this.close();
375 this.editor.focus();
361 this.editor.focus();
376 setTimeout(function () {
362 setTimeout(function () {
377 that.carry_on_completion();
363 that.carry_on_completion();
378 }, 50);
364 }, 50);
379 };
365 };
380
381 IPython.Completer = Completer;
366 IPython.Completer = Completer;
382
367
383 return IPython;
368 return IPython;
384 }(IPython));
369 }(IPython));
@@ -1,24 +1,25 b''
1 .completions {
1 .completions {
2 position: absolute;
2 position: absolute;
3 z-index: 10;
3 z-index: 10;
4 overflow: hidden;
4 overflow: hidden;
5 border: 1px solid @border_color;
5 border: 1px solid @border_color;
6 .corner-all;
6 .corner-all;
7 .box-shadow(0px 6px 10px -1px #adadad);
7 .box-shadow(0px 6px 10px -1px #adadad);
8 }
8 }
9
9
10 .completions select {
10 .completions select {
11 background: white;
11 background: white;
12 outline: none;
12 outline: none;
13 border: none;
13 border: none;
14 padding: 0px;
14 padding: 0px;
15 margin: 0px;
15 margin: 0px;
16 overflow: auto;
16 overflow: auto;
17 font-family: @monoFontFamily;
17 font-family: @monoFontFamily;
18 font-size: 110%;
18 font-size: 110%;
19 color: @textColor;
19 color: @textColor;
20 width: auto;
20 }
21 }
21
22
22 .completions select option.context {
23 .completions select option.context {
23 color: @blueDark;
24 color: @blueDark;
24 }
25 }
@@ -1,1536 +1,1536 b''
1 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
2 .clearfix:after{clear:both}
3 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
4 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
5 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
6 audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
7 audio:not([controls]){display:none}
3 audio:not([controls]){display:none}
8 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
9 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
10 a:hover,a:active{outline:0}
6 a:hover,a:active{outline:0}
11 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}
7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}
12 sup{top:-0.5em}
8 sup{top:-0.5em}
13 sub{bottom:-0.25em}
9 sub{bottom:-0.25em}
14 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}
10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}
15 #map_canvas img,.google-maps img{max-width:none}
11 #map_canvas img,.google-maps img{max-width:none}
16 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}
12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}
17 button,input{*overflow:visible;line-height:normal}
13 button,input{*overflow:visible;line-height:normal}
18 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
19 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
20 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}
16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}
21 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}
17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}
22 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
23 textarea{overflow:auto;vertical-align:top}
19 textarea{overflow:auto;vertical-align:top}
24 @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""} pre,blockquote{border:1px solid #999;page-break-inside:avoid} thead{display:table-header-group} tr,img{page-break-inside:avoid} img{max-width:100% !important} @page {margin:.5cm}p,h2,h3{orphans:3;widows:3} h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000;background-color:#fff}
20 @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""} pre,blockquote{border:1px solid #999;page-break-inside:avoid} thead{display:table-header-group} tr,img{page-break-inside:avoid} img{max-width:100% !important} @page {margin:.5cm}p,h2,h3{orphans:3;widows:3} h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000;background-color:#fff}
25 a{color:#08c;text-decoration:none}
21 a{color:#08c;text-decoration:none}
26 a:hover,a:focus{color:#005580;text-decoration:underline}
22 a:hover,a:focus{color:#005580;text-decoration:underline}
27 .img-rounded{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
23 .img-rounded{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
28 .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}
24 .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}
29 .img-circle{border-radius:500px;-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}
25 .img-circle{border-radius:500px;-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}
30 .row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0}
26 .row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0}
31 .row:after{clear:both}
27 .row:after{clear:both}
32 [class*="span"]{float:left;min-height:1px;margin-left:20px}
28 [class*="span"]{float:left;min-height:1px;margin-left:20px}
33 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
29 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
34 .span12{width:940px}
30 .span12{width:940px}
35 .span11{width:860px}
31 .span11{width:860px}
36 .span10{width:780px}
32 .span10{width:780px}
37 .span9{width:700px}
33 .span9{width:700px}
38 .span8{width:620px}
34 .span8{width:620px}
39 .span7{width:540px}
35 .span7{width:540px}
40 .span6{width:460px}
36 .span6{width:460px}
41 .span5{width:380px}
37 .span5{width:380px}
42 .span4{width:300px}
38 .span4{width:300px}
43 .span3{width:220px}
39 .span3{width:220px}
44 .span2{width:140px}
40 .span2{width:140px}
45 .span1{width:60px}
41 .span1{width:60px}
46 .offset12{margin-left:980px}
42 .offset12{margin-left:980px}
47 .offset11{margin-left:900px}
43 .offset11{margin-left:900px}
48 .offset10{margin-left:820px}
44 .offset10{margin-left:820px}
49 .offset9{margin-left:740px}
45 .offset9{margin-left:740px}
50 .offset8{margin-left:660px}
46 .offset8{margin-left:660px}
51 .offset7{margin-left:580px}
47 .offset7{margin-left:580px}
52 .offset6{margin-left:500px}
48 .offset6{margin-left:500px}
53 .offset5{margin-left:420px}
49 .offset5{margin-left:420px}
54 .offset4{margin-left:340px}
50 .offset4{margin-left:340px}
55 .offset3{margin-left:260px}
51 .offset3{margin-left:260px}
56 .offset2{margin-left:180px}
52 .offset2{margin-left:180px}
57 .offset1{margin-left:100px}
53 .offset1{margin-left:100px}
58 .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0}
54 .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0}
59 .row-fluid:after{clear:both}
55 .row-fluid:after{clear:both}
60 .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%}
56 .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%}
61 .row-fluid [class*="span"]:first-child{margin-left:0}
57 .row-fluid [class*="span"]:first-child{margin-left:0}
62 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}
58 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}
63 .row-fluid .span12{width:100%;*width:99.94680851063829%}
59 .row-fluid .span12{width:100%;*width:99.94680851063829%}
64 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}
60 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}
65 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}
61 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}
66 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}
62 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}
67 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}
63 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}
68 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}
64 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}
69 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}
65 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}
70 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}
66 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}
71 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}
67 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}
72 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}
68 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}
73 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}
69 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}
74 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}
70 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}
75 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}
71 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}
76 .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}
72 .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}
77 .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}
73 .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}
78 .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}
74 .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}
79 .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}
75 .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}
80 .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}
76 .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}
81 .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}
77 .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}
82 .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}
78 .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}
83 .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}
79 .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}
84 .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}
80 .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}
85 .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}
81 .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}
86 .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}
82 .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}
87 .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}
83 .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}
88 .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}
84 .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}
89 .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}
85 .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}
90 .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}
86 .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}
91 .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}
87 .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}
92 .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}
88 .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}
93 .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}
89 .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}
94 .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}
90 .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}
95 .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}
91 .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}
96 .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}
92 .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}
97 .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}
93 .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}
98 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}
94 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}
99 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none}
95 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none}
100 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}
96 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}
101 .container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:"";line-height:0}
97 .container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:"";line-height:0}
102 .container:after{clear:both}
98 .container:after{clear:both}
103 .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0}
99 .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0}
104 .container-fluid:after{clear:both}
100 .container-fluid:after{clear:both}
105 p{margin:0 0 10px}
101 p{margin:0 0 10px}
106 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px}
102 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px}
107 small{font-size:85%}
103 small{font-size:85%}
108 strong{font-weight:bold}
104 strong{font-weight:bold}
109 em{font-style:italic}
105 em{font-style:italic}
110 cite{font-style:normal}
106 cite{font-style:normal}
111 .muted{color:#999}
107 .muted{color:#999}
112 a.muted:hover,a.muted:focus{color:#808080}
108 a.muted:hover,a.muted:focus{color:#808080}
113 .text-warning{color:#c09853}
109 .text-warning{color:#c09853}
114 a.text-warning:hover,a.text-warning:focus{color:#a47e3c}
110 a.text-warning:hover,a.text-warning:focus{color:#a47e3c}
115 .text-error{color:#b94a48}
111 .text-error{color:#b94a48}
116 a.text-error:hover,a.text-error:focus{color:#953b39}
112 a.text-error:hover,a.text-error:focus{color:#953b39}
117 .text-info{color:#3a87ad}
113 .text-info{color:#3a87ad}
118 a.text-info:hover,a.text-info:focus{color:#2d6987}
114 a.text-info:hover,a.text-info:focus{color:#2d6987}
119 .text-success{color:#468847}
115 .text-success{color:#468847}
120 a.text-success:hover,a.text-success:focus{color:#356635}
116 a.text-success:hover,a.text-success:focus{color:#356635}
121 .text-left{text-align:left}
117 .text-left{text-align:left}
122 .text-right{text-align:right}
118 .text-right{text-align:right}
123 .text-center{text-align:center}
119 .text-center{text-align:center}
124 h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}
120 h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}
125 h1,h2,h3{line-height:40px}
121 h1,h2,h3{line-height:40px}
126 h1{font-size:35.75px}
122 h1{font-size:35.75px}
127 h2{font-size:29.25px}
123 h2{font-size:29.25px}
128 h3{font-size:22.75px}
124 h3{font-size:22.75px}
129 h4{font-size:16.25px}
125 h4{font-size:16.25px}
130 h5{font-size:13px}
126 h5{font-size:13px}
131 h6{font-size:11.049999999999999px}
127 h6{font-size:11.049999999999999px}
132 h1 small{font-size:22.75px}
128 h1 small{font-size:22.75px}
133 h2 small{font-size:16.25px}
129 h2 small{font-size:16.25px}
134 h3 small{font-size:13px}
130 h3 small{font-size:13px}
135 h4 small{font-size:13px}
131 h4 small{font-size:13px}
136 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}
132 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}
137 ul,ol{padding:0;margin:0 0 10px 25px}
133 ul,ol{padding:0;margin:0 0 10px 25px}
138 ul ul,ul ol,ol ol,ol ul{margin-bottom:0}
134 ul ul,ul ol,ol ol,ol ul{margin-bottom:0}
139 li{line-height:20px}
135 li{line-height:20px}
140 ul.unstyled,ol.unstyled{margin-left:0;list-style:none}
136 ul.unstyled,ol.unstyled{margin-left:0;list-style:none}
141 ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px}
137 ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px}
142 dl{margin-bottom:20px}
138 dl{margin-bottom:20px}
143 dt,dd{line-height:20px}
139 dt,dd{line-height:20px}
144 dt{font-weight:bold}
140 dt{font-weight:bold}
145 dd{margin-left:10px}
141 dd{margin-left:10px}
146 .dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0}
142 .dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0}
147 .dl-horizontal:after{clear:both}
143 .dl-horizontal:after{clear:both}
148 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
144 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
149 .dl-horizontal dd{margin-left:180px}
145 .dl-horizontal dd{margin-left:180px}
150 hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}
146 hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}
151 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}
147 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}
152 abbr.initialism{font-size:90%;text-transform:uppercase}
148 abbr.initialism{font-size:90%;text-transform:uppercase}
153 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16.25px;font-weight:300;line-height:1.25}
149 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16.25px;font-weight:300;line-height:1.25}
154 blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}
150 blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}
155 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}
151 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}
156 blockquote.pull-right small:before{content:''}
152 blockquote.pull-right small:before{content:''}
157 blockquote.pull-right small:after{content:'\00A0 \2014'}
153 blockquote.pull-right small:after{content:'\00A0 \2014'}
158 q:before,q:after,blockquote:before,blockquote:after{content:""}
154 q:before,q:after,blockquote:before,blockquote:after{content:""}
159 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}
155 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}
160 code,pre{padding:0 3px 2px;font-family:monospace;font-size:11px;color:#333;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
156 code,pre{padding:0 3px 2px;font-family:monospace;font-size:11px;color:#333;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
161 code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}
157 code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}
162 pre{display:block;padding:9.5px;margin:0 0 10px;font-size:12px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}
158 pre{display:block;padding:9.5px;margin:0 0 10px;font-size:12px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}
163 pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}
159 pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}
164 .pre-scrollable{max-height:340px;overflow-y:scroll}
160 .pre-scrollable{max-height:340px;overflow-y:scroll}
165 form{margin:0 0 20px}
161 form{margin:0 0 20px}
166 fieldset{padding:0;margin:0;border:0}
162 fieldset{padding:0;margin:0;border:0}
167 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}
163 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}
168 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px}
164 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px}
169 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}
165 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}
170 label{display:block;margin-bottom:5px}
166 label{display:block;margin-bottom:5px}
171 select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:13px;line-height:20px;color:#555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle}
167 select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:13px;line-height:20px;color:#555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle}
172 input,textarea,.uneditable-input{width:206px}
168 input,textarea,.uneditable-input{width:206px}
173 textarea{height:auto}
169 textarea{height:auto}
174 textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)}
170 textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)}
175 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal}
171 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal}
176 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}
172 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}
177 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}
173 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}
178 select{width:220px;border:1px solid #ccc;background-color:#fff}
174 select{width:220px;border:1px solid #ccc;background-color:#fff}
179 select[multiple],select[size]{height:auto}
175 select[multiple],select[size]{height:auto}
180 select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
176 select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
181 .uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);cursor:not-allowed}
177 .uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);cursor:not-allowed}
182 .uneditable-input{overflow:hidden;white-space:nowrap}
178 .uneditable-input{overflow:hidden;white-space:nowrap}
183 .uneditable-textarea{width:auto;height:auto}
179 .uneditable-textarea{width:auto;height:auto}
184 input:-moz-placeholder,textarea:-moz-placeholder{color:#999}
180 input:-moz-placeholder,textarea:-moz-placeholder{color:#999}
185 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}
181 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}
186 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}
182 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}
187 .radio,.checkbox{min-height:20px;padding-left:20px}
183 .radio,.checkbox{min-height:20px;padding-left:20px}
188 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}
184 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}
189 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}
185 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}
190 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}
186 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}
191 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}
187 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}
192 .input-mini{width:60px}
188 .input-mini{width:60px}
193 .input-small{width:90px}
189 .input-small{width:90px}
194 .input-medium{width:150px}
190 .input-medium{width:150px}
195 .input-large{width:210px}
191 .input-large{width:210px}
196 .input-xlarge{width:270px}
192 .input-xlarge{width:270px}
197 .input-xxlarge{width:530px}
193 .input-xxlarge{width:530px}
198 input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}
194 input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}
199 .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}
195 .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}
200 input,textarea,.uneditable-input{margin-left:0}
196 input,textarea,.uneditable-input{margin-left:0}
201 .controls-row [class*="span"]+[class*="span"]{margin-left:20px}
197 .controls-row [class*="span"]+[class*="span"]{margin-left:20px}
202 input.span12,textarea.span12,.uneditable-input.span12{width:926px}
198 input.span12,textarea.span12,.uneditable-input.span12{width:926px}
203 input.span11,textarea.span11,.uneditable-input.span11{width:846px}
199 input.span11,textarea.span11,.uneditable-input.span11{width:846px}
204 input.span10,textarea.span10,.uneditable-input.span10{width:766px}
200 input.span10,textarea.span10,.uneditable-input.span10{width:766px}
205 input.span9,textarea.span9,.uneditable-input.span9{width:686px}
201 input.span9,textarea.span9,.uneditable-input.span9{width:686px}
206 input.span8,textarea.span8,.uneditable-input.span8{width:606px}
202 input.span8,textarea.span8,.uneditable-input.span8{width:606px}
207 input.span7,textarea.span7,.uneditable-input.span7{width:526px}
203 input.span7,textarea.span7,.uneditable-input.span7{width:526px}
208 input.span6,textarea.span6,.uneditable-input.span6{width:446px}
204 input.span6,textarea.span6,.uneditable-input.span6{width:446px}
209 input.span5,textarea.span5,.uneditable-input.span5{width:366px}
205 input.span5,textarea.span5,.uneditable-input.span5{width:366px}
210 input.span4,textarea.span4,.uneditable-input.span4{width:286px}
206 input.span4,textarea.span4,.uneditable-input.span4{width:286px}
211 input.span3,textarea.span3,.uneditable-input.span3{width:206px}
207 input.span3,textarea.span3,.uneditable-input.span3{width:206px}
212 input.span2,textarea.span2,.uneditable-input.span2{width:126px}
208 input.span2,textarea.span2,.uneditable-input.span2{width:126px}
213 input.span1,textarea.span1,.uneditable-input.span1{width:46px}
209 input.span1,textarea.span1,.uneditable-input.span1{width:46px}
214 .controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0}
210 .controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0}
215 .controls-row:after{clear:both}
211 .controls-row:after{clear:both}
216 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}
212 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}
217 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}
213 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}
218 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}
214 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}
219 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}
215 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}
220 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}
216 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}
221 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}
217 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}
222 .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}
218 .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}
223 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}
219 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}
224 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}
220 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}
225 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}
221 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}
226 .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}
222 .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}
227 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}
223 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}
228 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}
224 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}
229 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}
225 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}
230 .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}
226 .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}
231 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}
227 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}
232 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}
228 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}
233 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}
229 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}
234 .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}
230 .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}
235 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}
231 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}
236 input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}
232 input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}
237 .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0}
233 .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0}
238 .form-actions:after{clear:both}
234 .form-actions:after{clear:both}
239 .help-block,.help-inline{color:#262626}
235 .help-block,.help-inline{color:#262626}
240 .help-block{display:block;margin-bottom:10px}
236 .help-block{display:block;margin-bottom:10px}
241 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px}
237 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px}
242 .input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:13px}
238 .input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:13px}
243 .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}
239 .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}
244 .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:13px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}
240 .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:13px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}
245 .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
241 .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
246 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}
242 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}
247 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px}
243 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px}
248 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
244 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
249 .input-append input,.input-append select,.input-append .uneditable-input{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
245 .input-append input,.input-append select,.input-append .uneditable-input{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
250 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}
246 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}
251 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
247 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
252 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
248 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
253 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
249 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
254 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
250 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
255 .input-prepend.input-append .btn-group:first-child{margin-left:0}
251 .input-prepend.input-append .btn-group:first-child{margin-left:0}
256 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
252 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
257 .form-search .input-append .search-query,.form-search .input-prepend .search-query{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
253 .form-search .input-append .search-query,.form-search .input-prepend .search-query{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
258 .form-search .input-append .search-query{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
254 .form-search .input-append .search-query{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
259 .form-search .input-append .btn{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
255 .form-search .input-append .btn{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
260 .form-search .input-prepend .search-query{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
256 .form-search .input-prepend .search-query{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
261 .form-search .input-prepend .btn{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
257 .form-search .input-prepend .btn{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
262 .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle}
258 .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle}
263 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}
259 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}
264 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}
260 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}
265 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}
261 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}
266 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}
262 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}
267 .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}
263 .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}
268 .control-group{margin-bottom:10px}
264 .control-group{margin-bottom:10px}
269 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}
265 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}
270 .form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0}
266 .form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0}
271 .form-horizontal .control-group:after{clear:both}
267 .form-horizontal .control-group:after{clear:both}
272 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}
268 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}
273 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}
269 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}
274 .form-horizontal .help-block{margin-bottom:0}
270 .form-horizontal .help-block{margin-bottom:0}
275 .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}
271 .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}
276 .form-horizontal .form-actions{padding-left:180px}
272 .form-horizontal .form-actions{padding-left:180px}
277 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}
273 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}
278 .table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}
274 .table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}
279 .table th{font-weight:bold}
275 .table th{font-weight:bold}
280 .table thead th{vertical-align:bottom}
276 .table thead th{vertical-align:bottom}
281 .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}
277 .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}
282 .table tbody+tbody{border-top:2px solid #ddd}
278 .table tbody+tbody{border-top:2px solid #ddd}
283 .table .table{background-color:#fff}
279 .table .table{background-color:#fff}
284 .table-condensed th,.table-condensed td{padding:4px 5px}
280 .table-condensed th,.table-condensed td{padding:4px 5px}
285 .table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}
281 .table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}
286 .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}
282 .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}
287 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
283 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
288 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
284 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
289 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
285 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
290 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
286 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
291 .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0}
287 .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0}
292 .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0}
288 .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0}
293 .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
289 .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
294 .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
290 .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
295 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
291 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
296 .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}
292 .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}
297 table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}
293 table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}
298 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0}
294 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0}
299 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0}
295 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0}
300 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0}
296 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0}
301 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0}
297 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0}
302 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0}
298 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0}
303 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0}
299 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0}
304 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0}
300 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0}
305 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0}
301 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0}
306 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0}
302 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0}
307 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0}
303 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0}
308 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0}
304 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0}
309 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0}
305 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0}
310 .table tbody tr.success>td{background-color:#dff0d8}
306 .table tbody tr.success>td{background-color:#dff0d8}
311 .table tbody tr.error>td{background-color:#f2dede}
307 .table tbody tr.error>td{background-color:#f2dede}
312 .table tbody tr.warning>td{background-color:#fcf8e3}
308 .table tbody tr.warning>td{background-color:#fcf8e3}
313 .table tbody tr.info>td{background-color:#d9edf7}
309 .table tbody tr.info>td{background-color:#d9edf7}
314 .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}
310 .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}
315 .table-hover tbody tr.error:hover>td{background-color:#ebcccc}
311 .table-hover tbody tr.error:hover>td{background-color:#ebcccc}
316 .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}
312 .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}
317 .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}
313 .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}
318 [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px}
314 [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px}
319 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}
315 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}
320 .icon-glass{background-position:0 0}
316 .icon-glass{background-position:0 0}
321 .icon-music{background-position:-24px 0}
317 .icon-music{background-position:-24px 0}
322 .icon-search{background-position:-48px 0}
318 .icon-search{background-position:-48px 0}
323 .icon-envelope{background-position:-72px 0}
319 .icon-envelope{background-position:-72px 0}
324 .icon-heart{background-position:-96px 0}
320 .icon-heart{background-position:-96px 0}
325 .icon-star{background-position:-120px 0}
321 .icon-star{background-position:-120px 0}
326 .icon-star-empty{background-position:-144px 0}
322 .icon-star-empty{background-position:-144px 0}
327 .icon-user{background-position:-168px 0}
323 .icon-user{background-position:-168px 0}
328 .icon-film{background-position:-192px 0}
324 .icon-film{background-position:-192px 0}
329 .icon-th-large{background-position:-216px 0}
325 .icon-th-large{background-position:-216px 0}
330 .icon-th{background-position:-240px 0}
326 .icon-th{background-position:-240px 0}
331 .icon-th-list{background-position:-264px 0}
327 .icon-th-list{background-position:-264px 0}
332 .icon-ok{background-position:-288px 0}
328 .icon-ok{background-position:-288px 0}
333 .icon-remove{background-position:-312px 0}
329 .icon-remove{background-position:-312px 0}
334 .icon-zoom-in{background-position:-336px 0}
330 .icon-zoom-in{background-position:-336px 0}
335 .icon-zoom-out{background-position:-360px 0}
331 .icon-zoom-out{background-position:-360px 0}
336 .icon-off{background-position:-384px 0}
332 .icon-off{background-position:-384px 0}
337 .icon-signal{background-position:-408px 0}
333 .icon-signal{background-position:-408px 0}
338 .icon-cog{background-position:-432px 0}
334 .icon-cog{background-position:-432px 0}
339 .icon-trash{background-position:-456px 0}
335 .icon-trash{background-position:-456px 0}
340 .icon-home{background-position:0 -24px}
336 .icon-home{background-position:0 -24px}
341 .icon-file{background-position:-24px -24px}
337 .icon-file{background-position:-24px -24px}
342 .icon-time{background-position:-48px -24px}
338 .icon-time{background-position:-48px -24px}
343 .icon-road{background-position:-72px -24px}
339 .icon-road{background-position:-72px -24px}
344 .icon-download-alt{background-position:-96px -24px}
340 .icon-download-alt{background-position:-96px -24px}
345 .icon-download{background-position:-120px -24px}
341 .icon-download{background-position:-120px -24px}
346 .icon-upload{background-position:-144px -24px}
342 .icon-upload{background-position:-144px -24px}
347 .icon-inbox{background-position:-168px -24px}
343 .icon-inbox{background-position:-168px -24px}
348 .icon-play-circle{background-position:-192px -24px}
344 .icon-play-circle{background-position:-192px -24px}
349 .icon-repeat{background-position:-216px -24px}
345 .icon-repeat{background-position:-216px -24px}
350 .icon-refresh{background-position:-240px -24px}
346 .icon-refresh{background-position:-240px -24px}
351 .icon-list-alt{background-position:-264px -24px}
347 .icon-list-alt{background-position:-264px -24px}
352 .icon-lock{background-position:-287px -24px}
348 .icon-lock{background-position:-287px -24px}
353 .icon-flag{background-position:-312px -24px}
349 .icon-flag{background-position:-312px -24px}
354 .icon-headphones{background-position:-336px -24px}
350 .icon-headphones{background-position:-336px -24px}
355 .icon-volume-off{background-position:-360px -24px}
351 .icon-volume-off{background-position:-360px -24px}
356 .icon-volume-down{background-position:-384px -24px}
352 .icon-volume-down{background-position:-384px -24px}
357 .icon-volume-up{background-position:-408px -24px}
353 .icon-volume-up{background-position:-408px -24px}
358 .icon-qrcode{background-position:-432px -24px}
354 .icon-qrcode{background-position:-432px -24px}
359 .icon-barcode{background-position:-456px -24px}
355 .icon-barcode{background-position:-456px -24px}
360 .icon-tag{background-position:0 -48px}
356 .icon-tag{background-position:0 -48px}
361 .icon-tags{background-position:-25px -48px}
357 .icon-tags{background-position:-25px -48px}
362 .icon-book{background-position:-48px -48px}
358 .icon-book{background-position:-48px -48px}
363 .icon-bookmark{background-position:-72px -48px}
359 .icon-bookmark{background-position:-72px -48px}
364 .icon-print{background-position:-96px -48px}
360 .icon-print{background-position:-96px -48px}
365 .icon-camera{background-position:-120px -48px}
361 .icon-camera{background-position:-120px -48px}
366 .icon-font{background-position:-144px -48px}
362 .icon-font{background-position:-144px -48px}
367 .icon-bold{background-position:-167px -48px}
363 .icon-bold{background-position:-167px -48px}
368 .icon-italic{background-position:-192px -48px}
364 .icon-italic{background-position:-192px -48px}
369 .icon-text-height{background-position:-216px -48px}
365 .icon-text-height{background-position:-216px -48px}
370 .icon-text-width{background-position:-240px -48px}
366 .icon-text-width{background-position:-240px -48px}
371 .icon-align-left{background-position:-264px -48px}
367 .icon-align-left{background-position:-264px -48px}
372 .icon-align-center{background-position:-288px -48px}
368 .icon-align-center{background-position:-288px -48px}
373 .icon-align-right{background-position:-312px -48px}
369 .icon-align-right{background-position:-312px -48px}
374 .icon-align-justify{background-position:-336px -48px}
370 .icon-align-justify{background-position:-336px -48px}
375 .icon-list{background-position:-360px -48px}
371 .icon-list{background-position:-360px -48px}
376 .icon-indent-left{background-position:-384px -48px}
372 .icon-indent-left{background-position:-384px -48px}
377 .icon-indent-right{background-position:-408px -48px}
373 .icon-indent-right{background-position:-408px -48px}
378 .icon-facetime-video{background-position:-432px -48px}
374 .icon-facetime-video{background-position:-432px -48px}
379 .icon-picture{background-position:-456px -48px}
375 .icon-picture{background-position:-456px -48px}
380 .icon-pencil{background-position:0 -72px}
376 .icon-pencil{background-position:0 -72px}
381 .icon-map-marker{background-position:-24px -72px}
377 .icon-map-marker{background-position:-24px -72px}
382 .icon-adjust{background-position:-48px -72px}
378 .icon-adjust{background-position:-48px -72px}
383 .icon-tint{background-position:-72px -72px}
379 .icon-tint{background-position:-72px -72px}
384 .icon-edit{background-position:-96px -72px}
380 .icon-edit{background-position:-96px -72px}
385 .icon-share{background-position:-120px -72px}
381 .icon-share{background-position:-120px -72px}
386 .icon-check{background-position:-144px -72px}
382 .icon-check{background-position:-144px -72px}
387 .icon-move{background-position:-168px -72px}
383 .icon-move{background-position:-168px -72px}
388 .icon-step-backward{background-position:-192px -72px}
384 .icon-step-backward{background-position:-192px -72px}
389 .icon-fast-backward{background-position:-216px -72px}
385 .icon-fast-backward{background-position:-216px -72px}
390 .icon-backward{background-position:-240px -72px}
386 .icon-backward{background-position:-240px -72px}
391 .icon-play{background-position:-264px -72px}
387 .icon-play{background-position:-264px -72px}
392 .icon-pause{background-position:-288px -72px}
388 .icon-pause{background-position:-288px -72px}
393 .icon-stop{background-position:-312px -72px}
389 .icon-stop{background-position:-312px -72px}
394 .icon-forward{background-position:-336px -72px}
390 .icon-forward{background-position:-336px -72px}
395 .icon-fast-forward{background-position:-360px -72px}
391 .icon-fast-forward{background-position:-360px -72px}
396 .icon-step-forward{background-position:-384px -72px}
392 .icon-step-forward{background-position:-384px -72px}
397 .icon-eject{background-position:-408px -72px}
393 .icon-eject{background-position:-408px -72px}
398 .icon-chevron-left{background-position:-432px -72px}
394 .icon-chevron-left{background-position:-432px -72px}
399 .icon-chevron-right{background-position:-456px -72px}
395 .icon-chevron-right{background-position:-456px -72px}
400 .icon-plus-sign{background-position:0 -96px}
396 .icon-plus-sign{background-position:0 -96px}
401 .icon-minus-sign{background-position:-24px -96px}
397 .icon-minus-sign{background-position:-24px -96px}
402 .icon-remove-sign{background-position:-48px -96px}
398 .icon-remove-sign{background-position:-48px -96px}
403 .icon-ok-sign{background-position:-72px -96px}
399 .icon-ok-sign{background-position:-72px -96px}
404 .icon-question-sign{background-position:-96px -96px}
400 .icon-question-sign{background-position:-96px -96px}
405 .icon-info-sign{background-position:-120px -96px}
401 .icon-info-sign{background-position:-120px -96px}
406 .icon-screenshot{background-position:-144px -96px}
402 .icon-screenshot{background-position:-144px -96px}
407 .icon-remove-circle{background-position:-168px -96px}
403 .icon-remove-circle{background-position:-168px -96px}
408 .icon-ok-circle{background-position:-192px -96px}
404 .icon-ok-circle{background-position:-192px -96px}
409 .icon-ban-circle{background-position:-216px -96px}
405 .icon-ban-circle{background-position:-216px -96px}
410 .icon-arrow-left{background-position:-240px -96px}
406 .icon-arrow-left{background-position:-240px -96px}
411 .icon-arrow-right{background-position:-264px -96px}
407 .icon-arrow-right{background-position:-264px -96px}
412 .icon-arrow-up{background-position:-289px -96px}
408 .icon-arrow-up{background-position:-289px -96px}
413 .icon-arrow-down{background-position:-312px -96px}
409 .icon-arrow-down{background-position:-312px -96px}
414 .icon-share-alt{background-position:-336px -96px}
410 .icon-share-alt{background-position:-336px -96px}
415 .icon-resize-full{background-position:-360px -96px}
411 .icon-resize-full{background-position:-360px -96px}
416 .icon-resize-small{background-position:-384px -96px}
412 .icon-resize-small{background-position:-384px -96px}
417 .icon-plus{background-position:-408px -96px}
413 .icon-plus{background-position:-408px -96px}
418 .icon-minus{background-position:-433px -96px}
414 .icon-minus{background-position:-433px -96px}
419 .icon-asterisk{background-position:-456px -96px}
415 .icon-asterisk{background-position:-456px -96px}
420 .icon-exclamation-sign{background-position:0 -120px}
416 .icon-exclamation-sign{background-position:0 -120px}
421 .icon-gift{background-position:-24px -120px}
417 .icon-gift{background-position:-24px -120px}
422 .icon-leaf{background-position:-48px -120px}
418 .icon-leaf{background-position:-48px -120px}
423 .icon-fire{background-position:-72px -120px}
419 .icon-fire{background-position:-72px -120px}
424 .icon-eye-open{background-position:-96px -120px}
420 .icon-eye-open{background-position:-96px -120px}
425 .icon-eye-close{background-position:-120px -120px}
421 .icon-eye-close{background-position:-120px -120px}
426 .icon-warning-sign{background-position:-144px -120px}
422 .icon-warning-sign{background-position:-144px -120px}
427 .icon-plane{background-position:-168px -120px}
423 .icon-plane{background-position:-168px -120px}
428 .icon-calendar{background-position:-192px -120px}
424 .icon-calendar{background-position:-192px -120px}
429 .icon-random{background-position:-216px -120px;width:16px}
425 .icon-random{background-position:-216px -120px;width:16px}
430 .icon-comment{background-position:-240px -120px}
426 .icon-comment{background-position:-240px -120px}
431 .icon-magnet{background-position:-264px -120px}
427 .icon-magnet{background-position:-264px -120px}
432 .icon-chevron-up{background-position:-288px -120px}
428 .icon-chevron-up{background-position:-288px -120px}
433 .icon-chevron-down{background-position:-313px -119px}
429 .icon-chevron-down{background-position:-313px -119px}
434 .icon-retweet{background-position:-336px -120px}
430 .icon-retweet{background-position:-336px -120px}
435 .icon-shopping-cart{background-position:-360px -120px}
431 .icon-shopping-cart{background-position:-360px -120px}
436 .icon-folder-close{background-position:-384px -120px;width:16px}
432 .icon-folder-close{background-position:-384px -120px;width:16px}
437 .icon-folder-open{background-position:-408px -120px;width:16px}
433 .icon-folder-open{background-position:-408px -120px;width:16px}
438 .icon-resize-vertical{background-position:-432px -119px}
434 .icon-resize-vertical{background-position:-432px -119px}
439 .icon-resize-horizontal{background-position:-456px -118px}
435 .icon-resize-horizontal{background-position:-456px -118px}
440 .icon-hdd{background-position:0 -144px}
436 .icon-hdd{background-position:0 -144px}
441 .icon-bullhorn{background-position:-24px -144px}
437 .icon-bullhorn{background-position:-24px -144px}
442 .icon-bell{background-position:-48px -144px}
438 .icon-bell{background-position:-48px -144px}
443 .icon-certificate{background-position:-72px -144px}
439 .icon-certificate{background-position:-72px -144px}
444 .icon-thumbs-up{background-position:-96px -144px}
440 .icon-thumbs-up{background-position:-96px -144px}
445 .icon-thumbs-down{background-position:-120px -144px}
441 .icon-thumbs-down{background-position:-120px -144px}
446 .icon-hand-right{background-position:-144px -144px}
442 .icon-hand-right{background-position:-144px -144px}
447 .icon-hand-left{background-position:-168px -144px}
443 .icon-hand-left{background-position:-168px -144px}
448 .icon-hand-up{background-position:-192px -144px}
444 .icon-hand-up{background-position:-192px -144px}
449 .icon-hand-down{background-position:-216px -144px}
445 .icon-hand-down{background-position:-216px -144px}
450 .icon-circle-arrow-right{background-position:-240px -144px}
446 .icon-circle-arrow-right{background-position:-240px -144px}
451 .icon-circle-arrow-left{background-position:-264px -144px}
447 .icon-circle-arrow-left{background-position:-264px -144px}
452 .icon-circle-arrow-up{background-position:-288px -144px}
448 .icon-circle-arrow-up{background-position:-288px -144px}
453 .icon-circle-arrow-down{background-position:-312px -144px}
449 .icon-circle-arrow-down{background-position:-312px -144px}
454 .icon-globe{background-position:-336px -144px}
450 .icon-globe{background-position:-336px -144px}
455 .icon-wrench{background-position:-360px -144px}
451 .icon-wrench{background-position:-360px -144px}
456 .icon-tasks{background-position:-384px -144px}
452 .icon-tasks{background-position:-384px -144px}
457 .icon-filter{background-position:-408px -144px}
453 .icon-filter{background-position:-408px -144px}
458 .icon-briefcase{background-position:-432px -144px}
454 .icon-briefcase{background-position:-432px -144px}
459 .icon-fullscreen{background-position:-456px -144px}
455 .icon-fullscreen{background-position:-456px -144px}
460 .dropup,.dropdown{position:relative}
456 .dropup,.dropdown{position:relative}
461 .dropdown-toggle{*margin-bottom:-3px}
457 .dropdown-toggle{*margin-bottom:-3px}
462 .dropdown-toggle:active,.open .dropdown-toggle{outline:0}
458 .dropdown-toggle:active,.open .dropdown-toggle{outline:0}
463 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}
459 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}
464 .dropdown .caret{margin-top:8px;margin-left:2px}
460 .dropdown .caret{margin-top:8px;margin-left:2px}
465 .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
461 .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
466 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
462 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
467 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}
463 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}
468 .dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
464 .dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
469 .dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
465 .dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
470 .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
466 .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
471 .dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default}
467 .dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default}
472 .open{*z-index:1000}.open>.dropdown-menu{display:block}
468 .open{*z-index:1000}.open>.dropdown-menu{display:block}
473 .dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}
469 .dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}
474 .pull-right>.dropdown-menu{right:0;left:auto}
470 .pull-right>.dropdown-menu{right:0;left:auto}
475 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}
471 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}
476 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}
472 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}
477 .dropdown-submenu{position:relative}
473 .dropdown-submenu{position:relative}
478 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px 6px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}
474 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px 6px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}
479 .dropdown-submenu:hover>.dropdown-menu{display:block}
475 .dropdown-submenu:hover>.dropdown-menu{display:block}
480 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:5px 5px 5px 0;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}
476 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:5px 5px 5px 0;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}
481 .dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}
477 .dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}
482 .dropdown-submenu:hover>a:after{border-left-color:#fff}
478 .dropdown-submenu:hover>a:after{border-left-color:#fff}
483 .dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
479 .dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
484 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}
480 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}
485 .typeahead{z-index:1051;margin-top:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
481 .typeahead{z-index:1051;margin-top:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
486 .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}
482 .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}
487 .well-large{padding:24px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
483 .well-large{padding:24px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
488 .well-small{padding:9px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
484 .well-small{padding:9px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
489 .fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}
485 .fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}
490 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}
486 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}
491 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}
487 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}
492 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}
488 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}
493 .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:13px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #fff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #fff, #e6e6e6);background-image:-o-linear-gradient(top, #fff, #e6e6e6);background-image:linear-gradient(to bottom, #fff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}
489 .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:13px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #fff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #fff, #e6e6e6);background-image:-o-linear-gradient(top, #fff, #e6e6e6);background-image:linear-gradient(to bottom, #fff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}
494 .btn:active,.btn.active{background-color:#ccc \9}
490 .btn:active,.btn.active{background-color:#ccc \9}
495 .btn:first-child{*margin-left:0}
491 .btn:first-child{*margin-left:0}
496 .btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}
492 .btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}
497 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
493 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
498 .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
494 .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
499 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
495 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
500 .btn-large{padding:11px 19px;font-size:16.25px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
496 .btn-large{padding:11px 19px;font-size:16.25px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
501 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}
497 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}
502 .btn-small{padding:2px 10px;font-size:11.049999999999999px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
498 .btn-small{padding:2px 10px;font-size:11.049999999999999px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
503 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}
499 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}
504 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}
500 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}
505 .btn-mini{padding:0 6px;font-size:9.75px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
501 .btn-mini{padding:0 6px;font-size:9.75px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
506 .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
502 .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
507 .btn-block+.btn-block{margin-top:5px}
503 .btn-block+.btn-block{margin-top:5px}
508 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}
504 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}
509 .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}
505 .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}
510 .btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}
506 .btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}
511 .btn-primary:active,.btn-primary.active{background-color:#039 \9}
507 .btn-primary:active,.btn-primary.active{background-color:#039 \9}
512 .btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}
508 .btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}
513 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9}
509 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9}
514 .btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}
510 .btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}
515 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9}
511 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9}
516 .btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}
512 .btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}
517 .btn-success:active,.btn-success.active{background-color:#408140 \9}
513 .btn-success:active,.btn-success.active{background-color:#408140 \9}
518 .btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}
514 .btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}
519 .btn-info:active,.btn-info.active{background-color:#24748c \9}
515 .btn-info:active,.btn-info.active{background-color:#24748c \9}
520 .btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444, #222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#222));background-image:-webkit-linear-gradient(top, #444, #222);background-image:-o-linear-gradient(top, #444, #222);background-image:linear-gradient(to bottom, #444, #222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}
516 .btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444, #222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#222));background-image:-webkit-linear-gradient(top, #444, #222);background-image:-o-linear-gradient(top, #444, #222);background-image:linear-gradient(to bottom, #444, #222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}
521 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}
517 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}
522 button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}
518 button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}
523 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}
519 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}
524 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}
520 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}
525 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}
521 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}
526 .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
522 .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
527 .btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
523 .btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
528 .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}
524 .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}
529 .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}
525 .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}
530 .btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em}.btn-group:first-child{*margin-left:0}
526 .btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em}.btn-group:first-child{*margin-left:0}
531 .btn-group+.btn-group{margin-left:5px}
527 .btn-group+.btn-group{margin-left:5px}
532 .btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}
528 .btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}
533 .btn-group>.btn{position:relative;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
529 .btn-group>.btn{position:relative;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
534 .btn-group>.btn+.btn{margin-left:-1px}
530 .btn-group>.btn+.btn{margin-left:-1px}
535 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px}
531 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px}
536 .btn-group>.btn-mini{font-size:9.75px}
532 .btn-group>.btn-mini{font-size:9.75px}
537 .btn-group>.btn-small{font-size:11.049999999999999px}
533 .btn-group>.btn-small{font-size:11.049999999999999px}
538 .btn-group>.btn-large{font-size:16.25px}
534 .btn-group>.btn-large{font-size:16.25px}
539 .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
535 .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
540 .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
536 .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
541 .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
537 .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
542 .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
538 .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
543 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}
539 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}
544 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}
540 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}
545 .btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px}
541 .btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px}
546 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px}
542 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px}
547 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}
543 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}
548 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px}
544 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px}
549 .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
545 .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
550 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}
546 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}
551 .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}
547 .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}
552 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}
548 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}
553 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}
549 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}
554 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}
550 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}
555 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}
551 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}
556 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}
552 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}
557 .btn .caret{margin-top:8px;margin-left:0}
553 .btn .caret{margin-top:8px;margin-left:0}
558 .btn-large .caret{margin-top:6px}
554 .btn-large .caret{margin-top:6px}
559 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}
555 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}
560 .btn-mini .caret,.btn-small .caret{margin-top:8px}
556 .btn-mini .caret,.btn-small .caret{margin-top:8px}
561 .dropup .btn-large .caret{border-bottom-width:5px}
557 .dropup .btn-large .caret{border-bottom-width:5px}
562 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}
558 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}
563 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}
559 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}
564 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
560 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
565 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}
561 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}
566 .btn-group-vertical>.btn:first-child{border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}
562 .btn-group-vertical>.btn:first-child{border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}
567 .btn-group-vertical>.btn:last-child{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}
563 .btn-group-vertical>.btn:last-child{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}
568 .btn-group-vertical>.btn-large:first-child{border-radius:6px 6px 0 0;-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}
564 .btn-group-vertical>.btn-large:first-child{border-radius:6px 6px 0 0;-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}
569 .btn-group-vertical>.btn-large:last-child{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
565 .btn-group-vertical>.btn-large:last-child{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
570 .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
566 .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
571 .alert,.alert h4{color:#c09853}
567 .alert,.alert h4{color:#c09853}
572 .alert h4{margin:0}
568 .alert h4{margin:0}
573 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}
569 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}
574 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}
570 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}
575 .alert-success h4{color:#468847}
571 .alert-success h4{color:#468847}
576 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}
572 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}
577 .alert-danger h4,.alert-error h4{color:#b94a48}
573 .alert-danger h4,.alert-error h4{color:#b94a48}
578 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}
574 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}
579 .alert-info h4{color:#3a87ad}
575 .alert-info h4{color:#3a87ad}
580 .alert-block{padding-top:14px;padding-bottom:14px}
576 .alert-block{padding-top:14px;padding-bottom:14px}
581 .alert-block>p,.alert-block>ul{margin-bottom:0}
577 .alert-block>p,.alert-block>ul{margin-bottom:0}
582 .alert-block p+p{margin-top:5px}
578 .alert-block p+p{margin-top:5px}
583 .nav{margin-left:0;margin-bottom:20px;list-style:none}
579 .nav{margin-left:0;margin-bottom:20px;list-style:none}
584 .nav>li>a{display:block}
580 .nav>li>a{display:block}
585 .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
581 .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
586 .nav>li>a>img{max-width:none}
582 .nav>li>a>img{max-width:none}
587 .nav>.pull-right{float:right}
583 .nav>.pull-right{float:right}
588 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}
584 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}
589 .nav li+.nav-header{margin-top:9px}
585 .nav li+.nav-header{margin-top:9px}
590 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}
586 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}
591 .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}
587 .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}
592 .nav-list>li>a{padding:3px 15px}
588 .nav-list>li>a{padding:3px 15px}
593 .nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}
589 .nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}
594 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}
590 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}
595 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
591 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
596 .nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0}
592 .nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0}
597 .nav-tabs:after,.nav-pills:after{clear:both}
593 .nav-tabs:after,.nav-pills:after{clear:both}
598 .nav-tabs>li,.nav-pills>li{float:left}
594 .nav-tabs>li,.nav-pills>li{float:left}
599 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}
595 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}
600 .nav-tabs{border-bottom:1px solid #ddd}
596 .nav-tabs{border-bottom:1px solid #ddd}
601 .nav-tabs>li{margin-bottom:-1px}
597 .nav-tabs>li{margin-bottom:-1px}
602 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}
598 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}
603 .nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
599 .nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
604 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
600 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
605 .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}
601 .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}
606 .nav-stacked>li{float:none}
602 .nav-stacked>li{float:none}
607 .nav-stacked>li>a{margin-right:0}
603 .nav-stacked>li>a{margin-right:0}
608 .nav-tabs.nav-stacked{border-bottom:0}
604 .nav-tabs.nav-stacked{border-bottom:0}
609 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
605 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
610 .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
606 .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
611 .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
607 .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
612 .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2}
608 .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2}
613 .nav-pills.nav-stacked>li>a{margin-bottom:3px}
609 .nav-pills.nav-stacked>li>a{margin-bottom:3px}
614 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}
610 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}
615 .nav-tabs .dropdown-menu{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
611 .nav-tabs .dropdown-menu{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
616 .nav-pills .dropdown-menu{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
612 .nav-pills .dropdown-menu{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
617 .nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}
613 .nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}
618 .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}
614 .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}
619 .nav-tabs .dropdown-toggle .caret{margin-top:8px}
615 .nav-tabs .dropdown-toggle .caret{margin-top:8px}
620 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
616 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
621 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
617 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
622 .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}
618 .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}
623 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}
619 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}
624 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}
620 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}
625 .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}
621 .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}
626 .tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0}
622 .tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0}
627 .tabbable:after{clear:both}
623 .tabbable:after{clear:both}
628 .tab-content{overflow:auto}
624 .tab-content{overflow:auto}
629 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}
625 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}
630 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
626 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
631 .tab-content>.active,.pill-content>.active{display:block}
627 .tab-content>.active,.pill-content>.active{display:block}
632 .tabs-below>.nav-tabs{border-top:1px solid #ddd}
628 .tabs-below>.nav-tabs{border-top:1px solid #ddd}
633 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}
629 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}
634 .tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd}
630 .tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd}
635 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}
631 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}
636 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}
632 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}
637 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}
633 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}
638 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}
634 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}
639 .tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
635 .tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
640 .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}
636 .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}
641 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}
637 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}
642 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}
638 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}
643 .tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
639 .tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
644 .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}
640 .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}
645 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}
641 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}
646 .nav>.disabled>a{color:#999}
642 .nav>.disabled>a{color:#999}
647 .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default}
643 .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default}
648 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2}
644 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2}
649 .navbar-inner{min-height:36px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #fff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #fff, #f2f2f2);background-image:-o-linear-gradient(top, #fff, #f2f2f2);background-image:linear-gradient(to bottom, #fff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);*zoom:1}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0}
645 .navbar-inner{min-height:36px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #fff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #fff, #f2f2f2);background-image:-o-linear-gradient(top, #fff, #f2f2f2);background-image:linear-gradient(to bottom, #fff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);*zoom:1}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0}
650 .navbar-inner:after{clear:both}
646 .navbar-inner:after{clear:both}
651 .navbar .container{width:auto}
647 .navbar .container{width:auto}
652 .nav-collapse.collapse{height:auto;overflow:visible}
648 .nav-collapse.collapse{height:auto;overflow:visible}
653 .navbar .brand{float:left;display:block;padding:8px 20px 8px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}
649 .navbar .brand{float:left;display:block;padding:8px 20px 8px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}
654 .navbar-text{margin-bottom:0;line-height:36px;color:#777}
650 .navbar-text{margin-bottom:0;line-height:36px;color:#777}
655 .navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}
651 .navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}
656 .navbar .divider-vertical{height:36px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}
652 .navbar .divider-vertical{height:36px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}
657 .navbar .btn,.navbar .btn-group{margin-top:3px}
653 .navbar .btn,.navbar .btn-group{margin-top:3px}
658 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}
654 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}
659 .navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0}
655 .navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0}
660 .navbar-form:after{clear:both}
656 .navbar-form:after{clear:both}
661 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:3px}
657 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:3px}
662 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}
658 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}
663 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}
659 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}
664 .navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}
660 .navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}
665 .navbar-search{position:relative;float:left;margin-top:3px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
661 .navbar-search{position:relative;float:left;margin-top:3px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
666 .navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
662 .navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
667 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}
663 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}
668 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}
664 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}
669 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}
665 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}
670 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
666 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
671 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
667 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
672 .navbar-fixed-top{top:0}
668 .navbar-fixed-top{top:0}
673 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1)}
669 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1)}
674 .navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1)}
670 .navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1)}
675 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}
671 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}
676 .navbar .nav.pull-right{float:right;margin-right:0}
672 .navbar .nav.pull-right{float:right;margin-right:0}
677 .navbar .nav>li{float:left}
673 .navbar .nav>li{float:left}
678 .navbar .nav>li>a{float:none;padding:8px 15px 8px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}
674 .navbar .nav>li>a{float:none;padding:8px 15px 8px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}
679 .navbar .nav .dropdown-toggle .caret{margin-top:8px}
675 .navbar .nav .dropdown-toggle .caret{margin-top:8px}
680 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}
676 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}
681 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}
677 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}
682 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}
678 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}
683 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}
679 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}
684 .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}
680 .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}
685 .btn-navbar .icon-bar+.icon-bar{margin-top:3px}
681 .btn-navbar .icon-bar+.icon-bar{margin-top:3px}
686 .navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:9px}
682 .navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:9px}
687 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}
683 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}
688 .navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);border-bottom:0;bottom:-7px;top:auto}
684 .navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);border-bottom:0;bottom:-7px;top:auto}
689 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}
685 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}
690 .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}
686 .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}
691 .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555}
687 .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555}
692 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}
688 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}
693 .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
689 .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
694 .navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px}
690 .navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px}
695 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px}
691 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px}
696 .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
692 .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
697 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222, #111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222), to(#111));background-image:-webkit-linear-gradient(top, #222, #111);background-image:-o-linear-gradient(top, #222, #111);background-image:linear-gradient(to bottom, #222, #111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525}
693 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222, #111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222), to(#111));background-image:-webkit-linear-gradient(top, #222, #111);background-image:-o-linear-gradient(top, #222, #111);background-image:linear-gradient(to bottom, #222, #111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525}
698 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}
694 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}
699 .navbar-inverse .brand{color:#999}
695 .navbar-inverse .brand{color:#999}
700 .navbar-inverse .navbar-text{color:#999}
696 .navbar-inverse .navbar-text{color:#999}
701 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}
697 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}
702 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}
698 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}
703 .navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}
699 .navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}
704 .navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}
700 .navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}
705 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111;color:#fff}
701 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111;color:#fff}
706 .navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}
702 .navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}
707 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}
703 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}
708 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
704 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
709 .navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}
705 .navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}
710 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}
706 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}
711 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}
707 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}
712 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15);outline:0}
708 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15);outline:0}
713 .navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}
709 .navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}
714 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}
710 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}
715 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #fff}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}
711 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #fff}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}
716 .breadcrumb>.active{color:#999}
712 .breadcrumb>.active{color:#999}
717 .pagination{margin:20px 0}
713 .pagination{margin:20px 0}
718 .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}
714 .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}
719 .pagination ul>li{display:inline}
715 .pagination ul>li{display:inline}
720 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}
716 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}
721 .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}
717 .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}
722 .pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}
718 .pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}
723 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;background-color:transparent;cursor:default}
719 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;background-color:transparent;cursor:default}
724 .pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
720 .pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
725 .pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
721 .pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
726 .pagination-centered{text-align:center}
722 .pagination-centered{text-align:center}
727 .pagination-right{text-align:right}
723 .pagination-right{text-align:right}
728 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px}
724 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px}
729 .pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
725 .pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
730 .pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
726 .pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
731 .pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px}
727 .pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px}
732 .pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px}
728 .pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px}
733 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px}
729 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px}
734 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px}
730 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px}
735 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1}.pager:before,.pager:after{display:table;content:"";line-height:0}
731 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1}.pager:before,.pager:after{display:table;content:"";line-height:0}
736 .pager:after{clear:both}
732 .pager:after{clear:both}
737 .pager li{display:inline}
733 .pager li{display:inline}
738 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
734 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
739 .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}
735 .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}
740 .pager .next>a,.pager .next>span{float:right}
736 .pager .next>a,.pager .next>span{float:right}
741 .pager .previous>a,.pager .previous>span{float:left}
737 .pager .previous>a,.pager .previous>span{float:left}
742 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}
738 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}
743 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}
739 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}
744 .modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}
740 .modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}
745 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%}
741 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%}
746 .modal.fade.in{top:10%}
742 .modal.fade.in{top:10%}
747 .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}
743 .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}
748 .modal-header h3{margin:0;line-height:30px}
744 .modal-header h3{margin:0;line-height:30px}
749 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px}
745 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px}
750 .modal-form{margin-bottom:0}
746 .modal-form{margin-bottom:0}
751 .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff;*zoom:1}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0}
747 .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff;*zoom:1}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0}
752 .modal-footer:after{clear:both}
748 .modal-footer:after{clear:both}
753 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}
749 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}
754 .modal-footer .btn-group .btn+.btn{margin-left:-1px}
750 .modal-footer .btn-group .btn+.btn{margin-left:-1px}
755 .modal-footer .btn-block+.btn-block{margin-left:0}
751 .modal-footer .btn-block+.btn-block{margin-left:0}
756 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}
752 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}
757 .tooltip.top{margin-top:-3px;padding:5px 0}
753 .tooltip.top{margin-top:-3px;padding:5px 0}
758 .tooltip.right{margin-left:3px;padding:0 5px}
754 .tooltip.right{margin-left:3px;padding:0 5px}
759 .tooltip.bottom{margin-top:3px;padding:5px 0}
755 .tooltip.bottom{margin-top:3px;padding:5px 0}
760 .tooltip.left{margin-left:-3px;padding:0 5px}
756 .tooltip.left{margin-left:-3px;padding:0 5px}
761 .tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
757 .tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
762 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}
758 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}
763 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}
759 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}
764 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}
760 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}
765 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}
761 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}
766 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}
762 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}
767 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}
763 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}
768 .popover.right{margin-left:10px}
764 .popover.right{margin-left:10px}
769 .popover.bottom{margin-top:10px}
765 .popover.bottom{margin-top:10px}
770 .popover.left{margin-left:-10px}
766 .popover.left{margin-left:-10px}
771 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}
767 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}
772 .popover-content{padding:9px 14px}
768 .popover-content{padding:9px 14px}
773 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}
769 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}
774 .popover .arrow{border-width:11px}
770 .popover .arrow{border-width:11px}
775 .popover .arrow:after{border-width:10px;content:""}
771 .popover .arrow:after{border-width:10px;content:""}
776 .popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}
772 .popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}
777 .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}
773 .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}
778 .popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}
774 .popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}
779 .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}
775 .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}
780 .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0}
776 .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0}
781 .thumbnails:after{clear:both}
777 .thumbnails:after{clear:both}
782 .row-fluid .thumbnails{margin-left:0}
778 .row-fluid .thumbnails{margin-left:0}
783 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}
779 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}
784 .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
780 .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
785 a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}
781 a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}
786 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}
782 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}
787 .thumbnail .caption{padding:9px;color:#555}
783 .thumbnail .caption{padding:9px;color:#555}
788 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1}
784 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1}
789 .media,.media .media{margin-top:15px}
785 .media,.media .media{margin-top:15px}
790 .media:first-child{margin-top:0}
786 .media:first-child{margin-top:0}
791 .media-object{display:block}
787 .media-object{display:block}
792 .media-heading{margin:0 0 5px}
788 .media-heading{margin:0 0 5px}
793 .media>.pull-left{margin-right:10px}
789 .media>.pull-left{margin-right:10px}
794 .media>.pull-right{margin-left:10px}
790 .media>.pull-right{margin-left:10px}
795 .media-list{margin-left:0;list-style:none}
791 .media-list{margin-left:0;list-style:none}
796 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#999}
792 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#999}
797 .label{border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
793 .label{border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
798 .badge{padding-left:9px;padding-right:9px;border-radius:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}
794 .badge{padding-left:9px;padding-right:9px;border-radius:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}
799 .label:empty,.badge:empty{display:none}
795 .label:empty,.badge:empty{display:none}
800 a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
796 a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
801 .label-important,.badge-important{background-color:#b94a48}
797 .label-important,.badge-important{background-color:#b94a48}
802 .label-important[href],.badge-important[href]{background-color:#953b39}
798 .label-important[href],.badge-important[href]{background-color:#953b39}
803 .label-warning,.badge-warning{background-color:#f89406}
799 .label-warning,.badge-warning{background-color:#f89406}
804 .label-warning[href],.badge-warning[href]{background-color:#c67605}
800 .label-warning[href],.badge-warning[href]{background-color:#c67605}
805 .label-success,.badge-success{background-color:#468847}
801 .label-success,.badge-success{background-color:#468847}
806 .label-success[href],.badge-success[href]{background-color:#356635}
802 .label-success[href],.badge-success[href]{background-color:#356635}
807 .label-info,.badge-info{background-color:#3a87ad}
803 .label-info,.badge-info{background-color:#3a87ad}
808 .label-info[href],.badge-info[href]{background-color:#2d6987}
804 .label-info[href],.badge-info[href]{background-color:#2d6987}
809 .label-inverse,.badge-inverse{background-color:#333}
805 .label-inverse,.badge-inverse{background-color:#333}
810 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}
806 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}
811 .btn .label,.btn .badge{position:relative;top:-1px}
807 .btn .label,.btn .badge{position:relative;top:-1px}
812 .btn-mini .label,.btn-mini .badge{top:0}
808 .btn-mini .label,.btn-mini .badge{top:0}
813 @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0} to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
809 @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0} to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
814 .progress .bar{width:0;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}
810 .progress .bar{width:0;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}
815 .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)}
811 .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)}
816 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}
812 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}
817 .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}
813 .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}
818 .progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0)}
814 .progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0)}
819 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
815 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
820 .progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0)}
816 .progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0)}
821 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
817 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
822 .progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0)}
818 .progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0)}
823 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
819 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
824 .progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0)}
820 .progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0)}
825 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
821 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
826 .accordion{margin-bottom:20px}
822 .accordion{margin-bottom:20px}
827 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
823 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
828 .accordion-heading{border-bottom:0}
824 .accordion-heading{border-bottom:0}
829 .accordion-heading .accordion-toggle{display:block;padding:8px 15px}
825 .accordion-heading .accordion-toggle{display:block;padding:8px 15px}
830 .accordion-toggle{cursor:pointer}
826 .accordion-toggle{cursor:pointer}
831 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}
827 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}
832 .carousel{position:relative;margin-bottom:20px;line-height:1}
828 .carousel{position:relative;margin-bottom:20px;line-height:1}
833 .carousel-inner{overflow:hidden;width:100%;position:relative}
829 .carousel-inner{overflow:hidden;width:100%;position:relative}
834 .carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}
830 .carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}
835 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}
831 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}
836 .carousel-inner>.active{left:0}
832 .carousel-inner>.active{left:0}
837 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}
833 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}
838 .carousel-inner>.next{left:100%}
834 .carousel-inner>.next{left:100%}
839 .carousel-inner>.prev{left:-100%}
835 .carousel-inner>.prev{left:-100%}
840 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}
836 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}
841 .carousel-inner>.active.left{left:-100%}
837 .carousel-inner>.active.left{left:-100%}
842 .carousel-inner>.active.right{left:100%}
838 .carousel-inner>.active.right{left:100%}
843 .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{left:auto;right:15px}
839 .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{left:auto;right:15px}
844 .carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}
840 .carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}
845 .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}
841 .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}
846 .carousel-indicators .active{background-color:#fff}
842 .carousel-indicators .active{background-color:#fff}
847 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}
843 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}
848 .carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}
844 .carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}
849 .carousel-caption h4{margin:0 0 5px}
845 .carousel-caption h4{margin:0 0 5px}
850 .carousel-caption p{margin-bottom:0}
846 .carousel-caption p{margin-bottom:0}
851 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px}
847 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px}
852 .hero-unit li{line-height:30px}
848 .hero-unit li{line-height:30px}
853 .pull-right{float:right}
849 .pull-right{float:right}
854 .pull-left{float:left}
850 .pull-left{float:left}
855 .hide{display:none}
851 .hide{display:none}
856 .show{display:block}
852 .show{display:block}
857 .invisible{visibility:hidden}
853 .invisible{visibility:hidden}
858 .affix{position:fixed}
854 .affix{position:fixed}
855 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
856 .clearfix:after{clear:both}
857 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
858 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
859 @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}
859 @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}
860 .visible-phone{display:none !important}
860 .visible-phone{display:none !important}
861 .visible-tablet{display:none !important}
861 .visible-tablet{display:none !important}
862 .hidden-desktop{display:none !important}
862 .hidden-desktop{display:none !important}
863 .visible-desktop{display:inherit !important}
863 .visible-desktop{display:inherit !important}
864 @media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-tablet{display:inherit !important} .hidden-tablet{display:none !important}}@media (max-width:767px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-phone{display:inherit !important} .hidden-phone{display:none !important}}.visible-print{display:none !important}
864 @media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-tablet{display:inherit !important} .hidden-tablet{display:none !important}}@media (max-width:767px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-phone{display:inherit !important} .hidden-phone{display:none !important}}.visible-print{display:none !important}
865 @media print{.visible-print{display:inherit !important} .hidden-print{display:none !important}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:30px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px} .span12{width:1170px} .span11{width:1070px} .span10{width:970px} .span9{width:870px} .span8{width:770px} .span7{width:670px} .span6{width:570px} .span5{width:470px} .span4{width:370px} .span3{width:270px} .span2{width:170px} .span1{width:70px} .offset12{margin-left:1230px} .offset11{margin-left:1130px} .offset10{margin-left:1030px} .offset9{margin-left:930px} .offset8{margin-left:830px} .offset7{margin-left:730px} .offset6{margin-left:630px} .offset5{margin-left:530px} .offset4{margin-left:430px} .offset3{margin-left:330px} .offset2{margin-left:230px} .offset1{margin-left:130px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:30px} input.span12,textarea.span12,.uneditable-input.span12{width:1156px} input.span11,textarea.span11,.uneditable-input.span11{width:1056px} input.span10,textarea.span10,.uneditable-input.span10{width:956px} input.span9,textarea.span9,.uneditable-input.span9{width:856px} input.span8,textarea.span8,.uneditable-input.span8{width:756px} input.span7,textarea.span7,.uneditable-input.span7{width:656px} input.span6,textarea.span6,.uneditable-input.span6{width:556px} input.span5,textarea.span5,.uneditable-input.span5{width:456px} input.span4,textarea.span4,.uneditable-input.span4{width:356px} input.span3,textarea.span3,.uneditable-input.span3{width:256px} input.span2,textarea.span2,.uneditable-input.span2{width:156px} input.span1,textarea.span1,.uneditable-input.span1{width:56px} .thumbnails{margin-left:-30px} .thumbnails>li{margin-left:30px} .row-fluid .thumbnails{margin-left:0}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:20px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px} .span12{width:724px} .span11{width:662px} .span10{width:600px} .span9{width:538px} .span8{width:476px} .span7{width:414px} .span6{width:352px} .span5{width:290px} .span4{width:228px} .span3{width:166px} .span2{width:104px} .span1{width:42px} .offset12{margin-left:764px} .offset11{margin-left:702px} .offset10{margin-left:640px} .offset9{margin-left:578px} .offset8{margin-left:516px} .offset7{margin-left:454px} .offset6{margin-left:392px} .offset5{margin-left:330px} .offset4{margin-left:268px} .offset3{margin-left:206px} .offset2{margin-left:144px} .offset1{margin-left:82px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:20px} input.span12,textarea.span12,.uneditable-input.span12{width:710px} input.span11,textarea.span11,.uneditable-input.span11{width:648px} input.span10,textarea.span10,.uneditable-input.span10{width:586px} input.span9,textarea.span9,.uneditable-input.span9{width:524px} input.span8,textarea.span8,.uneditable-input.span8{width:462px} input.span7,textarea.span7,.uneditable-input.span7{width:400px} input.span6,textarea.span6,.uneditable-input.span6{width:338px} input.span5,textarea.span5,.uneditable-input.span5{width:276px} input.span4,textarea.span4,.uneditable-input.span4{width:214px} input.span3,textarea.span3,.uneditable-input.span3{width:152px} input.span2,textarea.span2,.uneditable-input.span2{width:90px} input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media (max-width:767px){body{padding-left:20px;padding-right:20px} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px} .container-fluid{padding:0} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left} .dl-horizontal dd{margin-left:0} .container{width:auto} .row-fluid{width:100%} .row,.thumbnails{margin-left:0} .thumbnails>li{float:none;margin-left:0} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .row-fluid [class*="offset"]:first-child{margin-left:0} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto} .controls-row [class*="span"]+[class*="span"]{margin-left:0} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0}.modal.fade{top:-100px} .modal.fade.in{top:20px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0)} .page-header h1 small{display:block;line-height:20px} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left} .form-horizontal .controls{margin-left:0} .form-horizontal .control-list{padding-top:0} .form-horizontal .form-actions{padding-left:10px;padding-right:10px} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px} .media-object{margin-right:0;margin-left:0} .modal{top:10px;left:10px;right:10px} .modal-header .close{padding:10px;margin:-10px} .carousel-caption{position:static}}@media (max-width:979px){body{padding-top:0} .navbar-fixed-top,.navbar-fixed-bottom{position:static} .navbar-fixed-top{margin-bottom:20px} .navbar-fixed-bottom{margin-top:20px} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px} .navbar .container{width:auto;padding:0} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px} .nav-collapse{clear:both} .nav-collapse .nav{float:none;margin:0 0 10px} .nav-collapse .nav>li{float:none} .nav-collapse .nav>li>a{margin-bottom:2px} .nav-collapse .nav>.divider-vertical{display:none} .nav-collapse .nav .nav-header{color:#777;text-shadow:none} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111} .nav-collapse.in .btn-group{margin-top:5px;padding:0} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} .nav-collapse .open>.dropdown-menu{display:block} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none} .nav-collapse .dropdown-menu .divider{display:none} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0} .navbar .btn-navbar{display:block} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px}}@media (min-width:979px + 1){.nav-collapse.collapse{height:auto !important;overflow:visible !important}}@font-face{font-family:'FontAwesome';src:url('../components/font-awesome/font/fontawesome-webfont.eot?v=3.2.1');src:url('../components/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../components/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../components/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../components/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}
865 @media print{.visible-print{display:inherit !important} .hidden-print{display:none !important}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:30px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px} .span12{width:1170px} .span11{width:1070px} .span10{width:970px} .span9{width:870px} .span8{width:770px} .span7{width:670px} .span6{width:570px} .span5{width:470px} .span4{width:370px} .span3{width:270px} .span2{width:170px} .span1{width:70px} .offset12{margin-left:1230px} .offset11{margin-left:1130px} .offset10{margin-left:1030px} .offset9{margin-left:930px} .offset8{margin-left:830px} .offset7{margin-left:730px} .offset6{margin-left:630px} .offset5{margin-left:530px} .offset4{margin-left:430px} .offset3{margin-left:330px} .offset2{margin-left:230px} .offset1{margin-left:130px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:30px} input.span12,textarea.span12,.uneditable-input.span12{width:1156px} input.span11,textarea.span11,.uneditable-input.span11{width:1056px} input.span10,textarea.span10,.uneditable-input.span10{width:956px} input.span9,textarea.span9,.uneditable-input.span9{width:856px} input.span8,textarea.span8,.uneditable-input.span8{width:756px} input.span7,textarea.span7,.uneditable-input.span7{width:656px} input.span6,textarea.span6,.uneditable-input.span6{width:556px} input.span5,textarea.span5,.uneditable-input.span5{width:456px} input.span4,textarea.span4,.uneditable-input.span4{width:356px} input.span3,textarea.span3,.uneditable-input.span3{width:256px} input.span2,textarea.span2,.uneditable-input.span2{width:156px} input.span1,textarea.span1,.uneditable-input.span1{width:56px} .thumbnails{margin-left:-30px} .thumbnails>li{margin-left:30px} .row-fluid .thumbnails{margin-left:0}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:20px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px} .span12{width:724px} .span11{width:662px} .span10{width:600px} .span9{width:538px} .span8{width:476px} .span7{width:414px} .span6{width:352px} .span5{width:290px} .span4{width:228px} .span3{width:166px} .span2{width:104px} .span1{width:42px} .offset12{margin-left:764px} .offset11{margin-left:702px} .offset10{margin-left:640px} .offset9{margin-left:578px} .offset8{margin-left:516px} .offset7{margin-left:454px} .offset6{margin-left:392px} .offset5{margin-left:330px} .offset4{margin-left:268px} .offset3{margin-left:206px} .offset2{margin-left:144px} .offset1{margin-left:82px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:20px} input.span12,textarea.span12,.uneditable-input.span12{width:710px} input.span11,textarea.span11,.uneditable-input.span11{width:648px} input.span10,textarea.span10,.uneditable-input.span10{width:586px} input.span9,textarea.span9,.uneditable-input.span9{width:524px} input.span8,textarea.span8,.uneditable-input.span8{width:462px} input.span7,textarea.span7,.uneditable-input.span7{width:400px} input.span6,textarea.span6,.uneditable-input.span6{width:338px} input.span5,textarea.span5,.uneditable-input.span5{width:276px} input.span4,textarea.span4,.uneditable-input.span4{width:214px} input.span3,textarea.span3,.uneditable-input.span3{width:152px} input.span2,textarea.span2,.uneditable-input.span2{width:90px} input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media (max-width:767px){body{padding-left:20px;padding-right:20px} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px} .container-fluid{padding:0} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left} .dl-horizontal dd{margin-left:0} .container{width:auto} .row-fluid{width:100%} .row,.thumbnails{margin-left:0} .thumbnails>li{float:none;margin-left:0} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .row-fluid [class*="offset"]:first-child{margin-left:0} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto} .controls-row [class*="span"]+[class*="span"]{margin-left:0} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0}.modal.fade{top:-100px} .modal.fade.in{top:20px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0)} .page-header h1 small{display:block;line-height:20px} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left} .form-horizontal .controls{margin-left:0} .form-horizontal .control-list{padding-top:0} .form-horizontal .form-actions{padding-left:10px;padding-right:10px} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px} .media-object{margin-right:0;margin-left:0} .modal{top:10px;left:10px;right:10px} .modal-header .close{padding:10px;margin:-10px} .carousel-caption{position:static}}@media (max-width:979px){body{padding-top:0} .navbar-fixed-top,.navbar-fixed-bottom{position:static} .navbar-fixed-top{margin-bottom:20px} .navbar-fixed-bottom{margin-top:20px} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px} .navbar .container{width:auto;padding:0} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px} .nav-collapse{clear:both} .nav-collapse .nav{float:none;margin:0 0 10px} .nav-collapse .nav>li{float:none} .nav-collapse .nav>li>a{margin-bottom:2px} .nav-collapse .nav>.divider-vertical{display:none} .nav-collapse .nav .nav-header{color:#777;text-shadow:none} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111} .nav-collapse.in .btn-group{margin-top:5px;padding:0} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} .nav-collapse .open>.dropdown-menu{display:block} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none} .nav-collapse .dropdown-menu .divider{display:none} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0} .navbar .btn-navbar{display:block} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px}}@media (min-width:979px + 1){.nav-collapse.collapse{height:auto !important;overflow:visible !important}}@font-face{font-family:'FontAwesome';src:url('../components/font-awesome/font/fontawesome-webfont.eot?v=3.2.1');src:url('../components/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../components/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../components/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../components/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}
866 [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}
866 [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}
867 .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}
867 .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}
868 a [class^="icon-"],a [class*=" icon-"]{display:inline}
868 a [class^="icon-"],a [class*=" icon-"]{display:inline}
869 [class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}
869 [class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}
870 .icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}
870 .icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}
871 .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}
871 .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}
872 [class^="icon-"].hide,[class*=" icon-"].hide{display:none}
872 [class^="icon-"].hide,[class*=" icon-"].hide{display:none}
873 .icon-muted{color:#eee}
873 .icon-muted{color:#eee}
874 .icon-light{color:#fff}
874 .icon-light{color:#fff}
875 .icon-dark{color:#333}
875 .icon-dark{color:#333}
876 .icon-border{border:solid 1px #eee;padding:.2em .25em .15em;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
876 .icon-border{border:solid 1px #eee;padding:.2em .25em .15em;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
877 .icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
877 .icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
878 .icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
878 .icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
879 .icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
879 .icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
880 .icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;border-radius:7px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}
880 .icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;border-radius:7px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}
881 .pull-right{float:right}
881 .pull-right{float:right}
882 .pull-left{float:left}
882 .pull-left{float:left}
883 [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}
883 [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}
884 [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}
884 [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}
885 [class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}
885 [class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}
886 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}
886 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}
887 .btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}
887 .btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}
888 .btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}
888 .btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}
889 .nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}
889 .nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}
890 .btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}
890 .btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}
891 .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}
891 .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}
892 .btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}
892 .btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}
893 .btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}
893 .btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}
894 .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}
894 .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}
895 .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}
895 .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}
896 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}
896 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}
897 .icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}
897 .icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}
898 .icon-stack .icon-stack-base{font-size:2em;*line-height:1em}
898 .icon-stack .icon-stack-base{font-size:2em;*line-height:1em}
899 .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}
899 .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}
900 a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}
900 a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}
901 @-moz-keyframes spin{0%{-moz-transform:rotate(0deg)} 100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)} 100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)} 100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)} 100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)} 100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}
901 @-moz-keyframes spin{0%{-moz-transform:rotate(0deg)} 100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)} 100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)} 100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)} 100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)} 100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}
902 .icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}
902 .icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}
903 .icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}
903 .icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}
904 .icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}
904 .icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}
905 .icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}
905 .icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}
906 a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}
906 a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}
907 .icon-glass:before{content:"\f000"}
907 .icon-glass:before{content:"\f000"}
908 .icon-music:before{content:"\f001"}
908 .icon-music:before{content:"\f001"}
909 .icon-search:before{content:"\f002"}
909 .icon-search:before{content:"\f002"}
910 .icon-envelope-alt:before{content:"\f003"}
910 .icon-envelope-alt:before{content:"\f003"}
911 .icon-heart:before{content:"\f004"}
911 .icon-heart:before{content:"\f004"}
912 .icon-star:before{content:"\f005"}
912 .icon-star:before{content:"\f005"}
913 .icon-star-empty:before{content:"\f006"}
913 .icon-star-empty:before{content:"\f006"}
914 .icon-user:before{content:"\f007"}
914 .icon-user:before{content:"\f007"}
915 .icon-film:before{content:"\f008"}
915 .icon-film:before{content:"\f008"}
916 .icon-th-large:before{content:"\f009"}
916 .icon-th-large:before{content:"\f009"}
917 .icon-th:before{content:"\f00a"}
917 .icon-th:before{content:"\f00a"}
918 .icon-th-list:before{content:"\f00b"}
918 .icon-th-list:before{content:"\f00b"}
919 .icon-ok:before{content:"\f00c"}
919 .icon-ok:before{content:"\f00c"}
920 .icon-remove:before{content:"\f00d"}
920 .icon-remove:before{content:"\f00d"}
921 .icon-zoom-in:before{content:"\f00e"}
921 .icon-zoom-in:before{content:"\f00e"}
922 .icon-zoom-out:before{content:"\f010"}
922 .icon-zoom-out:before{content:"\f010"}
923 .icon-power-off:before,.icon-off:before{content:"\f011"}
923 .icon-power-off:before,.icon-off:before{content:"\f011"}
924 .icon-signal:before{content:"\f012"}
924 .icon-signal:before{content:"\f012"}
925 .icon-gear:before,.icon-cog:before{content:"\f013"}
925 .icon-gear:before,.icon-cog:before{content:"\f013"}
926 .icon-trash:before{content:"\f014"}
926 .icon-trash:before{content:"\f014"}
927 .icon-home:before{content:"\f015"}
927 .icon-home:before{content:"\f015"}
928 .icon-file-alt:before{content:"\f016"}
928 .icon-file-alt:before{content:"\f016"}
929 .icon-time:before{content:"\f017"}
929 .icon-time:before{content:"\f017"}
930 .icon-road:before{content:"\f018"}
930 .icon-road:before{content:"\f018"}
931 .icon-download-alt:before{content:"\f019"}
931 .icon-download-alt:before{content:"\f019"}
932 .icon-download:before{content:"\f01a"}
932 .icon-download:before{content:"\f01a"}
933 .icon-upload:before{content:"\f01b"}
933 .icon-upload:before{content:"\f01b"}
934 .icon-inbox:before{content:"\f01c"}
934 .icon-inbox:before{content:"\f01c"}
935 .icon-play-circle:before{content:"\f01d"}
935 .icon-play-circle:before{content:"\f01d"}
936 .icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}
936 .icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}
937 .icon-refresh:before{content:"\f021"}
937 .icon-refresh:before{content:"\f021"}
938 .icon-list-alt:before{content:"\f022"}
938 .icon-list-alt:before{content:"\f022"}
939 .icon-lock:before{content:"\f023"}
939 .icon-lock:before{content:"\f023"}
940 .icon-flag:before{content:"\f024"}
940 .icon-flag:before{content:"\f024"}
941 .icon-headphones:before{content:"\f025"}
941 .icon-headphones:before{content:"\f025"}
942 .icon-volume-off:before{content:"\f026"}
942 .icon-volume-off:before{content:"\f026"}
943 .icon-volume-down:before{content:"\f027"}
943 .icon-volume-down:before{content:"\f027"}
944 .icon-volume-up:before{content:"\f028"}
944 .icon-volume-up:before{content:"\f028"}
945 .icon-qrcode:before{content:"\f029"}
945 .icon-qrcode:before{content:"\f029"}
946 .icon-barcode:before{content:"\f02a"}
946 .icon-barcode:before{content:"\f02a"}
947 .icon-tag:before{content:"\f02b"}
947 .icon-tag:before{content:"\f02b"}
948 .icon-tags:before{content:"\f02c"}
948 .icon-tags:before{content:"\f02c"}
949 .icon-book:before{content:"\f02d"}
949 .icon-book:before{content:"\f02d"}
950 .icon-bookmark:before{content:"\f02e"}
950 .icon-bookmark:before{content:"\f02e"}
951 .icon-print:before{content:"\f02f"}
951 .icon-print:before{content:"\f02f"}
952 .icon-camera:before{content:"\f030"}
952 .icon-camera:before{content:"\f030"}
953 .icon-font:before{content:"\f031"}
953 .icon-font:before{content:"\f031"}
954 .icon-bold:before{content:"\f032"}
954 .icon-bold:before{content:"\f032"}
955 .icon-italic:before{content:"\f033"}
955 .icon-italic:before{content:"\f033"}
956 .icon-text-height:before{content:"\f034"}
956 .icon-text-height:before{content:"\f034"}
957 .icon-text-width:before{content:"\f035"}
957 .icon-text-width:before{content:"\f035"}
958 .icon-align-left:before{content:"\f036"}
958 .icon-align-left:before{content:"\f036"}
959 .icon-align-center:before{content:"\f037"}
959 .icon-align-center:before{content:"\f037"}
960 .icon-align-right:before{content:"\f038"}
960 .icon-align-right:before{content:"\f038"}
961 .icon-align-justify:before{content:"\f039"}
961 .icon-align-justify:before{content:"\f039"}
962 .icon-list:before{content:"\f03a"}
962 .icon-list:before{content:"\f03a"}
963 .icon-indent-left:before{content:"\f03b"}
963 .icon-indent-left:before{content:"\f03b"}
964 .icon-indent-right:before{content:"\f03c"}
964 .icon-indent-right:before{content:"\f03c"}
965 .icon-facetime-video:before{content:"\f03d"}
965 .icon-facetime-video:before{content:"\f03d"}
966 .icon-picture:before{content:"\f03e"}
966 .icon-picture:before{content:"\f03e"}
967 .icon-pencil:before{content:"\f040"}
967 .icon-pencil:before{content:"\f040"}
968 .icon-map-marker:before{content:"\f041"}
968 .icon-map-marker:before{content:"\f041"}
969 .icon-adjust:before{content:"\f042"}
969 .icon-adjust:before{content:"\f042"}
970 .icon-tint:before{content:"\f043"}
970 .icon-tint:before{content:"\f043"}
971 .icon-edit:before{content:"\f044"}
971 .icon-edit:before{content:"\f044"}
972 .icon-share:before{content:"\f045"}
972 .icon-share:before{content:"\f045"}
973 .icon-check:before{content:"\f046"}
973 .icon-check:before{content:"\f046"}
974 .icon-move:before{content:"\f047"}
974 .icon-move:before{content:"\f047"}
975 .icon-step-backward:before{content:"\f048"}
975 .icon-step-backward:before{content:"\f048"}
976 .icon-fast-backward:before{content:"\f049"}
976 .icon-fast-backward:before{content:"\f049"}
977 .icon-backward:before{content:"\f04a"}
977 .icon-backward:before{content:"\f04a"}
978 .icon-play:before{content:"\f04b"}
978 .icon-play:before{content:"\f04b"}
979 .icon-pause:before{content:"\f04c"}
979 .icon-pause:before{content:"\f04c"}
980 .icon-stop:before{content:"\f04d"}
980 .icon-stop:before{content:"\f04d"}
981 .icon-forward:before{content:"\f04e"}
981 .icon-forward:before{content:"\f04e"}
982 .icon-fast-forward:before{content:"\f050"}
982 .icon-fast-forward:before{content:"\f050"}
983 .icon-step-forward:before{content:"\f051"}
983 .icon-step-forward:before{content:"\f051"}
984 .icon-eject:before{content:"\f052"}
984 .icon-eject:before{content:"\f052"}
985 .icon-chevron-left:before{content:"\f053"}
985 .icon-chevron-left:before{content:"\f053"}
986 .icon-chevron-right:before{content:"\f054"}
986 .icon-chevron-right:before{content:"\f054"}
987 .icon-plus-sign:before{content:"\f055"}
987 .icon-plus-sign:before{content:"\f055"}
988 .icon-minus-sign:before{content:"\f056"}
988 .icon-minus-sign:before{content:"\f056"}
989 .icon-remove-sign:before{content:"\f057"}
989 .icon-remove-sign:before{content:"\f057"}
990 .icon-ok-sign:before{content:"\f058"}
990 .icon-ok-sign:before{content:"\f058"}
991 .icon-question-sign:before{content:"\f059"}
991 .icon-question-sign:before{content:"\f059"}
992 .icon-info-sign:before{content:"\f05a"}
992 .icon-info-sign:before{content:"\f05a"}
993 .icon-screenshot:before{content:"\f05b"}
993 .icon-screenshot:before{content:"\f05b"}
994 .icon-remove-circle:before{content:"\f05c"}
994 .icon-remove-circle:before{content:"\f05c"}
995 .icon-ok-circle:before{content:"\f05d"}
995 .icon-ok-circle:before{content:"\f05d"}
996 .icon-ban-circle:before{content:"\f05e"}
996 .icon-ban-circle:before{content:"\f05e"}
997 .icon-arrow-left:before{content:"\f060"}
997 .icon-arrow-left:before{content:"\f060"}
998 .icon-arrow-right:before{content:"\f061"}
998 .icon-arrow-right:before{content:"\f061"}
999 .icon-arrow-up:before{content:"\f062"}
999 .icon-arrow-up:before{content:"\f062"}
1000 .icon-arrow-down:before{content:"\f063"}
1000 .icon-arrow-down:before{content:"\f063"}
1001 .icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}
1001 .icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}
1002 .icon-resize-full:before{content:"\f065"}
1002 .icon-resize-full:before{content:"\f065"}
1003 .icon-resize-small:before{content:"\f066"}
1003 .icon-resize-small:before{content:"\f066"}
1004 .icon-plus:before{content:"\f067"}
1004 .icon-plus:before{content:"\f067"}
1005 .icon-minus:before{content:"\f068"}
1005 .icon-minus:before{content:"\f068"}
1006 .icon-asterisk:before{content:"\f069"}
1006 .icon-asterisk:before{content:"\f069"}
1007 .icon-exclamation-sign:before{content:"\f06a"}
1007 .icon-exclamation-sign:before{content:"\f06a"}
1008 .icon-gift:before{content:"\f06b"}
1008 .icon-gift:before{content:"\f06b"}
1009 .icon-leaf:before{content:"\f06c"}
1009 .icon-leaf:before{content:"\f06c"}
1010 .icon-fire:before{content:"\f06d"}
1010 .icon-fire:before{content:"\f06d"}
1011 .icon-eye-open:before{content:"\f06e"}
1011 .icon-eye-open:before{content:"\f06e"}
1012 .icon-eye-close:before{content:"\f070"}
1012 .icon-eye-close:before{content:"\f070"}
1013 .icon-warning-sign:before{content:"\f071"}
1013 .icon-warning-sign:before{content:"\f071"}
1014 .icon-plane:before{content:"\f072"}
1014 .icon-plane:before{content:"\f072"}
1015 .icon-calendar:before{content:"\f073"}
1015 .icon-calendar:before{content:"\f073"}
1016 .icon-random:before{content:"\f074"}
1016 .icon-random:before{content:"\f074"}
1017 .icon-comment:before{content:"\f075"}
1017 .icon-comment:before{content:"\f075"}
1018 .icon-magnet:before{content:"\f076"}
1018 .icon-magnet:before{content:"\f076"}
1019 .icon-chevron-up:before{content:"\f077"}
1019 .icon-chevron-up:before{content:"\f077"}
1020 .icon-chevron-down:before{content:"\f078"}
1020 .icon-chevron-down:before{content:"\f078"}
1021 .icon-retweet:before{content:"\f079"}
1021 .icon-retweet:before{content:"\f079"}
1022 .icon-shopping-cart:before{content:"\f07a"}
1022 .icon-shopping-cart:before{content:"\f07a"}
1023 .icon-folder-close:before{content:"\f07b"}
1023 .icon-folder-close:before{content:"\f07b"}
1024 .icon-folder-open:before{content:"\f07c"}
1024 .icon-folder-open:before{content:"\f07c"}
1025 .icon-resize-vertical:before{content:"\f07d"}
1025 .icon-resize-vertical:before{content:"\f07d"}
1026 .icon-resize-horizontal:before{content:"\f07e"}
1026 .icon-resize-horizontal:before{content:"\f07e"}
1027 .icon-bar-chart:before{content:"\f080"}
1027 .icon-bar-chart:before{content:"\f080"}
1028 .icon-twitter-sign:before{content:"\f081"}
1028 .icon-twitter-sign:before{content:"\f081"}
1029 .icon-facebook-sign:before{content:"\f082"}
1029 .icon-facebook-sign:before{content:"\f082"}
1030 .icon-camera-retro:before{content:"\f083"}
1030 .icon-camera-retro:before{content:"\f083"}
1031 .icon-key:before{content:"\f084"}
1031 .icon-key:before{content:"\f084"}
1032 .icon-gears:before,.icon-cogs:before{content:"\f085"}
1032 .icon-gears:before,.icon-cogs:before{content:"\f085"}
1033 .icon-comments:before{content:"\f086"}
1033 .icon-comments:before{content:"\f086"}
1034 .icon-thumbs-up-alt:before{content:"\f087"}
1034 .icon-thumbs-up-alt:before{content:"\f087"}
1035 .icon-thumbs-down-alt:before{content:"\f088"}
1035 .icon-thumbs-down-alt:before{content:"\f088"}
1036 .icon-star-half:before{content:"\f089"}
1036 .icon-star-half:before{content:"\f089"}
1037 .icon-heart-empty:before{content:"\f08a"}
1037 .icon-heart-empty:before{content:"\f08a"}
1038 .icon-signout:before{content:"\f08b"}
1038 .icon-signout:before{content:"\f08b"}
1039 .icon-linkedin-sign:before{content:"\f08c"}
1039 .icon-linkedin-sign:before{content:"\f08c"}
1040 .icon-pushpin:before{content:"\f08d"}
1040 .icon-pushpin:before{content:"\f08d"}
1041 .icon-external-link:before{content:"\f08e"}
1041 .icon-external-link:before{content:"\f08e"}
1042 .icon-signin:before{content:"\f090"}
1042 .icon-signin:before{content:"\f090"}
1043 .icon-trophy:before{content:"\f091"}
1043 .icon-trophy:before{content:"\f091"}
1044 .icon-github-sign:before{content:"\f092"}
1044 .icon-github-sign:before{content:"\f092"}
1045 .icon-upload-alt:before{content:"\f093"}
1045 .icon-upload-alt:before{content:"\f093"}
1046 .icon-lemon:before{content:"\f094"}
1046 .icon-lemon:before{content:"\f094"}
1047 .icon-phone:before{content:"\f095"}
1047 .icon-phone:before{content:"\f095"}
1048 .icon-unchecked:before,.icon-check-empty:before{content:"\f096"}
1048 .icon-unchecked:before,.icon-check-empty:before{content:"\f096"}
1049 .icon-bookmark-empty:before{content:"\f097"}
1049 .icon-bookmark-empty:before{content:"\f097"}
1050 .icon-phone-sign:before{content:"\f098"}
1050 .icon-phone-sign:before{content:"\f098"}
1051 .icon-twitter:before{content:"\f099"}
1051 .icon-twitter:before{content:"\f099"}
1052 .icon-facebook:before{content:"\f09a"}
1052 .icon-facebook:before{content:"\f09a"}
1053 .icon-github:before{content:"\f09b"}
1053 .icon-github:before{content:"\f09b"}
1054 .icon-unlock:before{content:"\f09c"}
1054 .icon-unlock:before{content:"\f09c"}
1055 .icon-credit-card:before{content:"\f09d"}
1055 .icon-credit-card:before{content:"\f09d"}
1056 .icon-rss:before{content:"\f09e"}
1056 .icon-rss:before{content:"\f09e"}
1057 .icon-hdd:before{content:"\f0a0"}
1057 .icon-hdd:before{content:"\f0a0"}
1058 .icon-bullhorn:before{content:"\f0a1"}
1058 .icon-bullhorn:before{content:"\f0a1"}
1059 .icon-bell:before{content:"\f0a2"}
1059 .icon-bell:before{content:"\f0a2"}
1060 .icon-certificate:before{content:"\f0a3"}
1060 .icon-certificate:before{content:"\f0a3"}
1061 .icon-hand-right:before{content:"\f0a4"}
1061 .icon-hand-right:before{content:"\f0a4"}
1062 .icon-hand-left:before{content:"\f0a5"}
1062 .icon-hand-left:before{content:"\f0a5"}
1063 .icon-hand-up:before{content:"\f0a6"}
1063 .icon-hand-up:before{content:"\f0a6"}
1064 .icon-hand-down:before{content:"\f0a7"}
1064 .icon-hand-down:before{content:"\f0a7"}
1065 .icon-circle-arrow-left:before{content:"\f0a8"}
1065 .icon-circle-arrow-left:before{content:"\f0a8"}
1066 .icon-circle-arrow-right:before{content:"\f0a9"}
1066 .icon-circle-arrow-right:before{content:"\f0a9"}
1067 .icon-circle-arrow-up:before{content:"\f0aa"}
1067 .icon-circle-arrow-up:before{content:"\f0aa"}
1068 .icon-circle-arrow-down:before{content:"\f0ab"}
1068 .icon-circle-arrow-down:before{content:"\f0ab"}
1069 .icon-globe:before{content:"\f0ac"}
1069 .icon-globe:before{content:"\f0ac"}
1070 .icon-wrench:before{content:"\f0ad"}
1070 .icon-wrench:before{content:"\f0ad"}
1071 .icon-tasks:before{content:"\f0ae"}
1071 .icon-tasks:before{content:"\f0ae"}
1072 .icon-filter:before{content:"\f0b0"}
1072 .icon-filter:before{content:"\f0b0"}
1073 .icon-briefcase:before{content:"\f0b1"}
1073 .icon-briefcase:before{content:"\f0b1"}
1074 .icon-fullscreen:before{content:"\f0b2"}
1074 .icon-fullscreen:before{content:"\f0b2"}
1075 .icon-group:before{content:"\f0c0"}
1075 .icon-group:before{content:"\f0c0"}
1076 .icon-link:before{content:"\f0c1"}
1076 .icon-link:before{content:"\f0c1"}
1077 .icon-cloud:before{content:"\f0c2"}
1077 .icon-cloud:before{content:"\f0c2"}
1078 .icon-beaker:before{content:"\f0c3"}
1078 .icon-beaker:before{content:"\f0c3"}
1079 .icon-cut:before{content:"\f0c4"}
1079 .icon-cut:before{content:"\f0c4"}
1080 .icon-copy:before{content:"\f0c5"}
1080 .icon-copy:before{content:"\f0c5"}
1081 .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}
1081 .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}
1082 .icon-save:before{content:"\f0c7"}
1082 .icon-save:before{content:"\f0c7"}
1083 .icon-sign-blank:before{content:"\f0c8"}
1083 .icon-sign-blank:before{content:"\f0c8"}
1084 .icon-reorder:before{content:"\f0c9"}
1084 .icon-reorder:before{content:"\f0c9"}
1085 .icon-list-ul:before{content:"\f0ca"}
1085 .icon-list-ul:before{content:"\f0ca"}
1086 .icon-list-ol:before{content:"\f0cb"}
1086 .icon-list-ol:before{content:"\f0cb"}
1087 .icon-strikethrough:before{content:"\f0cc"}
1087 .icon-strikethrough:before{content:"\f0cc"}
1088 .icon-underline:before{content:"\f0cd"}
1088 .icon-underline:before{content:"\f0cd"}
1089 .icon-table:before{content:"\f0ce"}
1089 .icon-table:before{content:"\f0ce"}
1090 .icon-magic:before{content:"\f0d0"}
1090 .icon-magic:before{content:"\f0d0"}
1091 .icon-truck:before{content:"\f0d1"}
1091 .icon-truck:before{content:"\f0d1"}
1092 .icon-pinterest:before{content:"\f0d2"}
1092 .icon-pinterest:before{content:"\f0d2"}
1093 .icon-pinterest-sign:before{content:"\f0d3"}
1093 .icon-pinterest-sign:before{content:"\f0d3"}
1094 .icon-google-plus-sign:before{content:"\f0d4"}
1094 .icon-google-plus-sign:before{content:"\f0d4"}
1095 .icon-google-plus:before{content:"\f0d5"}
1095 .icon-google-plus:before{content:"\f0d5"}
1096 .icon-money:before{content:"\f0d6"}
1096 .icon-money:before{content:"\f0d6"}
1097 .icon-caret-down:before{content:"\f0d7"}
1097 .icon-caret-down:before{content:"\f0d7"}
1098 .icon-caret-up:before{content:"\f0d8"}
1098 .icon-caret-up:before{content:"\f0d8"}
1099 .icon-caret-left:before{content:"\f0d9"}
1099 .icon-caret-left:before{content:"\f0d9"}
1100 .icon-caret-right:before{content:"\f0da"}
1100 .icon-caret-right:before{content:"\f0da"}
1101 .icon-columns:before{content:"\f0db"}
1101 .icon-columns:before{content:"\f0db"}
1102 .icon-sort:before{content:"\f0dc"}
1102 .icon-sort:before{content:"\f0dc"}
1103 .icon-sort-down:before{content:"\f0dd"}
1103 .icon-sort-down:before{content:"\f0dd"}
1104 .icon-sort-up:before{content:"\f0de"}
1104 .icon-sort-up:before{content:"\f0de"}
1105 .icon-envelope:before{content:"\f0e0"}
1105 .icon-envelope:before{content:"\f0e0"}
1106 .icon-linkedin:before{content:"\f0e1"}
1106 .icon-linkedin:before{content:"\f0e1"}
1107 .icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}
1107 .icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}
1108 .icon-legal:before{content:"\f0e3"}
1108 .icon-legal:before{content:"\f0e3"}
1109 .icon-dashboard:before{content:"\f0e4"}
1109 .icon-dashboard:before{content:"\f0e4"}
1110 .icon-comment-alt:before{content:"\f0e5"}
1110 .icon-comment-alt:before{content:"\f0e5"}
1111 .icon-comments-alt:before{content:"\f0e6"}
1111 .icon-comments-alt:before{content:"\f0e6"}
1112 .icon-bolt:before{content:"\f0e7"}
1112 .icon-bolt:before{content:"\f0e7"}
1113 .icon-sitemap:before{content:"\f0e8"}
1113 .icon-sitemap:before{content:"\f0e8"}
1114 .icon-umbrella:before{content:"\f0e9"}
1114 .icon-umbrella:before{content:"\f0e9"}
1115 .icon-paste:before{content:"\f0ea"}
1115 .icon-paste:before{content:"\f0ea"}
1116 .icon-lightbulb:before{content:"\f0eb"}
1116 .icon-lightbulb:before{content:"\f0eb"}
1117 .icon-exchange:before{content:"\f0ec"}
1117 .icon-exchange:before{content:"\f0ec"}
1118 .icon-cloud-download:before{content:"\f0ed"}
1118 .icon-cloud-download:before{content:"\f0ed"}
1119 .icon-cloud-upload:before{content:"\f0ee"}
1119 .icon-cloud-upload:before{content:"\f0ee"}
1120 .icon-user-md:before{content:"\f0f0"}
1120 .icon-user-md:before{content:"\f0f0"}
1121 .icon-stethoscope:before{content:"\f0f1"}
1121 .icon-stethoscope:before{content:"\f0f1"}
1122 .icon-suitcase:before{content:"\f0f2"}
1122 .icon-suitcase:before{content:"\f0f2"}
1123 .icon-bell-alt:before{content:"\f0f3"}
1123 .icon-bell-alt:before{content:"\f0f3"}
1124 .icon-coffee:before{content:"\f0f4"}
1124 .icon-coffee:before{content:"\f0f4"}
1125 .icon-food:before{content:"\f0f5"}
1125 .icon-food:before{content:"\f0f5"}
1126 .icon-file-text-alt:before{content:"\f0f6"}
1126 .icon-file-text-alt:before{content:"\f0f6"}
1127 .icon-building:before{content:"\f0f7"}
1127 .icon-building:before{content:"\f0f7"}
1128 .icon-hospital:before{content:"\f0f8"}
1128 .icon-hospital:before{content:"\f0f8"}
1129 .icon-ambulance:before{content:"\f0f9"}
1129 .icon-ambulance:before{content:"\f0f9"}
1130 .icon-medkit:before{content:"\f0fa"}
1130 .icon-medkit:before{content:"\f0fa"}
1131 .icon-fighter-jet:before{content:"\f0fb"}
1131 .icon-fighter-jet:before{content:"\f0fb"}
1132 .icon-beer:before{content:"\f0fc"}
1132 .icon-beer:before{content:"\f0fc"}
1133 .icon-h-sign:before{content:"\f0fd"}
1133 .icon-h-sign:before{content:"\f0fd"}
1134 .icon-plus-sign-alt:before{content:"\f0fe"}
1134 .icon-plus-sign-alt:before{content:"\f0fe"}
1135 .icon-double-angle-left:before{content:"\f100"}
1135 .icon-double-angle-left:before{content:"\f100"}
1136 .icon-double-angle-right:before{content:"\f101"}
1136 .icon-double-angle-right:before{content:"\f101"}
1137 .icon-double-angle-up:before{content:"\f102"}
1137 .icon-double-angle-up:before{content:"\f102"}
1138 .icon-double-angle-down:before{content:"\f103"}
1138 .icon-double-angle-down:before{content:"\f103"}
1139 .icon-angle-left:before{content:"\f104"}
1139 .icon-angle-left:before{content:"\f104"}
1140 .icon-angle-right:before{content:"\f105"}
1140 .icon-angle-right:before{content:"\f105"}
1141 .icon-angle-up:before{content:"\f106"}
1141 .icon-angle-up:before{content:"\f106"}
1142 .icon-angle-down:before{content:"\f107"}
1142 .icon-angle-down:before{content:"\f107"}
1143 .icon-desktop:before{content:"\f108"}
1143 .icon-desktop:before{content:"\f108"}
1144 .icon-laptop:before{content:"\f109"}
1144 .icon-laptop:before{content:"\f109"}
1145 .icon-tablet:before{content:"\f10a"}
1145 .icon-tablet:before{content:"\f10a"}
1146 .icon-mobile-phone:before{content:"\f10b"}
1146 .icon-mobile-phone:before{content:"\f10b"}
1147 .icon-circle-blank:before{content:"\f10c"}
1147 .icon-circle-blank:before{content:"\f10c"}
1148 .icon-quote-left:before{content:"\f10d"}
1148 .icon-quote-left:before{content:"\f10d"}
1149 .icon-quote-right:before{content:"\f10e"}
1149 .icon-quote-right:before{content:"\f10e"}
1150 .icon-spinner:before{content:"\f110"}
1150 .icon-spinner:before{content:"\f110"}
1151 .icon-circle:before{content:"\f111"}
1151 .icon-circle:before{content:"\f111"}
1152 .icon-mail-reply:before,.icon-reply:before{content:"\f112"}
1152 .icon-mail-reply:before,.icon-reply:before{content:"\f112"}
1153 .icon-github-alt:before{content:"\f113"}
1153 .icon-github-alt:before{content:"\f113"}
1154 .icon-folder-close-alt:before{content:"\f114"}
1154 .icon-folder-close-alt:before{content:"\f114"}
1155 .icon-folder-open-alt:before{content:"\f115"}
1155 .icon-folder-open-alt:before{content:"\f115"}
1156 .icon-expand-alt:before{content:"\f116"}
1156 .icon-expand-alt:before{content:"\f116"}
1157 .icon-collapse-alt:before{content:"\f117"}
1157 .icon-collapse-alt:before{content:"\f117"}
1158 .icon-smile:before{content:"\f118"}
1158 .icon-smile:before{content:"\f118"}
1159 .icon-frown:before{content:"\f119"}
1159 .icon-frown:before{content:"\f119"}
1160 .icon-meh:before{content:"\f11a"}
1160 .icon-meh:before{content:"\f11a"}
1161 .icon-gamepad:before{content:"\f11b"}
1161 .icon-gamepad:before{content:"\f11b"}
1162 .icon-keyboard:before{content:"\f11c"}
1162 .icon-keyboard:before{content:"\f11c"}
1163 .icon-flag-alt:before{content:"\f11d"}
1163 .icon-flag-alt:before{content:"\f11d"}
1164 .icon-flag-checkered:before{content:"\f11e"}
1164 .icon-flag-checkered:before{content:"\f11e"}
1165 .icon-terminal:before{content:"\f120"}
1165 .icon-terminal:before{content:"\f120"}
1166 .icon-code:before{content:"\f121"}
1166 .icon-code:before{content:"\f121"}
1167 .icon-reply-all:before{content:"\f122"}
1167 .icon-reply-all:before{content:"\f122"}
1168 .icon-mail-reply-all:before{content:"\f122"}
1168 .icon-mail-reply-all:before{content:"\f122"}
1169 .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}
1169 .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}
1170 .icon-location-arrow:before{content:"\f124"}
1170 .icon-location-arrow:before{content:"\f124"}
1171 .icon-crop:before{content:"\f125"}
1171 .icon-crop:before{content:"\f125"}
1172 .icon-code-fork:before{content:"\f126"}
1172 .icon-code-fork:before{content:"\f126"}
1173 .icon-unlink:before{content:"\f127"}
1173 .icon-unlink:before{content:"\f127"}
1174 .icon-question:before{content:"\f128"}
1174 .icon-question:before{content:"\f128"}
1175 .icon-info:before{content:"\f129"}
1175 .icon-info:before{content:"\f129"}
1176 .icon-exclamation:before{content:"\f12a"}
1176 .icon-exclamation:before{content:"\f12a"}
1177 .icon-superscript:before{content:"\f12b"}
1177 .icon-superscript:before{content:"\f12b"}
1178 .icon-subscript:before{content:"\f12c"}
1178 .icon-subscript:before{content:"\f12c"}
1179 .icon-eraser:before{content:"\f12d"}
1179 .icon-eraser:before{content:"\f12d"}
1180 .icon-puzzle-piece:before{content:"\f12e"}
1180 .icon-puzzle-piece:before{content:"\f12e"}
1181 .icon-microphone:before{content:"\f130"}
1181 .icon-microphone:before{content:"\f130"}
1182 .icon-microphone-off:before{content:"\f131"}
1182 .icon-microphone-off:before{content:"\f131"}
1183 .icon-shield:before{content:"\f132"}
1183 .icon-shield:before{content:"\f132"}
1184 .icon-calendar-empty:before{content:"\f133"}
1184 .icon-calendar-empty:before{content:"\f133"}
1185 .icon-fire-extinguisher:before{content:"\f134"}
1185 .icon-fire-extinguisher:before{content:"\f134"}
1186 .icon-rocket:before{content:"\f135"}
1186 .icon-rocket:before{content:"\f135"}
1187 .icon-maxcdn:before{content:"\f136"}
1187 .icon-maxcdn:before{content:"\f136"}
1188 .icon-chevron-sign-left:before{content:"\f137"}
1188 .icon-chevron-sign-left:before{content:"\f137"}
1189 .icon-chevron-sign-right:before{content:"\f138"}
1189 .icon-chevron-sign-right:before{content:"\f138"}
1190 .icon-chevron-sign-up:before{content:"\f139"}
1190 .icon-chevron-sign-up:before{content:"\f139"}
1191 .icon-chevron-sign-down:before{content:"\f13a"}
1191 .icon-chevron-sign-down:before{content:"\f13a"}
1192 .icon-html5:before{content:"\f13b"}
1192 .icon-html5:before{content:"\f13b"}
1193 .icon-css3:before{content:"\f13c"}
1193 .icon-css3:before{content:"\f13c"}
1194 .icon-anchor:before{content:"\f13d"}
1194 .icon-anchor:before{content:"\f13d"}
1195 .icon-unlock-alt:before{content:"\f13e"}
1195 .icon-unlock-alt:before{content:"\f13e"}
1196 .icon-bullseye:before{content:"\f140"}
1196 .icon-bullseye:before{content:"\f140"}
1197 .icon-ellipsis-horizontal:before{content:"\f141"}
1197 .icon-ellipsis-horizontal:before{content:"\f141"}
1198 .icon-ellipsis-vertical:before{content:"\f142"}
1198 .icon-ellipsis-vertical:before{content:"\f142"}
1199 .icon-rss-sign:before{content:"\f143"}
1199 .icon-rss-sign:before{content:"\f143"}
1200 .icon-play-sign:before{content:"\f144"}
1200 .icon-play-sign:before{content:"\f144"}
1201 .icon-ticket:before{content:"\f145"}
1201 .icon-ticket:before{content:"\f145"}
1202 .icon-minus-sign-alt:before{content:"\f146"}
1202 .icon-minus-sign-alt:before{content:"\f146"}
1203 .icon-check-minus:before{content:"\f147"}
1203 .icon-check-minus:before{content:"\f147"}
1204 .icon-level-up:before{content:"\f148"}
1204 .icon-level-up:before{content:"\f148"}
1205 .icon-level-down:before{content:"\f149"}
1205 .icon-level-down:before{content:"\f149"}
1206 .icon-check-sign:before{content:"\f14a"}
1206 .icon-check-sign:before{content:"\f14a"}
1207 .icon-edit-sign:before{content:"\f14b"}
1207 .icon-edit-sign:before{content:"\f14b"}
1208 .icon-external-link-sign:before{content:"\f14c"}
1208 .icon-external-link-sign:before{content:"\f14c"}
1209 .icon-share-sign:before{content:"\f14d"}
1209 .icon-share-sign:before{content:"\f14d"}
1210 .icon-compass:before{content:"\f14e"}
1210 .icon-compass:before{content:"\f14e"}
1211 .icon-collapse:before{content:"\f150"}
1211 .icon-collapse:before{content:"\f150"}
1212 .icon-collapse-top:before{content:"\f151"}
1212 .icon-collapse-top:before{content:"\f151"}
1213 .icon-expand:before{content:"\f152"}
1213 .icon-expand:before{content:"\f152"}
1214 .icon-euro:before,.icon-eur:before{content:"\f153"}
1214 .icon-euro:before,.icon-eur:before{content:"\f153"}
1215 .icon-gbp:before{content:"\f154"}
1215 .icon-gbp:before{content:"\f154"}
1216 .icon-dollar:before,.icon-usd:before{content:"\f155"}
1216 .icon-dollar:before,.icon-usd:before{content:"\f155"}
1217 .icon-rupee:before,.icon-inr:before{content:"\f156"}
1217 .icon-rupee:before,.icon-inr:before{content:"\f156"}
1218 .icon-yen:before,.icon-jpy:before{content:"\f157"}
1218 .icon-yen:before,.icon-jpy:before{content:"\f157"}
1219 .icon-renminbi:before,.icon-cny:before{content:"\f158"}
1219 .icon-renminbi:before,.icon-cny:before{content:"\f158"}
1220 .icon-won:before,.icon-krw:before{content:"\f159"}
1220 .icon-won:before,.icon-krw:before{content:"\f159"}
1221 .icon-bitcoin:before,.icon-btc:before{content:"\f15a"}
1221 .icon-bitcoin:before,.icon-btc:before{content:"\f15a"}
1222 .icon-file:before{content:"\f15b"}
1222 .icon-file:before{content:"\f15b"}
1223 .icon-file-text:before{content:"\f15c"}
1223 .icon-file-text:before{content:"\f15c"}
1224 .icon-sort-by-alphabet:before{content:"\f15d"}
1224 .icon-sort-by-alphabet:before{content:"\f15d"}
1225 .icon-sort-by-alphabet-alt:before{content:"\f15e"}
1225 .icon-sort-by-alphabet-alt:before{content:"\f15e"}
1226 .icon-sort-by-attributes:before{content:"\f160"}
1226 .icon-sort-by-attributes:before{content:"\f160"}
1227 .icon-sort-by-attributes-alt:before{content:"\f161"}
1227 .icon-sort-by-attributes-alt:before{content:"\f161"}
1228 .icon-sort-by-order:before{content:"\f162"}
1228 .icon-sort-by-order:before{content:"\f162"}
1229 .icon-sort-by-order-alt:before{content:"\f163"}
1229 .icon-sort-by-order-alt:before{content:"\f163"}
1230 .icon-thumbs-up:before{content:"\f164"}
1230 .icon-thumbs-up:before{content:"\f164"}
1231 .icon-thumbs-down:before{content:"\f165"}
1231 .icon-thumbs-down:before{content:"\f165"}
1232 .icon-youtube-sign:before{content:"\f166"}
1232 .icon-youtube-sign:before{content:"\f166"}
1233 .icon-youtube:before{content:"\f167"}
1233 .icon-youtube:before{content:"\f167"}
1234 .icon-xing:before{content:"\f168"}
1234 .icon-xing:before{content:"\f168"}
1235 .icon-xing-sign:before{content:"\f169"}
1235 .icon-xing-sign:before{content:"\f169"}
1236 .icon-youtube-play:before{content:"\f16a"}
1236 .icon-youtube-play:before{content:"\f16a"}
1237 .icon-dropbox:before{content:"\f16b"}
1237 .icon-dropbox:before{content:"\f16b"}
1238 .icon-stackexchange:before{content:"\f16c"}
1238 .icon-stackexchange:before{content:"\f16c"}
1239 .icon-instagram:before{content:"\f16d"}
1239 .icon-instagram:before{content:"\f16d"}
1240 .icon-flickr:before{content:"\f16e"}
1240 .icon-flickr:before{content:"\f16e"}
1241 .icon-adn:before{content:"\f170"}
1241 .icon-adn:before{content:"\f170"}
1242 .icon-bitbucket:before{content:"\f171"}
1242 .icon-bitbucket:before{content:"\f171"}
1243 .icon-bitbucket-sign:before{content:"\f172"}
1243 .icon-bitbucket-sign:before{content:"\f172"}
1244 .icon-tumblr:before{content:"\f173"}
1244 .icon-tumblr:before{content:"\f173"}
1245 .icon-tumblr-sign:before{content:"\f174"}
1245 .icon-tumblr-sign:before{content:"\f174"}
1246 .icon-long-arrow-down:before{content:"\f175"}
1246 .icon-long-arrow-down:before{content:"\f175"}
1247 .icon-long-arrow-up:before{content:"\f176"}
1247 .icon-long-arrow-up:before{content:"\f176"}
1248 .icon-long-arrow-left:before{content:"\f177"}
1248 .icon-long-arrow-left:before{content:"\f177"}
1249 .icon-long-arrow-right:before{content:"\f178"}
1249 .icon-long-arrow-right:before{content:"\f178"}
1250 .icon-apple:before{content:"\f179"}
1250 .icon-apple:before{content:"\f179"}
1251 .icon-windows:before{content:"\f17a"}
1251 .icon-windows:before{content:"\f17a"}
1252 .icon-android:before{content:"\f17b"}
1252 .icon-android:before{content:"\f17b"}
1253 .icon-linux:before{content:"\f17c"}
1253 .icon-linux:before{content:"\f17c"}
1254 .icon-dribbble:before{content:"\f17d"}
1254 .icon-dribbble:before{content:"\f17d"}
1255 .icon-skype:before{content:"\f17e"}
1255 .icon-skype:before{content:"\f17e"}
1256 .icon-foursquare:before{content:"\f180"}
1256 .icon-foursquare:before{content:"\f180"}
1257 .icon-trello:before{content:"\f181"}
1257 .icon-trello:before{content:"\f181"}
1258 .icon-female:before{content:"\f182"}
1258 .icon-female:before{content:"\f182"}
1259 .icon-male:before{content:"\f183"}
1259 .icon-male:before{content:"\f183"}
1260 .icon-gittip:before{content:"\f184"}
1260 .icon-gittip:before{content:"\f184"}
1261 .icon-sun:before{content:"\f185"}
1261 .icon-sun:before{content:"\f185"}
1262 .icon-moon:before{content:"\f186"}
1262 .icon-moon:before{content:"\f186"}
1263 .icon-archive:before{content:"\f187"}
1263 .icon-archive:before{content:"\f187"}
1264 .icon-bug:before{content:"\f188"}
1264 .icon-bug:before{content:"\f188"}
1265 .icon-vk:before{content:"\f189"}
1265 .icon-vk:before{content:"\f189"}
1266 .icon-weibo:before{content:"\f18a"}
1266 .icon-weibo:before{content:"\f18a"}
1267 .icon-renren:before{content:"\f18b"}
1267 .icon-renren:before{content:"\f18b"}
1268 code{color:#000}
1268 code{color:#000}
1269 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1269 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1270 .corner-all{border-radius:4px}
1270 .corner-all{border-radius:4px}
1271 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1271 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1272 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1272 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1273 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1273 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1274 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1274 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}
1275 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1275 .hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1276 .hbox.box-flex0,.vbox.box-flex0,.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}
1276 .hbox.box-flex0,.vbox.box-flex0,.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}
1277 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1277 .hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1278 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1278 .hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1279 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1279 .hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1280 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
1280 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
1281 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
1281 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
1282 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
1282 .hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
1283 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
1283 .hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
1284 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
1284 .hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
1285 .hbox.align-start,.vbox.align-start,.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1285 .hbox.align-start,.vbox.align-start,.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1286 .hbox.align-end,.vbox.align-end,.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}
1286 .hbox.align-end,.vbox.align-end,.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}
1287 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
1287 .hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}
1288 div.error{margin:2em;text-align:center}
1288 div.error{margin:2em;text-align:center}
1289 div.error>h1{font-size:500%;line-height:normal}
1289 div.error>h1{font-size:500%;line-height:normal}
1290 div.error>p{font-size:200%;line-height:normal}
1290 div.error>p{font-size:200%;line-height:normal}
1291 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
1291 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
1292 body{background-color:#fff;position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}
1292 body{background-color:#fff;position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}
1293 div#header{display:none}
1293 div#header{display:none}
1294 #ipython_notebook{padding-left:16px}
1294 #ipython_notebook{padding-left:16px}
1295 #noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:#f00;font-weight:bold}
1295 #noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:#f00;font-weight:bold}
1296 #ipython_notebook img{font-family:Verdana,"Helvetica Neue",Arial,Helvetica,Geneva,sans-serif;height:24px;text-decoration:none;color:#000}
1296 #ipython_notebook img{font-family:Verdana,"Helvetica Neue",Arial,Helvetica,Geneva,sans-serif;height:24px;text-decoration:none;color:#000}
1297 #site{width:100%;display:none}
1297 #site{width:100%;display:none}
1298 .ui-button .ui-button-text{padding:.2em .8em;font-size:77%}
1298 .ui-button .ui-button-text{padding:.2em .8em;font-size:77%}
1299 input.ui-button{padding:.3em .9em}
1299 input.ui-button{padding:.3em .9em}
1300 .navbar span{margin-top:3px}
1300 .navbar span{margin-top:3px}
1301 span#login_widget{float:right}
1301 span#login_widget{float:right}
1302 .nav-header{text-transform:none}
1302 .nav-header{text-transform:none}
1303 .navbar-nobg{background-color:transparent;background-image:none}
1303 .navbar-nobg{background-color:transparent;background-image:none}
1304 #header>span{margin-top:10px}
1304 #header>span{margin-top:10px}
1305 .modal-body{max-height:500px}
1305 .modal-body{max-height:500px}
1306 @media (min-width:768px){.modal{width:700px;margin-left:-350px}}.center-nav{display:inline-block;margin-bottom:-4px}
1306 @media (min-width:768px){.modal{width:700px;margin-left:-350px}}.center-nav{display:inline-block;margin-bottom:-4px}
1307 .alternate_upload{background-color:none;display:inline}
1307 .alternate_upload{background-color:none;display:inline}
1308 .alternate_upload.form{padding:0;margin:0}
1308 .alternate_upload.form{padding:0;margin:0}
1309 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
1309 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
1310 ul#tabs{margin-bottom:4px}
1310 ul#tabs{margin-bottom:4px}
1311 ul#tabs a{padding-top:4px;padding-bottom:4px}
1311 ul#tabs a{padding-top:4px;padding-bottom:4px}
1312 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
1312 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
1313 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
1313 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
1314 ul.breadcrumb span{color:#5e5e5e}
1314 ul.breadcrumb span{color:#5e5e5e}
1315 .list_toolbar{padding:4px 0 4px 0}
1315 .list_toolbar{padding:4px 0 4px 0}
1316 .list_toolbar [class*="span"]{min-height:26px}
1316 .list_toolbar [class*="span"]{min-height:26px}
1317 .list_header{font-weight:bold}
1317 .list_header{font-weight:bold}
1318 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
1318 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
1319 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
1319 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
1320 .list_container>div:last-child{border:none}
1320 .list_container>div:last-child{border:none}
1321 .list_item:hover .list_item{background-color:#ddd}
1321 .list_item:hover .list_item{background-color:#ddd}
1322 .list_item a{text-decoration:none}
1322 .list_item a{text-decoration:none}
1323 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
1323 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
1324 .item_name{line-height:22px;height:26px}
1324 .item_name{line-height:22px;height:26px}
1325 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
1325 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
1326 .item_buttons{line-height:1em}
1326 .item_buttons{line-height:1em}
1327 .toolbar_info{height:26px;line-height:26px}
1327 .toolbar_info{height:26px;line-height:26px}
1328 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
1328 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
1329 input.engine_num_input{width:60px}
1329 input.engine_num_input{width:60px}
1330 .highlight_text{color:#00f}
1330 .highlight_text{color:#00f}
1331 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
1331 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
1332 .ansibold{font-weight:bold}
1332 .ansibold{font-weight:bold}
1333 .ansiblack{color:#000}
1333 .ansiblack{color:#000}
1334 .ansired{color:#8b0000}
1334 .ansired{color:#8b0000}
1335 .ansigreen{color:#006400}
1335 .ansigreen{color:#006400}
1336 .ansiyellow{color:#a52a2a}
1336 .ansiyellow{color:#a52a2a}
1337 .ansiblue{color:#00008b}
1337 .ansiblue{color:#00008b}
1338 .ansipurple{color:#9400d3}
1338 .ansipurple{color:#9400d3}
1339 .ansicyan{color:#4682b4}
1339 .ansicyan{color:#4682b4}
1340 .ansigray{color:#808080}
1340 .ansigray{color:#808080}
1341 .ansibgblack{background-color:#000}
1341 .ansibgblack{background-color:#000}
1342 .ansibgred{background-color:#f00}
1342 .ansibgred{background-color:#f00}
1343 .ansibggreen{background-color:#008000}
1343 .ansibggreen{background-color:#008000}
1344 .ansibgyellow{background-color:#ff0}
1344 .ansibgyellow{background-color:#ff0}
1345 .ansibgblue{background-color:#00f}
1345 .ansibgblue{background-color:#00f}
1346 .ansibgpurple{background-color:#f0f}
1346 .ansibgpurple{background-color:#f0f}
1347 .ansibgcyan{background-color:#0ff}
1347 .ansibgcyan{background-color:#0ff}
1348 .ansibggray{background-color:#808080}
1348 .ansibggray{background-color:#808080}
1349 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
1349 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
1350 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
1350 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
1351 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
1351 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
1352 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}
1352 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}
1353 div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1353 div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1354 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1354 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1355 div.prompt:empty{padding-top:0;padding-bottom:0}
1355 div.prompt:empty{padding-top:0;padding-bottom:0}
1356 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1356 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1357 div.input_prompt{color:#000080;border-top:1px solid transparent}
1357 div.input_prompt{color:#000080;border-top:1px solid transparent}
1358 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
1358 div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}
1359 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
1359 div.input_area>div.highlight>pre{margin:0;border:0;padding:0;background-color:transparent;font-size:14px;line-height:1.21429em}
1360 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
1360 .CodeMirror{line-height:1.21429em;height:auto;background:none;}
1361 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
1361 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
1362 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
1362 @-moz-document url-prefix(){.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
1363 .CodeMirror-linenumber{padding:0 8px 0 4px}
1363 .CodeMirror-linenumber{padding:0 8px 0 4px}
1364 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
1364 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
1365 .CodeMirror pre{padding:0;border:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
1365 .CodeMirror pre{padding:0;border:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
1366 pre code{display:block;padding:.5em}
1366 pre code{display:block;padding:.5em}
1367 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
1367 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
1368 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
1368 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
1369 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
1369 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
1370 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
1370 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
1371 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
1371 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
1372 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
1372 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
1373 .highlight-builtin,pre .built_in{color:#008000}
1373 .highlight-builtin,pre .built_in{color:#008000}
1374 pre .markdown .emphasis{font-style:italic}
1374 pre .markdown .emphasis{font-style:italic}
1375 pre .nginx .built_in{font-weight:normal}
1375 pre .nginx .built_in{font-weight:normal}
1376 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
1376 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
1377 .cm-s-ipython span.cm-variable{color:#000}
1377 .cm-s-ipython span.cm-variable{color:#000}
1378 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
1378 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
1379 .cm-s-ipython span.cm-number{color:#080}
1379 .cm-s-ipython span.cm-number{color:#080}
1380 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
1380 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
1381 .cm-s-ipython span.cm-string{color:#ba2121}
1381 .cm-s-ipython span.cm-string{color:#ba2121}
1382 .cm-s-ipython span.cm-builtin{color:#008000}
1382 .cm-s-ipython span.cm-builtin{color:#008000}
1383 .cm-s-ipython span.cm-error{color:#f00}
1383 .cm-s-ipython span.cm-error{color:#f00}
1384 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
1384 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
1385 .cm-s-ipython span.cm-meta{color:#a2f}
1385 .cm-s-ipython span.cm-meta{color:#a2f}
1386 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
1386 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
1387 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1387 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1388 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);display:block}
1388 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);display:block}
1389 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1389 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1390 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
1390 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
1391 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
1391 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
1392 div.output_prompt{color:#8b0000}
1392 div.output_prompt{color:#8b0000}
1393 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
1393 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
1394 div.output_area .rendered_html table{margin-left:0;margin-right:0}
1394 div.output_area .rendered_html table{margin-left:0;margin-right:0}
1395 div.output_area .rendered_html img{margin-left:0;margin-right:0}
1395 div.output_area .rendered_html img{margin-left:0;margin-right:0}
1396 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1396 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1397 div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
1397 div.output_area pre{margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
1398 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1398 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1399 div.output_text{text-align:left;color:#000;line-height:1.21429em}
1399 div.output_text{text-align:left;color:#000;line-height:1.21429em}
1400 div.output_stderr{background:#fdd;}
1400 div.output_stderr{background:#fdd;}
1401 div.output_latex{text-align:left}
1401 div.output_latex{text-align:left}
1402 div.output_javascript:empty{padding:0}
1402 div.output_javascript:empty{padding:0}
1403 .js-error{color:#8b0000}
1403 .js-error{color:#8b0000}
1404 div.raw_input_container{font-family:monospace;padding-top:5px}
1404 div.raw_input_container{font-family:monospace;padding-top:5px}
1405 span.raw_input_prompt{}
1405 span.raw_input_prompt{}
1406 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
1406 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}
1407 input.raw_input:focus{box-shadow:none}
1407 input.raw_input:focus{box-shadow:none}
1408 p.p-space{margin-bottom:10px}
1408 p.p-space{margin-bottom:10px}
1409 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
1409 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
1410 .rendered_html strong{font-weight:bold}
1410 .rendered_html strong{font-weight:bold}
1411 .rendered_html u{text-decoration:underline}
1411 .rendered_html u{text-decoration:underline}
1412 .rendered_html :link{text-decoration:underline}
1412 .rendered_html :link{text-decoration:underline}
1413 .rendered_html :visited{text-decoration:underline}
1413 .rendered_html :visited{text-decoration:underline}
1414 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
1414 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
1415 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
1415 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
1416 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
1416 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
1417 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
1417 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
1418 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1418 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1419 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1419 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1420 .rendered_html h1:first-child{margin-top:.538em}
1420 .rendered_html h1:first-child{margin-top:.538em}
1421 .rendered_html h2:first-child{margin-top:.636em}
1421 .rendered_html h2:first-child{margin-top:.636em}
1422 .rendered_html h3:first-child{margin-top:.777em}
1422 .rendered_html h3:first-child{margin-top:.777em}
1423 .rendered_html h4:first-child{margin-top:1em}
1423 .rendered_html h4:first-child{margin-top:1em}
1424 .rendered_html h5:first-child{margin-top:1em}
1424 .rendered_html h5:first-child{margin-top:1em}
1425 .rendered_html h6:first-child{margin-top:1em}
1425 .rendered_html h6:first-child{margin-top:1em}
1426 .rendered_html ul{list-style:disc;margin:0 2em}
1426 .rendered_html ul{list-style:disc;margin:0 2em}
1427 .rendered_html ul ul{list-style:square;margin:0 2em}
1427 .rendered_html ul ul{list-style:square;margin:0 2em}
1428 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
1428 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
1429 .rendered_html ol{list-style:decimal;margin:0 2em}
1429 .rendered_html ol{list-style:decimal;margin:0 2em}
1430 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
1430 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
1431 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
1431 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
1432 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
1432 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
1433 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
1433 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
1434 .rendered_html *+ul{margin-top:1em}
1434 .rendered_html *+ul{margin-top:1em}
1435 .rendered_html *+ol{margin-top:1em}
1435 .rendered_html *+ol{margin-top:1em}
1436 .rendered_html hr{color:#000;background-color:#000}
1436 .rendered_html hr{color:#000;background-color:#000}
1437 .rendered_html pre{margin:1em 2em}
1437 .rendered_html pre{margin:1em 2em}
1438 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
1438 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
1439 .rendered_html blockquote{margin:1em 2em}
1439 .rendered_html blockquote{margin:1em 2em}
1440 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
1440 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
1441 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
1441 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
1442 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
1442 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
1443 .rendered_html th{font-weight:bold}
1443 .rendered_html th{font-weight:bold}
1444 .rendered_html *+table{margin-top:1em}
1444 .rendered_html *+table{margin-top:1em}
1445 .rendered_html p{text-align:justify}
1445 .rendered_html p{text-align:justify}
1446 .rendered_html *+p{margin-top:1em}
1446 .rendered_html *+p{margin-top:1em}
1447 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
1447 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
1448 .rendered_html *+img{margin-top:1em}
1448 .rendered_html *+img{margin-top:1em}
1449 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1449 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1450 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
1450 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
1451 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
1451 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
1452 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
1452 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
1453 div.cell.text_cell.rendered{padding:0}
1453 div.cell.text_cell.rendered{padding:0}
1454 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1454 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1455 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
1455 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
1456 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
1456 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
1457 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
1457 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
1458 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
1458 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
1459 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
1459 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
1460 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;margin-bottom:10px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
1460 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;margin-bottom:10px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
1461 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
1461 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
1462 .widget-text{width:350px;margin:0 !important}
1462 .widget-text{width:350px;margin:0 !important}
1463 .widget-listbox{width:364px;margin-bottom:0}
1463 .widget-listbox{width:364px;margin-bottom:0}
1464 .widget-numeric-text{width:150px;margin:0 !important}
1464 .widget-numeric-text{width:150px;margin:0 !important}
1465 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
1465 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
1466 .widget-combo-btn{min-width:138px;}
1466 .widget-combo-btn{min-width:138px;}
1467 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1467 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1468 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1468 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1469 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
1469 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
1470 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1470 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1471 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
1471 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
1472 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
1472 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
1473 .widget-modal-body{max-height:none !important}
1473 .widget-modal-body{max-height:none !important}
1474 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1474 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}
1475 .widget-radio-box{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:4px}
1475 .widget-radio-box{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:4px}
1476 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
1476 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
1477 body{background-color:#fff}
1477 body{background-color:#fff}
1478 body.notebook_app{overflow:hidden}
1478 body.notebook_app{overflow:hidden}
1479 span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%}
1479 span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%}
1480 div#notebook_panel{margin:0 0 0 0;padding:0;-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}
1480 div#notebook_panel{margin:0 0 0 0;padding:0;-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}
1481 div#notebook{font-size:14px;line-height:20px;overflow-y:scroll;overflow-x:auto;width:100%;padding:1em 0 1em 0;margin:0;border-top:1px solid #ababab;outline:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1481 div#notebook{font-size:14px;line-height:20px;overflow-y:scroll;overflow-x:auto;width:100%;padding:1em 0 1em 0;margin:0;border-top:1px solid #ababab;outline:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1482 div.ui-widget-content{border:1px solid #ababab;outline:none}
1482 div.ui-widget-content{border:1px solid #ababab;outline:none}
1483 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:.4em;padding-left:2em}
1483 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:.4em;padding-left:2em}
1484 p.dialog{padding:.2em}
1484 p.dialog{padding:.2em}
1485 pre,code,kbd,samp{white-space:pre-wrap}
1485 pre,code,kbd,samp{white-space:pre-wrap}
1486 #fonttest{font-family:monospace}
1486 #fonttest{font-family:monospace}
1487 p{margin-bottom:0}
1487 p{margin-bottom:0}
1488 .end_space{height:200px}
1488 .end_space{height:200px}
1489 .celltoolbar{border:thin solid #cfcfcf;border-bottom:none;background:#eee;border-radius:3px 3px 0 0;width:100%;-webkit-box-pack:end;height:22px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1489 .celltoolbar{border:thin solid #cfcfcf;border-bottom:none;background:#eee;border-radius:3px 3px 0 0;width:100%;-webkit-box-pack:end;height:22px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}
1490 .ctb_hideshow{display:none;vertical-align:bottom;padding-right:2px}
1490 .ctb_hideshow{display:none;vertical-align:bottom;padding-right:2px}
1491 .celltoolbar>div{padding-top:0}
1491 .celltoolbar>div{padding-top:0}
1492 .ctb_global_show .ctb_show.ctb_hideshow{display:block}
1492 .ctb_global_show .ctb_show.ctb_hideshow{display:block}
1493 .ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input{border-top-right-radius:0;border-top-left-radius:0}
1493 .ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input{border-top-right-radius:0;border-top-left-radius:0}
1494 .celltoolbar .button_container select{margin:10px;margin-top:1px;margin-bottom:0;padding:0;font-size:87%;width:auto;display:inline-block;height:18px;line-height:18px;vertical-align:top}
1494 .celltoolbar .button_container select{margin:10px;margin-top:1px;margin-bottom:0;padding:0;font-size:87%;width:auto;display:inline-block;height:18px;line-height:18px;vertical-align:top}
1495 .celltoolbar label{display:inline-block;height:15px;line-height:15px;vertical-align:top}
1495 .celltoolbar label{display:inline-block;height:15px;line-height:15px;vertical-align:top}
1496 .celltoolbar label span{font-size:85%}
1496 .celltoolbar label span{font-size:85%}
1497 .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px}
1497 .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px}
1498 .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px}
1498 .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px}
1499 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:4px;-webkit-box-shadow:0 6px 10px -1px #adadad;-moz-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad}
1499 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:4px;-webkit-box-shadow:0 6px 10px -1px #adadad;-moz-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad}
1500 .completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000}
1500 .completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000;width:auto}
1501 .completions select option.context{color:#0064cd}
1501 .completions select option.context{color:#0064cd}
1502 #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px}
1502 #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px}
1503 #menubar .navbar{margin-bottom:8px}
1503 #menubar .navbar{margin-bottom:8px}
1504 .nav-wrapper{border-bottom:1px solid #d4d4d4}
1504 .nav-wrapper{border-bottom:1px solid #d4d4d4}
1505 #menubar li.dropdown{line-height:12px}
1505 #menubar li.dropdown{line-height:12px}
1506 i.menu-icon{padding-top:4px}
1506 i.menu-icon{padding-top:4px}
1507 ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}
1507 ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}
1508 #notification_area{z-index:10}
1508 #notification_area{z-index:10}
1509 .indicator_area{color:#777;padding:4px 3px;margin:0;width:11px;z-index:10;text-align:center}
1509 .indicator_area{color:#777;padding:4px 3px;margin:0;width:11px;z-index:10;text-align:center}
1510 #kernel_indicator{margin-right:-16px}
1510 #kernel_indicator{margin-right:-16px}
1511 .edit_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f040"}
1511 .edit_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f040"}
1512 .command_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:' '}
1512 .command_mode_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:' '}
1513 .kernel_idle_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f10c"}
1513 .kernel_idle_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f10c"}
1514 .kernel_busy_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111"}
1514 .kernel_busy_icon:before{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111"}
1515 .notification_widget{color:#777;padding:1px 12px;margin:2px 4px;z-index:10;border:1px solid #ccc;border-radius:4px;background:rgba(240,240,240,0.5)}.notification_widget.span{padding-right:2px}
1515 .notification_widget{color:#777;padding:1px 12px;margin:2px 4px;z-index:10;border:1px solid #ccc;border-radius:4px;background:rgba(240,240,240,0.5)}.notification_widget.span{padding-right:2px}
1516 div#pager_splitter{height:8px}
1516 div#pager_splitter{height:8px}
1517 #pager-container{position:relative;padding:15px 0}
1517 #pager-container{position:relative;padding:15px 0}
1518 div#pager{font-size:14px;line-height:20px;overflow:auto;display:none}div#pager pre{font-size:13px;line-height:1.21429em;color:#000;background-color:#f7f7f7;padding:.4em}
1518 div#pager{font-size:14px;line-height:20px;overflow:auto;display:none}div#pager pre{font-size:13px;line-height:1.21429em;color:#000;background-color:#f7f7f7;padding:.4em}
1519 .quickhelp{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1519 .quickhelp{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1520 .shortcut_key{display:inline-block;width:20ex;text-align:right;font-family:monospace}
1520 .shortcut_key{display:inline-block;width:20ex;text-align:right;font-family:monospace}
1521 .shortcut_descr{display:inline-block;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1521 .shortcut_descr{display:inline-block;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1522 span#save_widget{padding:0 5px;margin-top:12px}
1522 span#save_widget{padding:0 5px;margin-top:12px}
1523 span#checkpoint_status,span#autosave_status{font-size:small}
1523 span#checkpoint_status,span#autosave_status{font-size:small}
1524 @media (max-width:767px){span#save_widget{font-size:small} span#checkpoint_status,span#autosave_status{font-size:x-small}}@media (max-width:767px){span#checkpoint_status,span#autosave_status{display:none}}@media (min-width:768px) and (max-width:979px){span#checkpoint_status{display:none} span#autosave_status{font-size:x-small}}.toolbar{padding:0 10px;margin-top:-5px}.toolbar select,.toolbar label{width:auto;height:26px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:0;padding-top:3px}
1524 @media (max-width:767px){span#save_widget{font-size:small} span#checkpoint_status,span#autosave_status{font-size:x-small}}@media (max-width:767px){span#checkpoint_status,span#autosave_status{display:none}}@media (min-width:768px) and (max-width:979px){span#checkpoint_status{display:none} span#autosave_status{font-size:x-small}}.toolbar{padding:0 10px;margin-top:-5px}.toolbar select,.toolbar label{width:auto;height:26px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:0;padding-top:3px}
1525 .toolbar .btn{padding:2px 8px}
1525 .toolbar .btn{padding:2px 8px}
1526 .toolbar .btn-group{margin-top:0}
1526 .toolbar .btn-group{margin-top:0}
1527 .toolbar-inner{border:none !important;-webkit-box-shadow:none !important;-moz-box-shadow:none !important;box-shadow:none !important}
1527 .toolbar-inner{border:none !important;-webkit-box-shadow:none !important;-moz-box-shadow:none !important;box-shadow:none !important}
1528 #maintoolbar{margin-bottom:0}
1528 #maintoolbar{margin-bottom:0}
1529 @-moz-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-webkit-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-moz-keyframes fadeIn{from{opacity:0} to{opacity:1}}@-webkit-keyframes fadeIn{from{opacity:0} to{opacity:1}}.bigtooltip{overflow:auto;height:200px;-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms}
1529 @-moz-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-webkit-keyframes fadeOut{from{opacity:1} to{opacity:0}}@-moz-keyframes fadeIn{from{opacity:0} to{opacity:1}}@-webkit-keyframes fadeIn{from{opacity:0} to{opacity:1}}.bigtooltip{overflow:auto;height:200px;-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms}
1530 .smalltooltip{-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms;text-overflow:ellipsis;overflow:hidden;height:80px}
1530 .smalltooltip{-webkit-transition-property:height;-webkit-transition-duration:500ms;-moz-transition-property:height;-moz-transition-duration:500ms;transition-property:height;transition-duration:500ms;text-overflow:ellipsis;overflow:hidden;height:80px}
1531 .tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}
1531 .tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}
1532 .tooltiptext{padding-right:30px}
1532 .tooltiptext{padding-right:30px}
1533 .ipython_tooltip{max-width:700px;-webkit-animation:fadeOut 400ms;-moz-animation:fadeOut 400ms;animation:fadeOut 400ms;-webkit-animation:fadeIn 400ms;-moz-animation:fadeIn 400ms;animation:fadeIn 400ms;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:#ababab 1px solid;outline:none;padding:3px;margin:0;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:4px;position:absolute;z-index:2}.ipython_tooltip a{float:right}
1533 .ipython_tooltip{max-width:700px;-webkit-animation:fadeOut 400ms;-moz-animation:fadeOut 400ms;animation:fadeOut 400ms;-webkit-animation:fadeIn 400ms;-moz-animation:fadeIn 400ms;animation:fadeIn 400ms;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:#ababab 1px solid;outline:none;padding:3px;margin:0;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:4px;position:absolute;z-index:2}.ipython_tooltip a{float:right}
1534 .ipython_tooltip .tooltiptext pre{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;font-size:100%;background-color:#f7f7f7}
1534 .ipython_tooltip .tooltiptext pre{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;font-size:100%;background-color:#f7f7f7}
1535 .pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}
1535 .pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}
1536 .pretooltiparrow:before{background-color:#f7f7f7;border:1px #ababab solid;z-index:11;content:"";position:absolute;left:15px;top:10px;width:25px;height:25px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg)}
1536 .pretooltiparrow:before{background-color:#f7f7f7;border:1px #ababab solid;z-index:11;content:"";position:absolute;left:15px;top:10px;width:25px;height:25px;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg)}
@@ -1,450 +1,451 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Base Widget Model and View classes
9 // Base Widget Model and View classes
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 **/
15 **/
16
16
17 define(["widgets/js/manager",
17 define(["widgets/js/manager",
18 "underscore",
18 "underscore",
19 "backbone"],
19 "backbone"],
20 function(WidgetManager, _, Backbone){
20 function(WidgetManager, _, Backbone){
21
21
22 var WidgetModel = Backbone.Model.extend({
22 var WidgetModel = Backbone.Model.extend({
23 constructor: function (widget_manager, model_id, comm) {
23 constructor: function (widget_manager, model_id, comm) {
24 // Constructor
24 // Constructor
25 //
25 //
26 // Creates a WidgetModel instance.
26 // Creates a WidgetModel instance.
27 //
27 //
28 // Parameters
28 // Parameters
29 // ----------
29 // ----------
30 // widget_manager : WidgetManager instance
30 // widget_manager : WidgetManager instance
31 // model_id : string
31 // model_id : string
32 // An ID unique to this model.
32 // An ID unique to this model.
33 // comm : Comm instance (optional)
33 // comm : Comm instance (optional)
34 this.widget_manager = widget_manager;
34 this.widget_manager = widget_manager;
35 this._buffered_state_diff = {};
35 this._buffered_state_diff = {};
36 this.pending_msgs = 0;
36 this.pending_msgs = 0;
37 this.msg_buffer = null;
37 this.msg_buffer = null;
38 this.key_value_lock = null;
38 this.key_value_lock = null;
39 this.id = model_id;
39 this.id = model_id;
40 this.views = [];
40 this.views = [];
41
41
42 if (comm !== undefined) {
42 if (comm !== undefined) {
43 // Remember comm associated with the model.
43 // Remember comm associated with the model.
44 this.comm = comm;
44 this.comm = comm;
45 comm.model = this;
45 comm.model = this;
46
46
47 // Hook comm messages up to model.
47 // Hook comm messages up to model.
48 comm.on_close($.proxy(this._handle_comm_closed, this));
48 comm.on_close($.proxy(this._handle_comm_closed, this));
49 comm.on_msg($.proxy(this._handle_comm_msg, this));
49 comm.on_msg($.proxy(this._handle_comm_msg, this));
50 }
50 }
51 return Backbone.Model.apply(this);
51 return Backbone.Model.apply(this);
52 },
52 },
53
53
54 send: function (content, callbacks) {
54 send: function (content, callbacks) {
55 // Send a custom msg over the comm.
55 // Send a custom msg over the comm.
56 if (this.comm !== undefined) {
56 if (this.comm !== undefined) {
57 var data = {method: 'custom', content: content};
57 var data = {method: 'custom', content: content};
58 this.comm.send(data, callbacks);
58 this.comm.send(data, callbacks);
59 this.pending_msgs++;
59 this.pending_msgs++;
60 }
60 }
61 },
61 },
62
62
63 _handle_comm_closed: function (msg) {
63 _handle_comm_closed: function (msg) {
64 // Handle when a widget is closed.
64 // Handle when a widget is closed.
65 this.trigger('comm:close');
65 this.trigger('comm:close');
66 delete this.comm.model; // Delete ref so GC will collect widget model.
66 delete this.comm.model; // Delete ref so GC will collect widget model.
67 delete this.comm;
67 delete this.comm;
68 delete this.model_id; // Delete id from model so widget manager cleans up.
68 delete this.model_id; // Delete id from model so widget manager cleans up.
69 _.each(this.views, function(view, i) {
69 _.each(this.views, function(view, i) {
70 view.remove();
70 view.remove();
71 });
71 });
72 },
72 },
73
73
74 _handle_comm_msg: function (msg) {
74 _handle_comm_msg: function (msg) {
75 // Handle incoming comm msg.
75 // Handle incoming comm msg.
76 var method = msg.content.data.method;
76 var method = msg.content.data.method;
77 switch (method) {
77 switch (method) {
78 case 'update':
78 case 'update':
79 this.apply_update(msg.content.data.state);
79 this.apply_update(msg.content.data.state);
80 break;
80 break;
81 case 'custom':
81 case 'custom':
82 this.trigger('msg:custom', msg.content.data.content);
82 this.trigger('msg:custom', msg.content.data.content);
83 break;
83 break;
84 case 'display':
84 case 'display':
85 this.widget_manager.display_view(msg, this);
85 this.widget_manager.display_view(msg, this);
86 this.trigger('displayed');
86 break;
87 break;
87 }
88 }
88 },
89 },
89
90
90 apply_update: function (state) {
91 apply_update: function (state) {
91 // Handle when a widget is updated via the python side.
92 // Handle when a widget is updated via the python side.
92 var that = this;
93 var that = this;
93 _.each(state, function(value, key) {
94 _.each(state, function(value, key) {
94 that.key_value_lock = [key, value];
95 that.key_value_lock = [key, value];
95 try {
96 try {
96 WidgetModel.__super__.set.apply(that, [key, that._unpack_models(value)]);
97 WidgetModel.__super__.set.apply(that, [key, that._unpack_models(value)]);
97 } finally {
98 } finally {
98 that.key_value_lock = null;
99 that.key_value_lock = null;
99 }
100 }
100 });
101 });
101 },
102 },
102
103
103 _handle_status: function (msg, callbacks) {
104 _handle_status: function (msg, callbacks) {
104 // Handle status msgs.
105 // Handle status msgs.
105
106
106 // execution_state : ('busy', 'idle', 'starting')
107 // execution_state : ('busy', 'idle', 'starting')
107 if (this.comm !== undefined) {
108 if (this.comm !== undefined) {
108 if (msg.content.execution_state ==='idle') {
109 if (msg.content.execution_state ==='idle') {
109 // Send buffer if this message caused another message to be
110 // Send buffer if this message caused another message to be
110 // throttled.
111 // throttled.
111 if (this.msg_buffer !== null &&
112 if (this.msg_buffer !== null &&
112 (this.get('msg_throttle') || 3) === this.pending_msgs) {
113 (this.get('msg_throttle') || 3) === this.pending_msgs) {
113 var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
114 var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
114 this.comm.send(data, callbacks);
115 this.comm.send(data, callbacks);
115 this.msg_buffer = null;
116 this.msg_buffer = null;
116 } else {
117 } else {
117 --this.pending_msgs;
118 --this.pending_msgs;
118 }
119 }
119 }
120 }
120 }
121 }
121 },
122 },
122
123
123 callbacks: function(view) {
124 callbacks: function(view) {
124 // Create msg callbacks for a comm msg.
125 // Create msg callbacks for a comm msg.
125 var callbacks = this.widget_manager.callbacks(view);
126 var callbacks = this.widget_manager.callbacks(view);
126
127
127 if (callbacks.iopub === undefined) {
128 if (callbacks.iopub === undefined) {
128 callbacks.iopub = {};
129 callbacks.iopub = {};
129 }
130 }
130
131
131 var that = this;
132 var that = this;
132 callbacks.iopub.status = function (msg) {
133 callbacks.iopub.status = function (msg) {
133 that._handle_status(msg, callbacks);
134 that._handle_status(msg, callbacks);
134 };
135 };
135 return callbacks;
136 return callbacks;
136 },
137 },
137
138
138 set: function(key, val, options) {
139 set: function(key, val, options) {
139 // Set a value.
140 // Set a value.
140 var return_value = WidgetModel.__super__.set.apply(this, arguments);
141 var return_value = WidgetModel.__super__.set.apply(this, arguments);
141
142
142 // Backbone only remembers the diff of the most recent set()
143 // Backbone only remembers the diff of the most recent set()
143 // operation. Calling set multiple times in a row results in a
144 // operation. Calling set multiple times in a row results in a
144 // loss of diff information. Here we keep our own running diff.
145 // loss of diff information. Here we keep our own running diff.
145 this._buffered_state_diff = $.extend(this._buffered_state_diff, this.changedAttributes() || {});
146 this._buffered_state_diff = $.extend(this._buffered_state_diff, this.changedAttributes() || {});
146 return return_value;
147 return return_value;
147 },
148 },
148
149
149 sync: function (method, model, options) {
150 sync: function (method, model, options) {
150 // Handle sync to the back-end. Called when a model.save() is called.
151 // Handle sync to the back-end. Called when a model.save() is called.
151
152
152 // Make sure a comm exists.
153 // Make sure a comm exists.
153 var error = options.error || function() {
154 var error = options.error || function() {
154 console.error('Backbone sync error:', arguments);
155 console.error('Backbone sync error:', arguments);
155 };
156 };
156 if (this.comm === undefined) {
157 if (this.comm === undefined) {
157 error();
158 error();
158 return false;
159 return false;
159 }
160 }
160
161
161 // Delete any key value pairs that the back-end already knows about.
162 // Delete any key value pairs that the back-end already knows about.
162 var attrs = (method === 'patch') ? options.attrs : model.toJSON(options);
163 var attrs = (method === 'patch') ? options.attrs : model.toJSON(options);
163 if (this.key_value_lock !== null) {
164 if (this.key_value_lock !== null) {
164 var key = this.key_value_lock[0];
165 var key = this.key_value_lock[0];
165 var value = this.key_value_lock[1];
166 var value = this.key_value_lock[1];
166 if (attrs[key] === value) {
167 if (attrs[key] === value) {
167 delete attrs[key];
168 delete attrs[key];
168 }
169 }
169 }
170 }
170
171
171 // Only sync if there are attributes to send to the back-end.
172 // Only sync if there are attributes to send to the back-end.
172 attrs = this._pack_models(attrs);
173 attrs = this._pack_models(attrs);
173 if (_.size(attrs) > 0) {
174 if (_.size(attrs) > 0) {
174
175
175 // If this message was sent via backbone itself, it will not
176 // If this message was sent via backbone itself, it will not
176 // have any callbacks. It's important that we create callbacks
177 // have any callbacks. It's important that we create callbacks
177 // so we can listen for status messages, etc...
178 // so we can listen for status messages, etc...
178 var callbacks = options.callbacks || this.callbacks();
179 var callbacks = options.callbacks || this.callbacks();
179
180
180 // Check throttle.
181 // Check throttle.
181 if (this.pending_msgs >= (this.get('msg_throttle') || 3)) {
182 if (this.pending_msgs >= (this.get('msg_throttle') || 3)) {
182 // The throttle has been exceeded, buffer the current msg so
183 // The throttle has been exceeded, buffer the current msg so
183 // it can be sent once the kernel has finished processing
184 // it can be sent once the kernel has finished processing
184 // some of the existing messages.
185 // some of the existing messages.
185
186
186 // Combine updates if it is a 'patch' sync, otherwise replace updates
187 // Combine updates if it is a 'patch' sync, otherwise replace updates
187 switch (method) {
188 switch (method) {
188 case 'patch':
189 case 'patch':
189 this.msg_buffer = $.extend(this.msg_buffer || {}, attrs);
190 this.msg_buffer = $.extend(this.msg_buffer || {}, attrs);
190 break;
191 break;
191 case 'update':
192 case 'update':
192 case 'create':
193 case 'create':
193 this.msg_buffer = attrs;
194 this.msg_buffer = attrs;
194 break;
195 break;
195 default:
196 default:
196 error();
197 error();
197 return false;
198 return false;
198 }
199 }
199 this.msg_buffer_callbacks = callbacks;
200 this.msg_buffer_callbacks = callbacks;
200
201
201 } else {
202 } else {
202 // We haven't exceeded the throttle, send the message like
203 // We haven't exceeded the throttle, send the message like
203 // normal.
204 // normal.
204 var data = {method: 'backbone', sync_data: attrs};
205 var data = {method: 'backbone', sync_data: attrs};
205 this.comm.send(data, callbacks);
206 this.comm.send(data, callbacks);
206 this.pending_msgs++;
207 this.pending_msgs++;
207 }
208 }
208 }
209 }
209 // Since the comm is a one-way communication, assume the message
210 // Since the comm is a one-way communication, assume the message
210 // arrived. Don't call success since we don't have a model back from the server
211 // arrived. Don't call success since we don't have a model back from the server
211 // this means we miss out on the 'sync' event.
212 // this means we miss out on the 'sync' event.
212 this._buffered_state_diff = {};
213 this._buffered_state_diff = {};
213 },
214 },
214
215
215 save_changes: function(callbacks) {
216 save_changes: function(callbacks) {
216 // Push this model's state to the back-end
217 // Push this model's state to the back-end
217 //
218 //
218 // This invokes a Backbone.Sync.
219 // This invokes a Backbone.Sync.
219 this.save(this._buffered_state_diff, {patch: true, callbacks: callbacks});
220 this.save(this._buffered_state_diff, {patch: true, callbacks: callbacks});
220 },
221 },
221
222
222 _pack_models: function(value) {
223 _pack_models: function(value) {
223 // Replace models with model ids recursively.
224 // Replace models with model ids recursively.
224 if (value instanceof Backbone.Model) {
225 if (value instanceof Backbone.Model) {
225 return value.id;
226 return value.id;
226
227
227 } else if ($.isArray(value)) {
228 } else if ($.isArray(value)) {
228 var packed = [];
229 var packed = [];
229 var that = this;
230 var that = this;
230 _.each(value, function(sub_value, key) {
231 _.each(value, function(sub_value, key) {
231 packed.push(that._pack_models(sub_value));
232 packed.push(that._pack_models(sub_value));
232 });
233 });
233 return packed;
234 return packed;
234
235
235 } else if (value instanceof Object) {
236 } else if (value instanceof Object) {
236 var packed = {};
237 var packed = {};
237 var that = this;
238 var that = this;
238 _.each(value, function(sub_value, key) {
239 _.each(value, function(sub_value, key) {
239 packed[key] = that._pack_models(sub_value);
240 packed[key] = that._pack_models(sub_value);
240 });
241 });
241 return packed;
242 return packed;
242
243
243 } else {
244 } else {
244 return value;
245 return value;
245 }
246 }
246 },
247 },
247
248
248 _unpack_models: function(value) {
249 _unpack_models: function(value) {
249 // Replace model ids with models recursively.
250 // Replace model ids with models recursively.
250 if ($.isArray(value)) {
251 if ($.isArray(value)) {
251 var unpacked = [];
252 var unpacked = [];
252 var that = this;
253 var that = this;
253 _.each(value, function(sub_value, key) {
254 _.each(value, function(sub_value, key) {
254 unpacked.push(that._unpack_models(sub_value));
255 unpacked.push(that._unpack_models(sub_value));
255 });
256 });
256 return unpacked;
257 return unpacked;
257
258
258 } else if (value instanceof Object) {
259 } else if (value instanceof Object) {
259 var unpacked = {};
260 var unpacked = {};
260 var that = this;
261 var that = this;
261 _.each(value, function(sub_value, key) {
262 _.each(value, function(sub_value, key) {
262 unpacked[key] = that._unpack_models(sub_value);
263 unpacked[key] = that._unpack_models(sub_value);
263 });
264 });
264 return unpacked;
265 return unpacked;
265
266
266 } else {
267 } else {
267 var model = this.widget_manager.get_model(value);
268 var model = this.widget_manager.get_model(value);
268 if (model) {
269 if (model) {
269 return model;
270 return model;
270 } else {
271 } else {
271 return value;
272 return value;
272 }
273 }
273 }
274 }
274 },
275 },
275
276
276 });
277 });
277 WidgetManager.register_widget_model('WidgetModel', WidgetModel);
278 WidgetManager.register_widget_model('WidgetModel', WidgetModel);
278
279
279
280
280 var WidgetView = Backbone.View.extend({
281 var WidgetView = Backbone.View.extend({
281 initialize: function(parameters) {
282 initialize: function(parameters) {
282 // Public constructor.
283 // Public constructor.
283 this.model.on('change',this.update,this);
284 this.model.on('change',this.update,this);
284 this.options = parameters.options;
285 this.options = parameters.options;
285 this.child_views = [];
286 this.child_views = [];
286 this.model.views.push(this);
287 this.model.views.push(this);
287 },
288 },
288
289
289 update: function(){
290 update: function(){
290 // Triggered on model change.
291 // Triggered on model change.
291 //
292 //
292 // Update view to be consistent with this.model
293 // Update view to be consistent with this.model
293 },
294 },
294
295
295 create_child_view: function(child_model, options) {
296 create_child_view: function(child_model, options) {
296 // Create and return a child view.
297 // Create and return a child view.
297 //
298 //
298 // -given a model and (optionally) a view name if the view name is
299 // -given a model and (optionally) a view name if the view name is
299 // not given, it defaults to the model's default view attribute.
300 // not given, it defaults to the model's default view attribute.
300
301
301 // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior
302 // TODO: this is hacky, and makes the view depend on this cell attribute and widget manager behavior
302 // it would be great to have the widget manager add the cell metadata
303 // it would be great to have the widget manager add the cell metadata
303 // to the subview without having to add it here.
304 // to the subview without having to add it here.
304 var child_view = this.model.widget_manager.create_view(child_model, options || {}, this);
305 var child_view = this.model.widget_manager.create_view(child_model, options || {}, this);
305 this.child_views[child_model.id] = child_view;
306 this.child_views[child_model.id] = child_view;
306 return child_view;
307 return child_view;
307 },
308 },
308
309
309 delete_child_view: function(child_model, options) {
310 delete_child_view: function(child_model, options) {
310 // Delete a child view that was previously created using create_child_view.
311 // Delete a child view that was previously created using create_child_view.
311 var view = this.child_views[child_model.id];
312 var view = this.child_views[child_model.id];
312 if (view !== undefined) {
313 if (view !== undefined) {
313 delete this.child_views[child_model.id];
314 delete this.child_views[child_model.id];
314 view.remove();
315 view.remove();
315 }
316 }
316 },
317 },
317
318
318 do_diff: function(old_list, new_list, removed_callback, added_callback) {
319 do_diff: function(old_list, new_list, removed_callback, added_callback) {
319 // Difference a changed list and call remove and add callbacks for
320 // Difference a changed list and call remove and add callbacks for
320 // each removed and added item in the new list.
321 // each removed and added item in the new list.
321 //
322 //
322 // Parameters
323 // Parameters
323 // ----------
324 // ----------
324 // old_list : array
325 // old_list : array
325 // new_list : array
326 // new_list : array
326 // removed_callback : Callback(item)
327 // removed_callback : Callback(item)
327 // Callback that is called for each item removed.
328 // Callback that is called for each item removed.
328 // added_callback : Callback(item)
329 // added_callback : Callback(item)
329 // Callback that is called for each item added.
330 // Callback that is called for each item added.
330
331
331
332
332 // removed items
333 // removed items
333 _.each(_.difference(old_list, new_list), function(item, index, list) {
334 _.each(_.difference(old_list, new_list), function(item, index, list) {
334 removed_callback(item);
335 removed_callback(item);
335 }, this);
336 }, this);
336
337
337 // added items
338 // added items
338 _.each(_.difference(new_list, old_list), function(item, index, list) {
339 _.each(_.difference(new_list, old_list), function(item, index, list) {
339 added_callback(item);
340 added_callback(item);
340 }, this);
341 }, this);
341 },
342 },
342
343
343 callbacks: function(){
344 callbacks: function(){
344 // Create msg callbacks for a comm msg.
345 // Create msg callbacks for a comm msg.
345 return this.model.callbacks(this);
346 return this.model.callbacks(this);
346 },
347 },
347
348
348 render: function(){
349 render: function(){
349 // Render the view.
350 // Render the view.
350 //
351 //
351 // By default, this is only called the first time the view is created
352 // By default, this is only called the first time the view is created
352 },
353 },
353
354
354 send: function (content) {
355 send: function (content) {
355 // Send a custom msg associated with this view.
356 // Send a custom msg associated with this view.
356 this.model.send(content, this.callbacks());
357 this.model.send(content, this.callbacks());
357 },
358 },
358
359
359 touch: function () {
360 touch: function () {
360 this.model.save_changes(this.callbacks());
361 this.model.save_changes(this.callbacks());
361 },
362 },
362 });
363 });
363
364
364
365
365 var DOMWidgetView = WidgetView.extend({
366 var DOMWidgetView = WidgetView.extend({
366 initialize: function (options) {
367 initialize: function (options) {
367 // Public constructor
368 // Public constructor
368
369
369 // In the future we may want to make changes more granular
370 // In the future we may want to make changes more granular
370 // (e.g., trigger on visible:change).
371 // (e.g., trigger on visible:change).
371 this.model.on('change', this.update, this);
372 this.model.on('change', this.update, this);
372 this.model.on('msg:custom', this.on_msg, this);
373 this.model.on('msg:custom', this.on_msg, this);
373 DOMWidgetView.__super__.initialize.apply(this, arguments);
374 DOMWidgetView.__super__.initialize.apply(this, arguments);
374 },
375 },
375
376
376 on_msg: function(msg) {
377 on_msg: function(msg) {
377 // Handle DOM specific msgs.
378 // Handle DOM specific msgs.
378 switch(msg.msg_type) {
379 switch(msg.msg_type) {
379 case 'add_class':
380 case 'add_class':
380 this.add_class(msg.selector, msg.class_list);
381 this.add_class(msg.selector, msg.class_list);
381 break;
382 break;
382 case 'remove_class':
383 case 'remove_class':
383 this.remove_class(msg.selector, msg.class_list);
384 this.remove_class(msg.selector, msg.class_list);
384 break;
385 break;
385 }
386 }
386 },
387 },
387
388
388 add_class: function (selector, class_list) {
389 add_class: function (selector, class_list) {
389 // Add a DOM class to an element.
390 // Add a DOM class to an element.
390 this._get_selector_element(selector).addClass(class_list);
391 this._get_selector_element(selector).addClass(class_list);
391 },
392 },
392
393
393 remove_class: function (selector, class_list) {
394 remove_class: function (selector, class_list) {
394 // Remove a DOM class from an element.
395 // Remove a DOM class from an element.
395 this._get_selector_element(selector).removeClass(class_list);
396 this._get_selector_element(selector).removeClass(class_list);
396 },
397 },
397
398
398 update: function () {
399 update: function () {
399 // Update the contents of this view
400 // Update the contents of this view
400 //
401 //
401 // Called when the model is changed. The model may have been
402 // Called when the model is changed. The model may have been
402 // changed by another view or by a state update from the back-end.
403 // changed by another view or by a state update from the back-end.
403 // The very first update seems to happen before the element is
404 // The very first update seems to happen before the element is
404 // finished rendering so we use setTimeout to give the element time
405 // finished rendering so we use setTimeout to give the element time
405 // to render
406 // to render
406 var e = this.$el;
407 var e = this.$el;
407 var visible = this.model.get('visible');
408 var visible = this.model.get('visible');
408 setTimeout(function() {e.toggle(visible);},0);
409 setTimeout(function() {e.toggle(visible);},0);
409
410
410 var css = this.model.get('_css');
411 var css = this.model.get('_css');
411 if (css === undefined) {return;}
412 if (css === undefined) {return;}
412 var that = this;
413 var that = this;
413 _.each(css, function(css_traits, selector){
414 _.each(css, function(css_traits, selector){
414 // Apply the css traits to all elements that match the selector.
415 // Apply the css traits to all elements that match the selector.
415 var elements = that._get_selector_element(selector);
416 var elements = that._get_selector_element(selector);
416 if (elements.length > 0) {
417 if (elements.length > 0) {
417 _.each(css_traits, function(css_value, css_key){
418 _.each(css_traits, function(css_value, css_key){
418 elements.css(css_key, css_value);
419 elements.css(css_key, css_value);
419 });
420 });
420 }
421 }
421 });
422 });
422 },
423 },
423
424
424 _get_selector_element: function (selector) {
425 _get_selector_element: function (selector) {
425 // Get the elements via the css selector.
426 // Get the elements via the css selector.
426
427
427 // If the selector is blank, apply the style to the $el_to_style
428 // If the selector is blank, apply the style to the $el_to_style
428 // element. If the $el_to_style element is not defined, use apply
429 // element. If the $el_to_style element is not defined, use apply
429 // the style to the view's element.
430 // the style to the view's element.
430 var elements;
431 var elements;
431 if (!selector) {
432 if (!selector) {
432 if (this.$el_to_style === undefined) {
433 if (this.$el_to_style === undefined) {
433 elements = this.$el;
434 elements = this.$el;
434 } else {
435 } else {
435 elements = this.$el_to_style;
436 elements = this.$el_to_style;
436 }
437 }
437 } else {
438 } else {
438 elements = this.$el.find(selector);
439 elements = this.$el.find(selector);
439 }
440 }
440 return elements;
441 return elements;
441 },
442 },
442 });
443 });
443
444
444 IPython.WidgetModel = WidgetModel;
445 IPython.WidgetModel = WidgetModel;
445 IPython.WidgetView = WidgetView;
446 IPython.WidgetView = WidgetView;
446 IPython.DOMWidgetView = DOMWidgetView;
447 IPython.DOMWidgetView = DOMWidgetView;
447
448
448 // Pass through WidgetManager namespace.
449 // Pass through WidgetManager namespace.
449 return WidgetManager;
450 return WidgetManager;
450 });
451 });
@@ -1,244 +1,243 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // SelectionContainerWidget
9 // SelectionContainerWidget
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 **/
15 **/
16
16
17 define(["widgets/js/widget"], function(WidgetManager){
17 define(["widgets/js/widget"], function(WidgetManager){
18
18
19 var AccordionView = IPython.DOMWidgetView.extend({
19 var AccordionView = IPython.DOMWidgetView.extend({
20 render: function(){
20 render: function(){
21 // Called when view is rendered.
21 // Called when view is rendered.
22 var guid = 'accordion' + IPython.utils.uuid();
22 var guid = 'accordion' + IPython.utils.uuid();
23 this.$el
23 this.$el
24 .attr('id', guid)
24 .attr('id', guid)
25 .addClass('accordion');
25 .addClass('accordion');
26 this.containers = [];
26 this.containers = [];
27 this.model_containers = {};
27 this.model_containers = {};
28 this.update_children([], this.model.get('_children'));
28 this.update_children([], this.model.get('_children'));
29 this.model.on('change:_children', function(model, value, options) {
29 this.model.on('change:_children', function(model, value, options) {
30 this.update_children(model.previous('_children'), value);
30 this.update_children(model.previous('_children'), value);
31 }, this);
31 }, this);
32 this.model.on('change:selected_index', function(model, value, options) {
33 this.update_selected_index(model.previous('selected_index'), value, options);
34 }, this);
35 this.model.on('change:_titles', function(model, value, options) {
36 this.update_titles(value);
37 }, this);
38 this.model.on('displayed', function() {
39 this.update_titles();
40 }, this);
32 },
41 },
33
34 update: function(options) {
35 // Update the contents of this view
36 //
37 // Called when the model is changed. The model may have been
38 // changed by another view or by a state update from the back-end.
39 if (options === undefined || options.updated_view != this) {
40 // Set tab titles
41 var titles = this.model.get('_titles');
42 var that = this;
43 _.each(titles, function(title, page_index) {
44 var accordian = that.containers[page_index];
45 if (accordian !== undefined) {
46 accordian
47 .find('.accordion-heading')
48 .find('.accordion-toggle')
49 .text(title);
50 }
51 });
52
42
53 // Set selected page
43 update_titles: function(titles) {
54 var selected_index = this.model.get("selected_index");
44 // Set tab titles
55 if (0 <= selected_index && selected_index < this.containers.length) {
45 if (!titles) {
56 _.each(this.containers, function(container, index) {
46 titles = this.model.get('_titles');
57 if (index==selected_index) {
47 }
58 container.find('.accordion-body').collapse('show');
48
59 } else {
49 var that = this;
60 container.find('.accordion-body').collapse('hide');
50 _.each(titles, function(title, page_index) {
61 }
51 var accordian = that.containers[page_index];
62 });
52 if (accordian !== undefined) {
53 accordian
54 .find('.accordion-heading')
55 .find('.accordion-toggle')
56 .text(title);
57 }
58 });
59 },
60
61 update_selected_index: function(old_index, new_index, options) {
62 // Only update the selection if the selection wasn't triggered
63 // by the front-end. It must be triggered by the back-end.
64 if (options === undefined || options.updated_view != this) {
65 this.containers[old_index].find('.accordion-body').collapse('hide');
66 if (0 <= new_index && new_index < this.containers.length) {
67 this.containers[new_index].find('.accordion-body').collapse('show');
63 }
68 }
64 }
69 }
65 return AccordionView.__super__.update.apply(this);
66 },
70 },
67
71
68 update_children: function(old_list, new_list) {
72 update_children: function(old_list, new_list) {
69 // Called when the children list is modified.
73 // Called when the children list is modified.
70 this.do_diff(old_list,
74 this.do_diff(old_list,
71 new_list,
75 new_list,
72 $.proxy(this.remove_child_model, this),
76 $.proxy(this.remove_child_model, this),
73 $.proxy(this.add_child_model, this));
77 $.proxy(this.add_child_model, this));
74 },
78 },
75
79
76 remove_child_model: function(model) {
80 remove_child_model: function(model) {
77 // Called when a child is removed from children list.
81 // Called when a child is removed from children list.
78 var accordion_group = this.model_containers[model.id];
82 var accordion_group = this.model_containers[model.id];
79 this.containers.splice(accordion_group.container_index, 1);
83 this.containers.splice(accordion_group.container_index, 1);
80 delete this.model_containers[model.id];
84 delete this.model_containers[model.id];
81 accordion_group.remove();
85 accordion_group.remove();
82 this.delete_child_view(model);
86 this.delete_child_view(model);
83 },
87 },
84
88
85 add_child_model: function(model) {
89 add_child_model: function(model) {
86 // Called when a child is added to children list.
90 // Called when a child is added to children list.
87 var view = this.create_child_view(model);
91 var view = this.create_child_view(model);
88 var index = this.containers.length;
92 var index = this.containers.length;
89 var uuid = IPython.utils.uuid();
93 var uuid = IPython.utils.uuid();
90 var accordion_group = $('<div />')
94 var accordion_group = $('<div />')
91 .addClass('accordion-group')
95 .addClass('accordion-group')
92 .appendTo(this.$el);
96 .appendTo(this.$el);
93 var accordion_heading = $('<div />')
97 var accordion_heading = $('<div />')
94 .addClass('accordion-heading')
98 .addClass('accordion-heading')
95 .appendTo(accordion_group);
99 .appendTo(accordion_group);
96 var that = this;
100 var that = this;
97 var accordion_toggle = $('<a />')
101 var accordion_toggle = $('<a />')
98 .addClass('accordion-toggle')
102 .addClass('accordion-toggle')
99 .attr('data-toggle', 'collapse')
103 .attr('data-toggle', 'collapse')
100 .attr('data-parent', '#' + this.$el.attr('id'))
104 .attr('data-parent', '#' + this.$el.attr('id'))
101 .attr('href', '#' + uuid)
105 .attr('href', '#' + uuid)
102 .click(function(evt){
106 .click(function(evt){
103
107
104 // Calling model.set will trigger all of the other views of the
108 // Calling model.set will trigger all of the other views of the
105 // model to update.
109 // model to update.
106 that.model.set("selected_index", index, {updated_view: this});
110 that.model.set("selected_index", index, {updated_view: that});
107 that.touch();
111 that.touch();
108 })
112 })
109 .text('Page ' + index)
113 .text('Page ' + index)
110 .appendTo(accordion_heading);
114 .appendTo(accordion_heading);
111 var accordion_body = $('<div />', {id: uuid})
115 var accordion_body = $('<div />', {id: uuid})
112 .addClass('accordion-body collapse')
116 .addClass('accordion-body collapse')
113 .appendTo(accordion_group);
117 .appendTo(accordion_group);
114 var accordion_inner = $('<div />')
118 var accordion_inner = $('<div />')
115 .addClass('accordion-inner')
119 .addClass('accordion-inner')
116 .appendTo(accordion_body);
120 .appendTo(accordion_body);
117 var container_index = this.containers.push(accordion_group) - 1;
121 var container_index = this.containers.push(accordion_group) - 1;
118 accordion_group.container_index = container_index;
122 accordion_group.container_index = container_index;
119 this.model_containers[model.id] = accordion_group;
123 this.model_containers[model.id] = accordion_group;
120 accordion_inner.append(view.$el);
124 accordion_inner.append(view.$el);
121
125
122 this.update();
126 this.update();
123
127 this.update_titles();
124 // Stupid workaround to close the bootstrap accordion tabs which
125 // open by default even though they don't have the `in` class
126 // attached to them. For some reason a delay is required.
127 // TODO: Better fix.
128 setTimeout(function(){ that.update(); }, 500);
129 },
128 },
130 });
129 });
131 WidgetManager.register_widget_view('AccordionView', AccordionView);
130 WidgetManager.register_widget_view('AccordionView', AccordionView);
132
131
133
132
134 var TabView = IPython.DOMWidgetView.extend({
133 var TabView = IPython.DOMWidgetView.extend({
135 initialize: function() {
134 initialize: function() {
136 // Public constructor.
135 // Public constructor.
137 this.containers = [];
136 this.containers = [];
138 TabView.__super__.initialize.apply(this, arguments);
137 TabView.__super__.initialize.apply(this, arguments);
139 },
138 },
140
139
141 render: function(){
140 render: function(){
142 // Called when view is rendered.
141 // Called when view is rendered.
143 var uuid = 'tabs'+IPython.utils.uuid();
142 var uuid = 'tabs'+IPython.utils.uuid();
144 var that = this;
143 var that = this;
145 this.$tabs = $('<div />', {id: uuid})
144 this.$tabs = $('<div />', {id: uuid})
146 .addClass('nav')
145 .addClass('nav')
147 .addClass('nav-tabs')
146 .addClass('nav-tabs')
148 .appendTo(this.$el);
147 .appendTo(this.$el);
149 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
148 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
150 .addClass('tab-content')
149 .addClass('tab-content')
151 .appendTo(this.$el);
150 .appendTo(this.$el);
152 this.containers = [];
151 this.containers = [];
153 this.update_children([], this.model.get('_children'));
152 this.update_children([], this.model.get('_children'));
154 this.model.on('change:_children', function(model, value, options) {
153 this.model.on('change:_children', function(model, value, options) {
155 this.update_children(model.previous('_children'), value);
154 this.update_children(model.previous('_children'), value);
156 }, this);
155 }, this);
157 },
156 },
158
157
159 update_children: function(old_list, new_list) {
158 update_children: function(old_list, new_list) {
160 // Called when the children list is modified.
159 // Called when the children list is modified.
161 this.do_diff(old_list,
160 this.do_diff(old_list,
162 new_list,
161 new_list,
163 $.proxy(this.remove_child_model, this),
162 $.proxy(this.remove_child_model, this),
164 $.proxy(this.add_child_model, this));
163 $.proxy(this.add_child_model, this));
165 },
164 },
166
165
167 remove_child_model: function(model) {
166 remove_child_model: function(model) {
168 // Called when a child is removed from children list.
167 // Called when a child is removed from children list.
169 var view = this.child_views[model.id];
168 var view = this.child_views[model.id];
170 this.containers.splice(view.parent_tab.tab_text_index, 1);
169 this.containers.splice(view.parent_tab.tab_text_index, 1);
171 view.parent_tab.remove();
170 view.parent_tab.remove();
172 view.parent_container.remove();
171 view.parent_container.remove();
173 view.remove();
172 view.remove();
174 this.delete_child_view(model);
173 this.delete_child_view(model);
175 },
174 },
176
175
177 add_child_model: function(model) {
176 add_child_model: function(model) {
178 // Called when a child is added to children list.
177 // Called when a child is added to children list.
179 var view = this.create_child_view(model);
178 var view = this.create_child_view(model);
180 var index = this.containers.length;
179 var index = this.containers.length;
181 var uuid = IPython.utils.uuid();
180 var uuid = IPython.utils.uuid();
182
181
183 var that = this;
182 var that = this;
184 var tab = $('<li />')
183 var tab = $('<li />')
185 .css('list-style-type', 'none')
184 .css('list-style-type', 'none')
186 .appendTo(this.$tabs);
185 .appendTo(this.$tabs);
187 view.parent_tab = tab;
186 view.parent_tab = tab;
188
187
189 var tab_text = $('<a />')
188 var tab_text = $('<a />')
190 .attr('href', '#' + uuid)
189 .attr('href', '#' + uuid)
191 .attr('data-toggle', 'tab')
190 .attr('data-toggle', 'tab')
192 .text('Page ' + index)
191 .text('Page ' + index)
193 .appendTo(tab)
192 .appendTo(tab)
194 .click(function (e) {
193 .click(function (e) {
195
194
196 // Calling model.set will trigger all of the other views of the
195 // Calling model.set will trigger all of the other views of the
197 // model to update.
196 // model to update.
198 that.model.set("selected_index", index, {updated_view: this});
197 that.model.set("selected_index", index, {updated_view: this});
199 that.touch();
198 that.touch();
200 that.select_page(index);
199 that.select_page(index);
201 });
200 });
202 tab.tab_text_index = this.containers.push(tab_text) - 1;
201 tab.tab_text_index = this.containers.push(tab_text) - 1;
203
202
204 var contents_div = $('<div />', {id: uuid})
203 var contents_div = $('<div />', {id: uuid})
205 .addClass('tab-pane')
204 .addClass('tab-pane')
206 .addClass('fade')
205 .addClass('fade')
207 .append(view.$el)
206 .append(view.$el)
208 .appendTo(this.$tab_contents);
207 .appendTo(this.$tab_contents);
209 view.parent_container = contents_div;
208 view.parent_container = contents_div;
210 },
209 },
211
210
212 update: function(options) {
211 update: function(options) {
213 // Update the contents of this view
212 // Update the contents of this view
214 //
213 //
215 // Called when the model is changed. The model may have been
214 // Called when the model is changed. The model may have been
216 // changed by another view or by a state update from the back-end.
215 // changed by another view or by a state update from the back-end.
217 if (options === undefined || options.updated_view != this) {
216 if (options === undefined || options.updated_view != this) {
218 // Set tab titles
217 // Set tab titles
219 var titles = this.model.get('_titles');
218 var titles = this.model.get('_titles');
220 var that = this;
219 var that = this;
221 _.each(titles, function(title, page_index) {
220 _.each(titles, function(title, page_index) {
222 var tab_text = that.containers[page_index];
221 var tab_text = that.containers[page_index];
223 if (tab_text !== undefined) {
222 if (tab_text !== undefined) {
224 tab_text.text(title);
223 tab_text.text(title);
225 }
224 }
226 });
225 });
227
226
228 var selected_index = this.model.get('selected_index');
227 var selected_index = this.model.get('selected_index');
229 if (0 <= selected_index && selected_index < this.containers.length) {
228 if (0 <= selected_index && selected_index < this.containers.length) {
230 this.select_page(selected_index);
229 this.select_page(selected_index);
231 }
230 }
232 }
231 }
233 return TabView.__super__.update.apply(this);
232 return TabView.__super__.update.apply(this);
234 },
233 },
235
234
236 select_page: function(index) {
235 select_page: function(index) {
237 // Select a page.
236 // Select a page.
238 this.$tabs.find('li')
237 this.$tabs.find('li')
239 .removeClass('active');
238 .removeClass('active');
240 this.containers[index].tab('show');
239 this.containers[index].tab('show');
241 },
240 },
242 });
241 });
243 WidgetManager.register_widget_view('TabView', TabView);
242 WidgetManager.register_widget_view('TabView', TabView);
244 });
243 });
@@ -1,108 +1,113 b''
1 // Test multicontainer class
1 // Test multicontainer class
2 casper.notebook_test(function () {
2 casper.notebook_test(function () {
3 index = this.append_cell(
3 index = this.append_cell(
4 'from IPython.html import widgets\n' +
4 'from IPython.html import widgets\n' +
5 'from IPython.display import display, clear_output\n' +
5 'from IPython.display import display, clear_output\n' +
6 'print("Success")');
6 'print("Success")');
7 this.execute_cell_then(index);
7 this.execute_cell_then(index);
8
8
9 // Test tab view
9 // Test tab view
10 var multicontainer1_query = '.widget-area .widget-subarea div div.nav-tabs';
10 var multicontainer1_query = '.widget-area .widget-subarea div div.nav-tabs';
11 var multicontainer1_index = this.append_cell(
11 var multicontainer1_index = this.append_cell(
12 'multicontainer = widgets.TabWidget()\n' +
12 'multicontainer = widgets.TabWidget()\n' +
13 'page1 = widgets.TextWidget()\n' +
13 'page1 = widgets.TextWidget()\n' +
14 'page2 = widgets.TextWidget()\n' +
14 'page2 = widgets.TextWidget()\n' +
15 'page3 = widgets.TextWidget()\n' +
15 'page3 = widgets.TextWidget()\n' +
16 'multicontainer.children = [page1, page2, page3]\n' +
16 'multicontainer.children = [page1, page2, page3]\n' +
17 'display(multicontainer)\n' +
17 'display(multicontainer)\n' +
18 'multicontainer.selected_index = 0\n' +
18 'multicontainer.selected_index = 0\n' +
19 'print("Success")\n');
19 'print("Success")\n');
20 this.execute_cell_then(multicontainer1_index, function(index){
20 this.execute_cell_then(multicontainer1_index, function(index){
21
21
22 this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
22 this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
23 'Create multicontainer cell executed with correct output. (1)');
23 'Create multicontainer cell executed with correct output. (1)');
24
24
25 this.test.assert(this.cell_element_exists(index,
25 this.test.assert(this.cell_element_exists(index,
26 '.widget-area .widget-subarea'),
26 '.widget-area .widget-subarea'),
27 'Widget subarea exists.');
27 'Widget subarea exists.');
28
28
29 this.test.assert(this.cell_element_exists(index, multicontainer1_query),
29 this.test.assert(this.cell_element_exists(index, multicontainer1_query),
30 'Widget tab list exists.');
30 'Widget tab list exists.');
31
31
32 this.test.assert(this.cell_element_exists(index, multicontainer1_query),
32 this.test.assert(this.cell_element_exists(index, multicontainer1_query),
33 'First widget tab list exists.');
33 'First widget tab list exists.');
34
34
35 // JQuery selector is 1 based
35 // JQuery selector is 1 based
36 this.click(multicontainer1_query + ' li:nth-child(2) a');
36 this.click(multicontainer1_query + ' li:nth-child(2) a');
37 });
37 });
38
38
39 this.wait_for_idle();
39 this.wait_for_idle();
40
40
41 index = this.append_cell(
41 index = this.append_cell(
42 'print(multicontainer.selected_index)\n' +
42 'print(multicontainer.selected_index)\n' +
43 'multicontainer.selected_index = 2'); // 0 based
43 'multicontainer.selected_index = 2'); // 0 based
44 this.execute_cell_then(index, function(index){
44 this.execute_cell_then(index, function(index){
45 this.test.assertEquals(this.get_output_cell(index).text, '1\n', // 0 based
45 this.test.assertEquals(this.get_output_cell(index).text, '1\n', // 0 based
46 'selected_index property updated with tab change.');
46 'selected_index property updated with tab change.');
47
47
48 // JQuery selector is 1 based
48 // JQuery selector is 1 based
49 this.test.assert(!this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(1)', 'hasClass', ['active']),
49 this.test.assert(!this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(1)', 'hasClass', ['active']),
50 "Tab 1 is not selected.");
50 "Tab 1 is not selected.");
51 this.test.assert(!this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(2)', 'hasClass', ['active']),
51 this.test.assert(!this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(2)', 'hasClass', ['active']),
52 "Tab 2 is not selected.");
52 "Tab 2 is not selected.");
53 this.test.assert(this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(3)', 'hasClass', ['active']),
53 this.test.assert(this.cell_element_function(multicontainer1_index, multicontainer1_query + ' li:nth-child(3)', 'hasClass', ['active']),
54 "Tab 3 is selected.");
54 "Tab 3 is selected.");
55 });
55 });
56
56
57 index = this.append_cell('multicontainer.set_title(1, "hello")\nprint("Success")'); // 0 based
57 index = this.append_cell('multicontainer.set_title(1, "hello")\nprint("Success")'); // 0 based
58 this.execute_cell_then(index, function(index){
58 this.execute_cell_then(index, function(index){
59 this.test.assert(this.cell_element_function(multicontainer1_index, multicontainer1_query +
59 this.test.assert(this.cell_element_function(multicontainer1_index, multicontainer1_query +
60 ' li:nth-child(2) a', 'html') == 'hello',
60 ' li:nth-child(2) a', 'html') == 'hello',
61 'Tab page title set (after display).');
61 'Tab page title set (after display).');
62 });
62 });
63
63
64 // Test accordion view
64 // Test accordion view
65 var multicontainer2_query = '.widget-area .widget-subarea .accordion';
65 var multicontainer2_query = '.widget-area .widget-subarea .accordion';
66 var multicontainer2_index = this.append_cell(
66 var multicontainer2_index = this.append_cell(
67 'multicontainer = widgets.AccordionWidget()\n' +
67 'multicontainer = widgets.AccordionWidget()\n' +
68 'page1 = widgets.TextWidget()\n' +
68 'page1 = widgets.TextWidget()\n' +
69 'page2 = widgets.TextWidget()\n' +
69 'page2 = widgets.TextWidget()\n' +
70 'page3 = widgets.TextWidget()\n' +
70 'page3 = widgets.TextWidget()\n' +
71 'multicontainer.children = [page1, page2, page3]\n' +
71 'multicontainer.children = [page1, page2, page3]\n' +
72 'multicontainer.set_title(2, "good")\n' +
72 'multicontainer.set_title(2, "good")\n' +
73 'display(multicontainer)\n' +
73 'display(multicontainer)\n' +
74 'multicontainer.selected_index = 0\n' +
74 'multicontainer.selected_index = 0\n' +
75 'print("Success")\n');
75 'print("Success")\n');
76 this.execute_cell_then(multicontainer2_index, function(index){
76 this.execute_cell_then(multicontainer2_index, function(index){
77
77
78 this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
78 this.test.assertEquals(this.get_output_cell(index).text, 'Success\n',
79 'Create multicontainer cell executed with correct output. (2)');
79 'Create multicontainer cell executed with correct output. (2)');
80
80
81 this.test.assert(this.cell_element_exists(index,
81 this.test.assert(this.cell_element_exists(index,
82 '.widget-area .widget-subarea'),
82 '.widget-area .widget-subarea'),
83 'Widget subarea exists.');
83 'Widget subarea exists.');
84
84
85 this.test.assert(this.cell_element_exists(index, multicontainer2_query),
85 this.test.assert(this.cell_element_exists(index, multicontainer2_query),
86 'Widget accordion exists.');
86 'Widget accordion exists.');
87
87
88 this.test.assert(this.cell_element_exists(index, multicontainer2_query +
88 this.test.assert(this.cell_element_exists(index, multicontainer2_query +
89 ' .accordion-group:nth-child(1) .accordion-body'),
89 ' .accordion-group:nth-child(1) .accordion-body'),
90 'First accordion page exists.');
90 'First accordion page exists.');
91
91
92 // JQuery selector is 1 based
92 // JQuery selector is 1 based
93 this.test.assert(this.cell_element_function(index, multicontainer2_query +
93 this.test.assert(this.cell_element_function(index, multicontainer2_query +
94 ' .accordion-group:nth-child(3) .accordion-heading .accordion-toggle',
94 ' .accordion-group:nth-child(3) .accordion-heading .accordion-toggle',
95 'html')=='good', 'Accordion page title set (before display).');
95 'html')=='good', 'Accordion page title set (before display).');
96
96
97 // JQuery selector is 1 based
97 // JQuery selector is 1 based
98 this.click(multicontainer2_query + ' .accordion-group:nth-child(2) .accordion-heading .accordion-toggle');
98 this.click(multicontainer2_query + ' .accordion-group:nth-child(2) .accordion-heading .accordion-toggle');
99 });
99 });
100
100
101 this.wait_for_idle();
101 this.wait_for_idle();
102
102
103 index = this.append_cell('print(multicontainer.selected_index)'); // 0 based
103 index = this.append_cell('print(multicontainer.selected_index)'); // 0 based
104 this.execute_cell_then(index, function(index){
104 this.execute_cell_then(index, function(index){
105 this.test.assertEquals(this.get_output_cell(index).text, '1\n', // 0 based
105 this.test.assertEquals(this.get_output_cell(index).text, '1\n', // 0 based
106 'selected_index property updated with tab change.');
106 'selected_index property updated with tab change.');
107
108 var is_collapsed = this.evaluate(function(s){
109 return $(s + ' div.accordion-group:nth-child(2) a').hasClass('collapsed'); // 1 based
110 }, {s: multicontainer2_query});
111 this.test.assertEquals(is_collapsed, false, 'Was tab actually opened?');
107 });
112 });
108 }); No newline at end of file
113 });
@@ -1,583 +1,583 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
4 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
5 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
6 control to IPython.
6 control to IPython.
7
7
8
8
9 Provided classes
9 Provided classes
10 ----------------
10 ----------------
11
11
12 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
13
13
14 - Demo: pure python demos
14 - Demo: pure python demos
15
15
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
18 may have added via input prefilters).
18 may have added via input prefilters).
19
19
20 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
21 one line at a time, and require no markup.
21 one line at a time, and require no markup.
22
22
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
25
25
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
28 block (see Subclassing below).
28 block (see Subclassing below).
29
29
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 classes.
31 classes.
32
32
33 Inheritance diagram:
33 Inheritance diagram:
34
34
35 .. inheritance-diagram:: IPython.lib.demo
35 .. inheritance-diagram:: IPython.lib.demo
36 :parts: 3
36 :parts: 3
37
37
38 Subclassing
38 Subclassing
39 -----------
39 -----------
40
40
41 The classes here all include a few methods meant to make customization by
41 The classes here all include a few methods meant to make customization by
42 subclassing more convenient. Their docstrings below have some more details:
42 subclassing more convenient. Their docstrings below have some more details:
43
43
44 - marquee(): generates a marquee to provide visible on-screen markers at each
44 - marquee(): generates a marquee to provide visible on-screen markers at each
45 block start and end.
45 block start and end.
46
46
47 - pre_cmd(): run right before the execution of each block.
47 - pre_cmd(): run right before the execution of each block.
48
48
49 - post_cmd(): run right after the execution of each block. If the block
49 - post_cmd(): run right after the execution of each block. If the block
50 raises an exception, this is NOT called.
50 raises an exception, this is NOT called.
51
51
52
52
53 Operation
53 Operation
54 ---------
54 ---------
55
55
56 The file is run in its own empty namespace (though you can pass it a string of
56 The file is run in its own empty namespace (though you can pass it a string of
57 arguments as if in a command line environment, and it will see those as
57 arguments as if in a command line environment, and it will see those as
58 sys.argv). But at each stop, the global IPython namespace is updated with the
58 sys.argv). But at each stop, the global IPython namespace is updated with the
59 current internal demo namespace, so you can work interactively with the data
59 current internal demo namespace, so you can work interactively with the data
60 accumulated so far.
60 accumulated so far.
61
61
62 By default, each block of code is printed (with syntax highlighting) before
62 By default, each block of code is printed (with syntax highlighting) before
63 executing it and you have to confirm execution. This is intended to show the
63 executing it and you have to confirm execution. This is intended to show the
64 code to an audience first so you can discuss it, and only proceed with
64 code to an audience first so you can discuss it, and only proceed with
65 execution once you agree. There are a few tags which allow you to modify this
65 execution once you agree. There are a few tags which allow you to modify this
66 behavior.
66 behavior.
67
67
68 The supported tags are:
68 The supported tags are:
69
69
70 # <demo> stop
70 # <demo> stop
71
71
72 Defines block boundaries, the points where IPython stops execution of the
72 Defines block boundaries, the points where IPython stops execution of the
73 file and returns to the interactive prompt.
73 file and returns to the interactive prompt.
74
74
75 You can optionally mark the stop tag with extra dashes before and after the
75 You can optionally mark the stop tag with extra dashes before and after the
76 word 'stop', to help visually distinguish the blocks in a text editor:
76 word 'stop', to help visually distinguish the blocks in a text editor:
77
77
78 # <demo> --- stop ---
78 # <demo> --- stop ---
79
79
80
80
81 # <demo> silent
81 # <demo> silent
82
82
83 Make a block execute silently (and hence automatically). Typically used in
83 Make a block execute silently (and hence automatically). Typically used in
84 cases where you have some boilerplate or initialization code which you need
84 cases where you have some boilerplate or initialization code which you need
85 executed but do not want to be seen in the demo.
85 executed but do not want to be seen in the demo.
86
86
87 # <demo> auto
87 # <demo> auto
88
88
89 Make a block execute automatically, but still being printed. Useful for
89 Make a block execute automatically, but still being printed. Useful for
90 simple code which does not warrant discussion, since it avoids the extra
90 simple code which does not warrant discussion, since it avoids the extra
91 manual confirmation.
91 manual confirmation.
92
92
93 # <demo> auto_all
93 # <demo> auto_all
94
94
95 This tag can _only_ be in the first block, and if given it overrides the
95 This tag can _only_ be in the first block, and if given it overrides the
96 individual auto tags to make the whole demo fully automatic (no block asks
96 individual auto tags to make the whole demo fully automatic (no block asks
97 for confirmation). It can also be given at creation time (or the attribute
97 for confirmation). It can also be given at creation time (or the attribute
98 set later) to override what's in the file.
98 set later) to override what's in the file.
99
99
100 While _any_ python file can be run as a Demo instance, if there are no stop
100 While _any_ python file can be run as a Demo instance, if there are no stop
101 tags the whole file will run in a single block (no different that calling
101 tags the whole file will run in a single block (no different that calling
102 first %pycat and then %run). The minimal markup to make this useful is to
102 first %pycat and then %run). The minimal markup to make this useful is to
103 place a set of stop tags; the other tags are only there to let you fine-tune
103 place a set of stop tags; the other tags are only there to let you fine-tune
104 the execution.
104 the execution.
105
105
106 This is probably best explained with the simple example file below. You can
106 This is probably best explained with the simple example file below. You can
107 copy this into a file named ex_demo.py, and try running it via::
107 copy this into a file named ex_demo.py, and try running it via::
108
108
109 from IPython.demo import Demo
109 from IPython.demo import Demo
110 d = Demo('ex_demo.py')
110 d = Demo('ex_demo.py')
111 d()
111 d()
112
112
113 Each time you call the demo object, it runs the next block. The demo object
113 Each time you call the demo object, it runs the next block. The demo object
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
115 and back(). It can be reset for a new run via reset() or reloaded from disk
115 and back(). It can be reset for a new run via reset() or reloaded from disk
116 (in case you've edited the source) via reload(). See their docstrings below.
116 (in case you've edited the source) via reload(). See their docstrings below.
117
117
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
119 been added to the "docs/examples/core" directory. Just cd to this directory in
119 been added to the "docs/examples/core" directory. Just cd to this directory in
120 an IPython session, and type::
120 an IPython session, and type::
121
121
122 %run demo-exercizer.py
122 %run demo-exercizer.py
123
123
124 and then follow the directions.
124 and then follow the directions.
125
125
126 Example
126 Example
127 -------
127 -------
128
128
129 The following is a very simple example of a valid demo file.
129 The following is a very simple example of a valid demo file.
130
130
131 ::
131 ::
132
132
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
135
135
136 print 'Hello, welcome to an interactive IPython demo.'
136 print 'Hello, welcome to an interactive IPython demo.'
137
137
138 # The mark below defines a block boundary, which is a point where IPython will
138 # The mark below defines a block boundary, which is a point where IPython will
139 # stop execution and return to the interactive prompt. The dashes are actually
139 # stop execution and return to the interactive prompt. The dashes are actually
140 # optional and used only as a visual aid to clearly separate blocks while
140 # optional and used only as a visual aid to clearly separate blocks while
141 # editing the demo code.
141 # editing the demo code.
142 # <demo> stop
142 # <demo> stop
143
143
144 x = 1
144 x = 1
145 y = 2
145 y = 2
146
146
147 # <demo> stop
147 # <demo> stop
148
148
149 # the mark below makes this block as silent
149 # the mark below makes this block as silent
150 # <demo> silent
150 # <demo> silent
151
151
152 print 'This is a silent block, which gets executed but not printed.'
152 print 'This is a silent block, which gets executed but not printed.'
153
153
154 # <demo> stop
154 # <demo> stop
155 # <demo> auto
155 # <demo> auto
156 print 'This is an automatic block.'
156 print 'This is an automatic block.'
157 print 'It is executed without asking for confirmation, but printed.'
157 print 'It is executed without asking for confirmation, but printed.'
158 z = x+y
158 z = x+y
159
159
160 print 'z=',x
160 print 'z=',x
161
161
162 # <demo> stop
162 # <demo> stop
163 # This is just another normal block.
163 # This is just another normal block.
164 print 'z is now:', z
164 print 'z is now:', z
165
165
166 print 'bye!'
166 print 'bye!'
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
168 """
168 """
169
169
170 from __future__ import unicode_literals
170 from __future__ import unicode_literals
171
171
172 #*****************************************************************************
172 #*****************************************************************************
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
174 #
174 #
175 # Distributed under the terms of the BSD License. The full license is in
175 # Distributed under the terms of the BSD License. The full license is in
176 # the file COPYING, distributed as part of this software.
176 # the file COPYING, distributed as part of this software.
177 #
177 #
178 #*****************************************************************************
178 #*****************************************************************************
179 from __future__ import print_function
179 from __future__ import print_function
180
180
181 import os
181 import os
182 import re
182 import re
183 import shlex
183 import shlex
184 import sys
184 import sys
185
185
186 from IPython.utils import io
186 from IPython.utils import io
187 from IPython.utils.text import marquee
187 from IPython.utils.text import marquee
188 from IPython.utils import openpy
188 from IPython.utils import openpy
189 from IPython.utils import py3compat
189 from IPython.utils import py3compat
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
191
191
192 class DemoError(Exception): pass
192 class DemoError(Exception): pass
193
193
194 def re_mark(mark):
194 def re_mark(mark):
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
196
196
197 class Demo(object):
197 class Demo(object):
198
198
199 re_stop = re_mark('-*\s?stop\s?-*')
199 re_stop = re_mark('-*\s?stop\s?-*')
200 re_silent = re_mark('silent')
200 re_silent = re_mark('silent')
201 re_auto = re_mark('auto')
201 re_auto = re_mark('auto')
202 re_auto_all = re_mark('auto_all')
202 re_auto_all = re_mark('auto_all')
203
203
204 def __init__(self,src,title='',arg_str='',auto_all=None):
204 def __init__(self,src,title='',arg_str='',auto_all=None):
205 """Make a new demo object. To run the demo, simply call the object.
205 """Make a new demo object. To run the demo, simply call the object.
206
206
207 See the module docstring for full details and an example (you can use
207 See the module docstring for full details and an example (you can use
208 IPython.Demo? in IPython to see it).
208 IPython.Demo? in IPython to see it).
209
209
210 Inputs:
210 Inputs:
211
211
212 - src is either a file, or file-like object, or a
212 - src is either a file, or file-like object, or a
213 string that can be resolved to a filename.
213 string that can be resolved to a filename.
214
214
215 Optional inputs:
215 Optional inputs:
216
216
217 - title: a string to use as the demo name. Of most use when the demo
217 - title: a string to use as the demo name. Of most use when the demo
218 you are making comes from an object that has no filename, or if you
218 you are making comes from an object that has no filename, or if you
219 want an alternate denotation distinct from the filename.
219 want an alternate denotation distinct from the filename.
220
220
221 - arg_str(''): a string of arguments, internally converted to a list
221 - arg_str(''): a string of arguments, internally converted to a list
222 just like sys.argv, so the demo script can see a similar
222 just like sys.argv, so the demo script can see a similar
223 environment.
223 environment.
224
224
225 - auto_all(None): global flag to run all blocks automatically without
225 - auto_all(None): global flag to run all blocks automatically without
226 confirmation. This attribute overrides the block-level tags and
226 confirmation. This attribute overrides the block-level tags and
227 applies to the whole demo. It is an attribute of the object, and
227 applies to the whole demo. It is an attribute of the object, and
228 can be changed at runtime simply by reassigning it to a boolean
228 can be changed at runtime simply by reassigning it to a boolean
229 value.
229 value.
230 """
230 """
231 if hasattr(src, "read"):
231 if hasattr(src, "read"):
232 # It seems to be a file or a file-like object
232 # It seems to be a file or a file-like object
233 self.fname = "from a file-like object"
233 self.fname = "from a file-like object"
234 if title == '':
234 if title == '':
235 self.title = "from a file-like object"
235 self.title = "from a file-like object"
236 else:
236 else:
237 self.title = title
237 self.title = title
238 else:
238 else:
239 # Assume it's a string or something that can be converted to one
239 # Assume it's a string or something that can be converted to one
240 self.fname = src
240 self.fname = src
241 if title == '':
241 if title == '':
242 (filepath, filename) = os.path.split(src)
242 (filepath, filename) = os.path.split(src)
243 self.title = filename
243 self.title = filename
244 else:
244 else:
245 self.title = title
245 self.title = title
246 self.sys_argv = [src] + shlex.split(arg_str)
246 self.sys_argv = [src] + shlex.split(arg_str)
247 self.auto_all = auto_all
247 self.auto_all = auto_all
248 self.src = src
248 self.src = src
249
249
250 # get a few things from ipython. While it's a bit ugly design-wise,
250 # get a few things from ipython. While it's a bit ugly design-wise,
251 # it ensures that things like color scheme and the like are always in
251 # it ensures that things like color scheme and the like are always in
252 # sync with the ipython mode being used. This class is only meant to
252 # sync with the ipython mode being used. This class is only meant to
253 # be used inside ipython anyways, so it's OK.
253 # be used inside ipython anyways, so it's OK.
254 ip = get_ipython() # this is in builtins whenever IPython is running
254 ip = get_ipython() # this is in builtins whenever IPython is running
255 self.ip_ns = ip.user_ns
255 self.ip_ns = ip.user_ns
256 self.ip_colorize = ip.pycolorize
256 self.ip_colorize = ip.pycolorize
257 self.ip_showtb = ip.showtraceback
257 self.ip_showtb = ip.showtraceback
258 self.ip_run_cell = ip.run_cell
258 self.ip_run_cell = ip.run_cell
259 self.shell = ip
259 self.shell = ip
260
260
261 # load user data and initialize data structures
261 # load user data and initialize data structures
262 self.reload()
262 self.reload()
263
263
264 def fload(self):
264 def fload(self):
265 """Load file object."""
265 """Load file object."""
266 # read data and parse into blocks
266 # read data and parse into blocks
267 if hasattr(self, 'fobj') and self.fobj is not None:
267 if hasattr(self, 'fobj') and self.fobj is not None:
268 self.fobj.close()
268 self.fobj.close()
269 if hasattr(self.src, "read"):
269 if hasattr(self.src, "read"):
270 # It seems to be a file or a file-like object
270 # It seems to be a file or a file-like object
271 self.fobj = self.src
271 self.fobj = self.src
272 else:
272 else:
273 # Assume it's a string or something that can be converted to one
273 # Assume it's a string or something that can be converted to one
274 self.fobj = openpy.open(self.fname)
274 self.fobj = openpy.open(self.fname)
275
275
276 def reload(self):
276 def reload(self):
277 """Reload source from disk and initialize state."""
277 """Reload source from disk and initialize state."""
278 self.fload()
278 self.fload()
279
279
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
284
284
285 # if auto_all is not given (def. None), we read it from the file
285 # if auto_all is not given (def. None), we read it from the file
286 if self.auto_all is None:
286 if self.auto_all is None:
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
288 else:
288 else:
289 self.auto_all = bool(self.auto_all)
289 self.auto_all = bool(self.auto_all)
290
290
291 # Clean the sources from all markup so it doesn't get displayed when
291 # Clean the sources from all markup so it doesn't get displayed when
292 # running the demo
292 # running the demo
293 src_blocks = []
293 src_blocks = []
294 auto_strip = lambda s: self.re_auto.sub('',s)
294 auto_strip = lambda s: self.re_auto.sub('',s)
295 for i,b in enumerate(src_b):
295 for i,b in enumerate(src_b):
296 if self._auto[i]:
296 if self._auto[i]:
297 src_blocks.append(auto_strip(b))
297 src_blocks.append(auto_strip(b))
298 else:
298 else:
299 src_blocks.append(b)
299 src_blocks.append(b)
300 # remove the auto_all marker
300 # remove the auto_all marker
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
302
302
303 self.nblocks = len(src_blocks)
303 self.nblocks = len(src_blocks)
304 self.src_blocks = src_blocks
304 self.src_blocks = src_blocks
305
305
306 # also build syntax-highlighted source
306 # also build syntax-highlighted source
307 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
307 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
308
308
309 # ensure clean namespace and seek offset
309 # ensure clean namespace and seek offset
310 self.reset()
310 self.reset()
311
311
312 def reset(self):
312 def reset(self):
313 """Reset the namespace and seek pointer to restart the demo"""
313 """Reset the namespace and seek pointer to restart the demo"""
314 self.user_ns = {}
314 self.user_ns = {}
315 self.finished = False
315 self.finished = False
316 self.block_index = 0
316 self.block_index = 0
317
317
318 def _validate_index(self,index):
318 def _validate_index(self,index):
319 if index<0 or index>=self.nblocks:
319 if index<0 or index>=self.nblocks:
320 raise ValueError('invalid block index %s' % index)
320 raise ValueError('invalid block index %s' % index)
321
321
322 def _get_index(self,index):
322 def _get_index(self,index):
323 """Get the current block index, validating and checking status.
323 """Get the current block index, validating and checking status.
324
324
325 Returns None if the demo is finished"""
325 Returns None if the demo is finished"""
326
326
327 if index is None:
327 if index is None:
328 if self.finished:
328 if self.finished:
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.', file=io.stdout)
330 return None
330 return None
331 index = self.block_index
331 index = self.block_index
332 else:
332 else:
333 self._validate_index(index)
333 self._validate_index(index)
334 return index
334 return index
335
335
336 def seek(self,index):
336 def seek(self,index):
337 """Move the current seek pointer to the given block.
337 """Move the current seek pointer to the given block.
338
338
339 You can use negative indices to seek from the end, with identical
339 You can use negative indices to seek from the end, with identical
340 semantics to those of Python lists."""
340 semantics to those of Python lists."""
341 if index<0:
341 if index<0:
342 index = self.nblocks + index
342 index = self.nblocks + index
343 self._validate_index(index)
343 self._validate_index(index)
344 self.block_index = index
344 self.block_index = index
345 self.finished = False
345 self.finished = False
346
346
347 def back(self,num=1):
347 def back(self,num=1):
348 """Move the seek pointer back num blocks (default is 1)."""
348 """Move the seek pointer back num blocks (default is 1)."""
349 self.seek(self.block_index-num)
349 self.seek(self.block_index-num)
350
350
351 def jump(self,num=1):
351 def jump(self,num=1):
352 """Jump a given number of blocks relative to the current one.
352 """Jump a given number of blocks relative to the current one.
353
353
354 The offset can be positive or negative, defaults to 1."""
354 The offset can be positive or negative, defaults to 1."""
355 self.seek(self.block_index+num)
355 self.seek(self.block_index+num)
356
356
357 def again(self):
357 def again(self):
358 """Move the seek pointer back one block and re-execute."""
358 """Move the seek pointer back one block and re-execute."""
359 self.back(1)
359 self.back(1)
360 self()
360 self()
361
361
362 def edit(self,index=None):
362 def edit(self,index=None):
363 """Edit a block.
363 """Edit a block.
364
364
365 If no number is given, use the last block executed.
365 If no number is given, use the last block executed.
366
366
367 This edits the in-memory copy of the demo, it does NOT modify the
367 This edits the in-memory copy of the demo, it does NOT modify the
368 original source file. If you want to do that, simply open the file in
368 original source file. If you want to do that, simply open the file in
369 an editor and use reload() when you make changes to the file. This
369 an editor and use reload() when you make changes to the file. This
370 method is meant to let you change a block during a demonstration for
370 method is meant to let you change a block during a demonstration for
371 explanatory purposes, without damaging your original script."""
371 explanatory purposes, without damaging your original script."""
372
372
373 index = self._get_index(index)
373 index = self._get_index(index)
374 if index is None:
374 if index is None:
375 return
375 return
376 # decrease the index by one (unless we're at the very beginning), so
376 # decrease the index by one (unless we're at the very beginning), so
377 # that the default demo.edit() call opens up the sblock we've last run
377 # that the default demo.edit() call opens up the sblock we've last run
378 if index>0:
378 if index>0:
379 index -= 1
379 index -= 1
380
380
381 filename = self.shell.mktempfile(self.src_blocks[index])
381 filename = self.shell.mktempfile(self.src_blocks[index])
382 self.shell.hooks.editor(filename,1)
382 self.shell.hooks.editor(filename,1)
383 with open(filename, 'r') as f:
383 with open(filename, 'r') as f:
384 new_block = f.read()
384 new_block = f.read()
385 # update the source and colored block
385 # update the source and colored block
386 self.src_blocks[index] = new_block
386 self.src_blocks[index] = new_block
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
388 self.block_index = index
388 self.block_index = index
389 # call to run with the newly edited index
389 # call to run with the newly edited index
390 self()
390 self()
391
391
392 def show(self,index=None):
392 def show(self,index=None):
393 """Show a single block on screen"""
393 """Show a single block on screen"""
394
394
395 index = self._get_index(index)
395 index = self._get_index(index)
396 if index is None:
396 if index is None:
397 return
397 return
398
398
399 print(self.marquee('<%s> block # %s (%s remaining)' %
399 print(self.marquee('<%s> block # %s (%s remaining)' %
400 (self.title,index,self.nblocks-index-1)), file=io.stdout)
400 (self.title,index,self.nblocks-index-1)), file=io.stdout)
401 print(self.src_blocks_colored[index], file=io.stdout)
401 print(self.src_blocks_colored[index], file=io.stdout)
402 sys.stdout.flush()
402 sys.stdout.flush()
403
403
404 def show_all(self):
404 def show_all(self):
405 """Show entire demo on screen, block by block"""
405 """Show entire demo on screen, block by block"""
406
406
407 fname = self.title
407 fname = self.title
408 title = self.title
408 title = self.title
409 nblocks = self.nblocks
409 nblocks = self.nblocks
410 silent = self._silent
410 silent = self._silent
411 marquee = self.marquee
411 marquee = self.marquee
412 for index,block in enumerate(self.src_blocks_colored):
412 for index,block in enumerate(self.src_blocks_colored):
413 if silent[index]:
413 if silent[index]:
414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
415 (title,index,nblocks-index-1)), file=io.stdout)
415 (title,index,nblocks-index-1)), file=io.stdout)
416 else:
416 else:
417 print(marquee('<%s> block # %s (%s remaining)' %
417 print(marquee('<%s> block # %s (%s remaining)' %
418 (title,index,nblocks-index-1)), file=io.stdout)
418 (title,index,nblocks-index-1)), file=io.stdout)
419 print(block, end=' ', file=io.stdout)
419 print(block, end=' ', file=io.stdout)
420 sys.stdout.flush()
420 sys.stdout.flush()
421
421
422 def run_cell(self,source):
422 def run_cell(self,source):
423 """Execute a string with one or more lines of code"""
423 """Execute a string with one or more lines of code"""
424
424
425 exec(source, self.user_ns)
425 exec(source, self.user_ns)
426
426
427 def __call__(self,index=None):
427 def __call__(self,index=None):
428 """run a block of the demo.
428 """run a block of the demo.
429
429
430 If index is given, it should be an integer >=1 and <= nblocks. This
430 If index is given, it should be an integer >=1 and <= nblocks. This
431 means that the calling convention is one off from typical Python
431 means that the calling convention is one off from typical Python
432 lists. The reason for the inconsistency is that the demo always
432 lists. The reason for the inconsistency is that the demo always
433 prints 'Block n/N, and N is the total, so it would be very odd to use
433 prints 'Block n/N, and N is the total, so it would be very odd to use
434 zero-indexing here."""
434 zero-indexing here."""
435
435
436 index = self._get_index(index)
436 index = self._get_index(index)
437 if index is None:
437 if index is None:
438 return
438 return
439 try:
439 try:
440 marquee = self.marquee
440 marquee = self.marquee
441 next_block = self.src_blocks[index]
441 next_block = self.src_blocks[index]
442 self.block_index += 1
442 self.block_index += 1
443 if self._silent[index]:
443 if self._silent[index]:
444 print(marquee('Executing silent block # %s (%s remaining)' %
444 print(marquee('Executing silent block # %s (%s remaining)' %
445 (index,self.nblocks-index-1)), file=io.stdout)
445 (index,self.nblocks-index-1)), file=io.stdout)
446 else:
446 else:
447 self.pre_cmd()
447 self.pre_cmd()
448 self.show(index)
448 self.show(index)
449 if self.auto_all or self._auto[index]:
449 if self.auto_all or self._auto[index]:
450 print(marquee('output:'), file=io.stdout)
450 print(marquee('output:'), file=io.stdout)
451 else:
451 else:
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ', file=io.stdout)
453 ans = py3compat.input().strip()
453 ans = py3compat.input().strip()
454 if ans:
454 if ans:
455 print(marquee('Block NOT executed'), file=io.stdout)
455 print(marquee('Block NOT executed'), file=io.stdout)
456 return
456 return
457 try:
457 try:
458 save_argv = sys.argv
458 save_argv = sys.argv
459 sys.argv = self.sys_argv
459 sys.argv = self.sys_argv
460 self.run_cell(next_block)
460 self.run_cell(next_block)
461 self.post_cmd()
461 self.post_cmd()
462 finally:
462 finally:
463 sys.argv = save_argv
463 sys.argv = save_argv
464
464
465 except:
465 except:
466 self.ip_showtb(filename=self.fname)
466 self.ip_showtb(filename=self.fname)
467 else:
467 else:
468 self.ip_ns.update(self.user_ns)
468 self.ip_ns.update(self.user_ns)
469
469
470 if self.block_index == self.nblocks:
470 if self.block_index == self.nblocks:
471 mq1 = self.marquee('END OF DEMO')
471 mq1 = self.marquee('END OF DEMO')
472 if mq1:
472 if mq1:
473 # avoid spurious print >>io.stdout,s if empty marquees are used
473 # avoid spurious print >>io.stdout,s if empty marquees are used
474 print(file=io.stdout)
474 print(file=io.stdout)
475 print(mq1, file=io.stdout)
475 print(mq1, file=io.stdout)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'), file=io.stdout)
477 self.finished = True
477 self.finished = True
478
478
479 # These methods are meant to be overridden by subclasses who may wish to
479 # These methods are meant to be overridden by subclasses who may wish to
480 # customize the behavior of of their demos.
480 # customize the behavior of of their demos.
481 def marquee(self,txt='',width=78,mark='*'):
481 def marquee(self,txt='',width=78,mark='*'):
482 """Return the input string centered in a 'marquee'."""
482 """Return the input string centered in a 'marquee'."""
483 return marquee(txt,width,mark)
483 return marquee(txt,width,mark)
484
484
485 def pre_cmd(self):
485 def pre_cmd(self):
486 """Method called before executing each block."""
486 """Method called before executing each block."""
487 pass
487 pass
488
488
489 def post_cmd(self):
489 def post_cmd(self):
490 """Method called after executing each block."""
490 """Method called after executing each block."""
491 pass
491 pass
492
492
493
493
494 class IPythonDemo(Demo):
494 class IPythonDemo(Demo):
495 """Class for interactive demos with IPython's input processing applied.
495 """Class for interactive demos with IPython's input processing applied.
496
496
497 This subclasses Demo, but instead of executing each block by the Python
497 This subclasses Demo, but instead of executing each block by the Python
498 interpreter (via exec), it actually calls IPython on it, so that any input
498 interpreter (via exec), it actually calls IPython on it, so that any input
499 filters which may be in place are applied to the input block.
499 filters which may be in place are applied to the input block.
500
500
501 If you have an interactive environment which exposes special input
501 If you have an interactive environment which exposes special input
502 processing, you can use this class instead to write demo scripts which
502 processing, you can use this class instead to write demo scripts which
503 operate exactly as if you had typed them interactively. The default Demo
503 operate exactly as if you had typed them interactively. The default Demo
504 class requires the input to be valid, pure Python code.
504 class requires the input to be valid, pure Python code.
505 """
505 """
506
506
507 def run_cell(self,source):
507 def run_cell(self,source):
508 """Execute a string with one or more lines of code"""
508 """Execute a string with one or more lines of code"""
509
509
510 self.shell.run_cell(source)
510 self.shell.run_cell(source)
511
511
512 class LineDemo(Demo):
512 class LineDemo(Demo):
513 """Demo where each line is executed as a separate block.
513 """Demo where each line is executed as a separate block.
514
514
515 The input script should be valid Python code.
515 The input script should be valid Python code.
516
516
517 This class doesn't require any markup at all, and it's meant for simple
517 This class doesn't require any markup at all, and it's meant for simple
518 scripts (with no nesting or any kind of indentation) which consist of
518 scripts (with no nesting or any kind of indentation) which consist of
519 multiple lines of input to be executed, one at a time, as if they had been
519 multiple lines of input to be executed, one at a time, as if they had been
520 typed in the interactive prompt.
520 typed in the interactive prompt.
521
521
522 Note: the input can not have *any* indentation, which means that only
522 Note: the input can not have *any* indentation, which means that only
523 single-lines of input are accepted, not even function definitions are
523 single-lines of input are accepted, not even function definitions are
524 valid."""
524 valid."""
525
525
526 def reload(self):
526 def reload(self):
527 """Reload source from disk and initialize state."""
527 """Reload source from disk and initialize state."""
528 # read data and parse into blocks
528 # read data and parse into blocks
529 self.fload()
529 self.fload()
530 lines = self.fobj.readlines()
530 lines = self.fobj.readlines()
531 src_b = [l for l in lines if l.strip()]
531 src_b = [l for l in lines if l.strip()]
532 nblocks = len(src_b)
532 nblocks = len(src_b)
533 self.src = ''.join(lines)
533 self.src = ''.join(lines)
534 self._silent = [False]*nblocks
534 self._silent = [False]*nblocks
535 self._auto = [True]*nblocks
535 self._auto = [True]*nblocks
536 self.auto_all = True
536 self.auto_all = True
537 self.nblocks = nblocks
537 self.nblocks = nblocks
538 self.src_blocks = src_b
538 self.src_blocks = src_b
539
539
540 # also build syntax-highlighted source
540 # also build syntax-highlighted source
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
542
542
543 # ensure clean namespace and seek offset
543 # ensure clean namespace and seek offset
544 self.reset()
544 self.reset()
545
545
546
546
547 class IPythonLineDemo(IPythonDemo,LineDemo):
547 class IPythonLineDemo(IPythonDemo,LineDemo):
548 """Variant of the LineDemo class whose input is processed by IPython."""
548 """Variant of the LineDemo class whose input is processed by IPython."""
549 pass
549 pass
550
550
551
551
552 class ClearMixin(object):
552 class ClearMixin(object):
553 """Use this mixin to make Demo classes with less visual clutter.
553 """Use this mixin to make Demo classes with less visual clutter.
554
554
555 Demos using this mixin will clear the screen before every block and use
555 Demos using this mixin will clear the screen before every block and use
556 blank marquees.
556 blank marquees.
557
557
558 Note that in order for the methods defined here to actually override those
558 Note that in order for the methods defined here to actually override those
559 of the classes it's mixed with, it must go /first/ in the inheritance
559 of the classes it's mixed with, it must go /first/ in the inheritance
560 tree. For example:
560 tree. For example:
561
561
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
563
563
564 will provide an IPythonDemo class with the mixin's features.
564 will provide an IPythonDemo class with the mixin's features.
565 """
565 """
566
566
567 def marquee(self,txt='',width=78,mark='*'):
567 def marquee(self,txt='',width=78,mark='*'):
568 """Blank marquee that returns '' no matter what the input."""
568 """Blank marquee that returns '' no matter what the input."""
569 return ''
569 return ''
570
570
571 def pre_cmd(self):
571 def pre_cmd(self):
572 """Method called before executing each block.
572 """Method called before executing each block.
573
573
574 This one simply clears the screen."""
574 This one simply clears the screen."""
575 from IPython.utils.terminal import term_clear
575 from IPython.utils.terminal import term_clear
576 term_clear()
576 term_clear()
577
577
578 class ClearDemo(ClearMixin,Demo):
578 class ClearDemo(ClearMixin,Demo):
579 pass
579 pass
580
580
581
581
582 class ClearIPDemo(ClearMixin,IPythonDemo):
582 class ClearIPDemo(ClearMixin,IPythonDemo):
583 pass
583 pass
@@ -1,1463 +1,1463 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Facilities for launching IPython processes asynchronously.
3 Facilities for launching IPython processes asynchronously.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * MinRK
8 * MinRK
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import copy
22 import copy
23 import logging
23 import logging
24 import os
24 import os
25 import pipes
25 import pipes
26 import stat
26 import stat
27 import sys
27 import sys
28 import time
28 import time
29
29
30 # signal imports, handling various platforms, versions
30 # signal imports, handling various platforms, versions
31
31
32 from signal import SIGINT, SIGTERM
32 from signal import SIGINT, SIGTERM
33 try:
33 try:
34 from signal import SIGKILL
34 from signal import SIGKILL
35 except ImportError:
35 except ImportError:
36 # Windows
36 # Windows
37 SIGKILL=SIGTERM
37 SIGKILL=SIGTERM
38
38
39 try:
39 try:
40 # Windows >= 2.7, 3.2
40 # Windows >= 2.7, 3.2
41 from signal import CTRL_C_EVENT as SIGINT
41 from signal import CTRL_C_EVENT as SIGINT
42 except ImportError:
42 except ImportError:
43 pass
43 pass
44
44
45 from subprocess import Popen, PIPE, STDOUT
45 from subprocess import Popen, PIPE, STDOUT
46 try:
46 try:
47 from subprocess import check_output
47 from subprocess import check_output
48 except ImportError:
48 except ImportError:
49 # pre-2.7, define check_output with Popen
49 # pre-2.7, define check_output with Popen
50 def check_output(*args, **kwargs):
50 def check_output(*args, **kwargs):
51 kwargs.update(dict(stdout=PIPE))
51 kwargs.update(dict(stdout=PIPE))
52 p = Popen(*args, **kwargs)
52 p = Popen(*args, **kwargs)
53 out,err = p.communicate()
53 out,err = p.communicate()
54 return out
54 return out
55
55
56 from zmq.eventloop import ioloop
56 from zmq.eventloop import ioloop
57
57
58 from IPython.config.application import Application
58 from IPython.config.application import Application
59 from IPython.config.configurable import LoggingConfigurable
59 from IPython.config.configurable import LoggingConfigurable
60 from IPython.utils.text import EvalFormatter
60 from IPython.utils.text import EvalFormatter
61 from IPython.utils.traitlets import (
61 from IPython.utils.traitlets import (
62 Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, CRegExp
62 Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, CRegExp
63 )
63 )
64 from IPython.utils.encoding import DEFAULT_ENCODING
64 from IPython.utils.encoding import DEFAULT_ENCODING
65 from IPython.utils.path import get_home_dir
65 from IPython.utils.path import get_home_dir
66 from IPython.utils.process import find_cmd, FindCmdError
66 from IPython.utils.process import find_cmd, FindCmdError
67 from IPython.utils.py3compat import iteritems, itervalues
67 from IPython.utils.py3compat import iteritems, itervalues
68
68
69 from .win32support import forward_read_events
69 from .win32support import forward_read_events
70
70
71 from .winhpcjob import IPControllerTask, IPEngineTask, IPControllerJob, IPEngineSetJob
71 from .winhpcjob import IPControllerTask, IPEngineTask, IPControllerJob, IPEngineSetJob
72
72
73 WINDOWS = os.name == 'nt'
73 WINDOWS = os.name == 'nt'
74
74
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76 # Paths to the kernel apps
76 # Paths to the kernel apps
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78
78
79 ipcluster_cmd_argv = [sys.executable, "-m", "IPython.parallel.cluster"]
79 ipcluster_cmd_argv = [sys.executable, "-m", "IPython.parallel.cluster"]
80
80
81 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.engine"]
81 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.engine"]
82
82
83 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.controller"]
83 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.controller"]
84
84
85 if WINDOWS and sys.version_info < (3,):
85 if WINDOWS and sys.version_info < (3,):
86 # `python -m package` doesn't work on Windows Python 2,
86 # `python -m package` doesn't work on Windows Python 2,
87 # but `python -m module` does.
87 # but `python -m module` does.
88 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipengineapp"]
88 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipengineapp"]
89 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipcontrollerapp"]
89 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipcontrollerapp"]
90
90
91 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
92 # Base launchers and errors
92 # Base launchers and errors
93 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
94
94
95 class LauncherError(Exception):
95 class LauncherError(Exception):
96 pass
96 pass
97
97
98
98
99 class ProcessStateError(LauncherError):
99 class ProcessStateError(LauncherError):
100 pass
100 pass
101
101
102
102
103 class UnknownStatus(LauncherError):
103 class UnknownStatus(LauncherError):
104 pass
104 pass
105
105
106
106
107 class BaseLauncher(LoggingConfigurable):
107 class BaseLauncher(LoggingConfigurable):
108 """An asbtraction for starting, stopping and signaling a process."""
108 """An asbtraction for starting, stopping and signaling a process."""
109
109
110 # In all of the launchers, the work_dir is where child processes will be
110 # In all of the launchers, the work_dir is where child processes will be
111 # run. This will usually be the profile_dir, but may not be. any work_dir
111 # run. This will usually be the profile_dir, but may not be. any work_dir
112 # passed into the __init__ method will override the config value.
112 # passed into the __init__ method will override the config value.
113 # This should not be used to set the work_dir for the actual engine
113 # This should not be used to set the work_dir for the actual engine
114 # and controller. Instead, use their own config files or the
114 # and controller. Instead, use their own config files or the
115 # controller_args, engine_args attributes of the launchers to add
115 # controller_args, engine_args attributes of the launchers to add
116 # the work_dir option.
116 # the work_dir option.
117 work_dir = Unicode(u'.')
117 work_dir = Unicode(u'.')
118 loop = Instance('zmq.eventloop.ioloop.IOLoop')
118 loop = Instance('zmq.eventloop.ioloop.IOLoop')
119
119
120 start_data = Any()
120 start_data = Any()
121 stop_data = Any()
121 stop_data = Any()
122
122
123 def _loop_default(self):
123 def _loop_default(self):
124 return ioloop.IOLoop.instance()
124 return ioloop.IOLoop.instance()
125
125
126 def __init__(self, work_dir=u'.', config=None, **kwargs):
126 def __init__(self, work_dir=u'.', config=None, **kwargs):
127 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config, **kwargs)
127 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config, **kwargs)
128 self.state = 'before' # can be before, running, after
128 self.state = 'before' # can be before, running, after
129 self.stop_callbacks = []
129 self.stop_callbacks = []
130 self.start_data = None
130 self.start_data = None
131 self.stop_data = None
131 self.stop_data = None
132
132
133 @property
133 @property
134 def args(self):
134 def args(self):
135 """A list of cmd and args that will be used to start the process.
135 """A list of cmd and args that will be used to start the process.
136
136
137 This is what is passed to :func:`spawnProcess` and the first element
137 This is what is passed to :func:`spawnProcess` and the first element
138 will be the process name.
138 will be the process name.
139 """
139 """
140 return self.find_args()
140 return self.find_args()
141
141
142 def find_args(self):
142 def find_args(self):
143 """The ``.args`` property calls this to find the args list.
143 """The ``.args`` property calls this to find the args list.
144
144
145 Subcommand should implement this to construct the cmd and args.
145 Subcommand should implement this to construct the cmd and args.
146 """
146 """
147 raise NotImplementedError('find_args must be implemented in a subclass')
147 raise NotImplementedError('find_args must be implemented in a subclass')
148
148
149 @property
149 @property
150 def arg_str(self):
150 def arg_str(self):
151 """The string form of the program arguments."""
151 """The string form of the program arguments."""
152 return ' '.join(self.args)
152 return ' '.join(self.args)
153
153
154 @property
154 @property
155 def running(self):
155 def running(self):
156 """Am I running."""
156 """Am I running."""
157 if self.state == 'running':
157 if self.state == 'running':
158 return True
158 return True
159 else:
159 else:
160 return False
160 return False
161
161
162 def start(self):
162 def start(self):
163 """Start the process."""
163 """Start the process."""
164 raise NotImplementedError('start must be implemented in a subclass')
164 raise NotImplementedError('start must be implemented in a subclass')
165
165
166 def stop(self):
166 def stop(self):
167 """Stop the process and notify observers of stopping.
167 """Stop the process and notify observers of stopping.
168
168
169 This method will return None immediately.
169 This method will return None immediately.
170 To observe the actual process stopping, see :meth:`on_stop`.
170 To observe the actual process stopping, see :meth:`on_stop`.
171 """
171 """
172 raise NotImplementedError('stop must be implemented in a subclass')
172 raise NotImplementedError('stop must be implemented in a subclass')
173
173
174 def on_stop(self, f):
174 def on_stop(self, f):
175 """Register a callback to be called with this Launcher's stop_data
175 """Register a callback to be called with this Launcher's stop_data
176 when the process actually finishes.
176 when the process actually finishes.
177 """
177 """
178 if self.state=='after':
178 if self.state=='after':
179 return f(self.stop_data)
179 return f(self.stop_data)
180 else:
180 else:
181 self.stop_callbacks.append(f)
181 self.stop_callbacks.append(f)
182
182
183 def notify_start(self, data):
183 def notify_start(self, data):
184 """Call this to trigger startup actions.
184 """Call this to trigger startup actions.
185
185
186 This logs the process startup and sets the state to 'running'. It is
186 This logs the process startup and sets the state to 'running'. It is
187 a pass-through so it can be used as a callback.
187 a pass-through so it can be used as a callback.
188 """
188 """
189
189
190 self.log.debug('Process %r started: %r', self.args[0], data)
190 self.log.debug('Process %r started: %r', self.args[0], data)
191 self.start_data = data
191 self.start_data = data
192 self.state = 'running'
192 self.state = 'running'
193 return data
193 return data
194
194
195 def notify_stop(self, data):
195 def notify_stop(self, data):
196 """Call this to trigger process stop actions.
196 """Call this to trigger process stop actions.
197
197
198 This logs the process stopping and sets the state to 'after'. Call
198 This logs the process stopping and sets the state to 'after'. Call
199 this to trigger callbacks registered via :meth:`on_stop`."""
199 this to trigger callbacks registered via :meth:`on_stop`."""
200
200
201 self.log.debug('Process %r stopped: %r', self.args[0], data)
201 self.log.debug('Process %r stopped: %r', self.args[0], data)
202 self.stop_data = data
202 self.stop_data = data
203 self.state = 'after'
203 self.state = 'after'
204 for i in range(len(self.stop_callbacks)):
204 for i in range(len(self.stop_callbacks)):
205 d = self.stop_callbacks.pop()
205 d = self.stop_callbacks.pop()
206 d(data)
206 d(data)
207 return data
207 return data
208
208
209 def signal(self, sig):
209 def signal(self, sig):
210 """Signal the process.
210 """Signal the process.
211
211
212 Parameters
212 Parameters
213 ----------
213 ----------
214 sig : str or int
214 sig : str or int
215 'KILL', 'INT', etc., or any signal number
215 'KILL', 'INT', etc., or any signal number
216 """
216 """
217 raise NotImplementedError('signal must be implemented in a subclass')
217 raise NotImplementedError('signal must be implemented in a subclass')
218
218
219 class ClusterAppMixin(HasTraits):
219 class ClusterAppMixin(HasTraits):
220 """MixIn for cluster args as traits"""
220 """MixIn for cluster args as traits"""
221 profile_dir=Unicode('')
221 profile_dir=Unicode('')
222 cluster_id=Unicode('')
222 cluster_id=Unicode('')
223
223
224 @property
224 @property
225 def cluster_args(self):
225 def cluster_args(self):
226 return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id]
226 return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id]
227
227
228 class ControllerMixin(ClusterAppMixin):
228 class ControllerMixin(ClusterAppMixin):
229 controller_cmd = List(ipcontroller_cmd_argv, config=True,
229 controller_cmd = List(ipcontroller_cmd_argv, config=True,
230 help="""Popen command to launch ipcontroller.""")
230 help="""Popen command to launch ipcontroller.""")
231 # Command line arguments to ipcontroller.
231 # Command line arguments to ipcontroller.
232 controller_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
232 controller_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
233 help="""command-line args to pass to ipcontroller""")
233 help="""command-line args to pass to ipcontroller""")
234
234
235 class EngineMixin(ClusterAppMixin):
235 class EngineMixin(ClusterAppMixin):
236 engine_cmd = List(ipengine_cmd_argv, config=True,
236 engine_cmd = List(ipengine_cmd_argv, config=True,
237 help="""command to launch the Engine.""")
237 help="""command to launch the Engine.""")
238 # Command line arguments for ipengine.
238 # Command line arguments for ipengine.
239 engine_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
239 engine_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
240 help="command-line arguments to pass to ipengine"
240 help="command-line arguments to pass to ipengine"
241 )
241 )
242
242
243
243
244 #-----------------------------------------------------------------------------
244 #-----------------------------------------------------------------------------
245 # Local process launchers
245 # Local process launchers
246 #-----------------------------------------------------------------------------
246 #-----------------------------------------------------------------------------
247
247
248
248
249 class LocalProcessLauncher(BaseLauncher):
249 class LocalProcessLauncher(BaseLauncher):
250 """Start and stop an external process in an asynchronous manner.
250 """Start and stop an external process in an asynchronous manner.
251
251
252 This will launch the external process with a working directory of
252 This will launch the external process with a working directory of
253 ``self.work_dir``.
253 ``self.work_dir``.
254 """
254 """
255
255
256 # This is used to to construct self.args, which is passed to
256 # This is used to to construct self.args, which is passed to
257 # spawnProcess.
257 # spawnProcess.
258 cmd_and_args = List([])
258 cmd_and_args = List([])
259 poll_frequency = Integer(100) # in ms
259 poll_frequency = Integer(100) # in ms
260
260
261 def __init__(self, work_dir=u'.', config=None, **kwargs):
261 def __init__(self, work_dir=u'.', config=None, **kwargs):
262 super(LocalProcessLauncher, self).__init__(
262 super(LocalProcessLauncher, self).__init__(
263 work_dir=work_dir, config=config, **kwargs
263 work_dir=work_dir, config=config, **kwargs
264 )
264 )
265 self.process = None
265 self.process = None
266 self.poller = None
266 self.poller = None
267
267
268 def find_args(self):
268 def find_args(self):
269 return self.cmd_and_args
269 return self.cmd_and_args
270
270
271 def start(self):
271 def start(self):
272 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
272 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
273 if self.state == 'before':
273 if self.state == 'before':
274 self.process = Popen(self.args,
274 self.process = Popen(self.args,
275 stdout=PIPE,stderr=PIPE,stdin=PIPE,
275 stdout=PIPE,stderr=PIPE,stdin=PIPE,
276 env=os.environ,
276 env=os.environ,
277 cwd=self.work_dir
277 cwd=self.work_dir
278 )
278 )
279 if WINDOWS:
279 if WINDOWS:
280 self.stdout = forward_read_events(self.process.stdout)
280 self.stdout = forward_read_events(self.process.stdout)
281 self.stderr = forward_read_events(self.process.stderr)
281 self.stderr = forward_read_events(self.process.stderr)
282 else:
282 else:
283 self.stdout = self.process.stdout.fileno()
283 self.stdout = self.process.stdout.fileno()
284 self.stderr = self.process.stderr.fileno()
284 self.stderr = self.process.stderr.fileno()
285 self.loop.add_handler(self.stdout, self.handle_stdout, self.loop.READ)
285 self.loop.add_handler(self.stdout, self.handle_stdout, self.loop.READ)
286 self.loop.add_handler(self.stderr, self.handle_stderr, self.loop.READ)
286 self.loop.add_handler(self.stderr, self.handle_stderr, self.loop.READ)
287 self.poller = ioloop.PeriodicCallback(self.poll, self.poll_frequency, self.loop)
287 self.poller = ioloop.PeriodicCallback(self.poll, self.poll_frequency, self.loop)
288 self.poller.start()
288 self.poller.start()
289 self.notify_start(self.process.pid)
289 self.notify_start(self.process.pid)
290 else:
290 else:
291 s = 'The process was already started and has state: %r' % self.state
291 s = 'The process was already started and has state: %r' % self.state
292 raise ProcessStateError(s)
292 raise ProcessStateError(s)
293
293
294 def stop(self):
294 def stop(self):
295 return self.interrupt_then_kill()
295 return self.interrupt_then_kill()
296
296
297 def signal(self, sig):
297 def signal(self, sig):
298 if self.state == 'running':
298 if self.state == 'running':
299 if WINDOWS and sig != SIGINT:
299 if WINDOWS and sig != SIGINT:
300 # use Windows tree-kill for better child cleanup
300 # use Windows tree-kill for better child cleanup
301 check_output(['taskkill', '-pid', str(self.process.pid), '-t', '-f'])
301 check_output(['taskkill', '-pid', str(self.process.pid), '-t', '-f'])
302 else:
302 else:
303 self.process.send_signal(sig)
303 self.process.send_signal(sig)
304
304
305 def interrupt_then_kill(self, delay=2.0):
305 def interrupt_then_kill(self, delay=2.0):
306 """Send INT, wait a delay and then send KILL."""
306 """Send INT, wait a delay and then send KILL."""
307 try:
307 try:
308 self.signal(SIGINT)
308 self.signal(SIGINT)
309 except Exception:
309 except Exception:
310 self.log.debug("interrupt failed")
310 self.log.debug("interrupt failed")
311 pass
311 pass
312 self.killer = ioloop.DelayedCallback(lambda : self.signal(SIGKILL), delay*1000, self.loop)
312 self.killer = ioloop.DelayedCallback(lambda : self.signal(SIGKILL), delay*1000, self.loop)
313 self.killer.start()
313 self.killer.start()
314
314
315 # callbacks, etc:
315 # callbacks, etc:
316
316
317 def handle_stdout(self, fd, events):
317 def handle_stdout(self, fd, events):
318 if WINDOWS:
318 if WINDOWS:
319 line = self.stdout.recv()
319 line = self.stdout.recv()
320 else:
320 else:
321 line = self.process.stdout.readline()
321 line = self.process.stdout.readline()
322 # a stopped process will be readable but return empty strings
322 # a stopped process will be readable but return empty strings
323 if line:
323 if line:
324 self.log.debug(line[:-1])
324 self.log.debug(line[:-1])
325 else:
325 else:
326 self.poll()
326 self.poll()
327
327
328 def handle_stderr(self, fd, events):
328 def handle_stderr(self, fd, events):
329 if WINDOWS:
329 if WINDOWS:
330 line = self.stderr.recv()
330 line = self.stderr.recv()
331 else:
331 else:
332 line = self.process.stderr.readline()
332 line = self.process.stderr.readline()
333 # a stopped process will be readable but return empty strings
333 # a stopped process will be readable but return empty strings
334 if line:
334 if line:
335 self.log.debug(line[:-1])
335 self.log.debug(line[:-1])
336 else:
336 else:
337 self.poll()
337 self.poll()
338
338
339 def poll(self):
339 def poll(self):
340 status = self.process.poll()
340 status = self.process.poll()
341 if status is not None:
341 if status is not None:
342 self.poller.stop()
342 self.poller.stop()
343 self.loop.remove_handler(self.stdout)
343 self.loop.remove_handler(self.stdout)
344 self.loop.remove_handler(self.stderr)
344 self.loop.remove_handler(self.stderr)
345 self.notify_stop(dict(exit_code=status, pid=self.process.pid))
345 self.notify_stop(dict(exit_code=status, pid=self.process.pid))
346 return status
346 return status
347
347
348 class LocalControllerLauncher(LocalProcessLauncher, ControllerMixin):
348 class LocalControllerLauncher(LocalProcessLauncher, ControllerMixin):
349 """Launch a controller as a regular external process."""
349 """Launch a controller as a regular external process."""
350
350
351 def find_args(self):
351 def find_args(self):
352 return self.controller_cmd + self.cluster_args + self.controller_args
352 return self.controller_cmd + self.cluster_args + self.controller_args
353
353
354 def start(self):
354 def start(self):
355 """Start the controller by profile_dir."""
355 """Start the controller by profile_dir."""
356 return super(LocalControllerLauncher, self).start()
356 return super(LocalControllerLauncher, self).start()
357
357
358
358
359 class LocalEngineLauncher(LocalProcessLauncher, EngineMixin):
359 class LocalEngineLauncher(LocalProcessLauncher, EngineMixin):
360 """Launch a single engine as a regular externall process."""
360 """Launch a single engine as a regular externall process."""
361
361
362 def find_args(self):
362 def find_args(self):
363 return self.engine_cmd + self.cluster_args + self.engine_args
363 return self.engine_cmd + self.cluster_args + self.engine_args
364
364
365
365
366 class LocalEngineSetLauncher(LocalEngineLauncher):
366 class LocalEngineSetLauncher(LocalEngineLauncher):
367 """Launch a set of engines as regular external processes."""
367 """Launch a set of engines as regular external processes."""
368
368
369 delay = CFloat(0.1, config=True,
369 delay = CFloat(0.1, config=True,
370 help="""delay (in seconds) between starting each engine after the first.
370 help="""delay (in seconds) between starting each engine after the first.
371 This can help force the engines to get their ids in order, or limit
371 This can help force the engines to get their ids in order, or limit
372 process flood when starting many engines."""
372 process flood when starting many engines."""
373 )
373 )
374
374
375 # launcher class
375 # launcher class
376 launcher_class = LocalEngineLauncher
376 launcher_class = LocalEngineLauncher
377
377
378 launchers = Dict()
378 launchers = Dict()
379 stop_data = Dict()
379 stop_data = Dict()
380
380
381 def __init__(self, work_dir=u'.', config=None, **kwargs):
381 def __init__(self, work_dir=u'.', config=None, **kwargs):
382 super(LocalEngineSetLauncher, self).__init__(
382 super(LocalEngineSetLauncher, self).__init__(
383 work_dir=work_dir, config=config, **kwargs
383 work_dir=work_dir, config=config, **kwargs
384 )
384 )
385 self.stop_data = {}
385 self.stop_data = {}
386
386
387 def start(self, n):
387 def start(self, n):
388 """Start n engines by profile or profile_dir."""
388 """Start n engines by profile or profile_dir."""
389 dlist = []
389 dlist = []
390 for i in range(n):
390 for i in range(n):
391 if i > 0:
391 if i > 0:
392 time.sleep(self.delay)
392 time.sleep(self.delay)
393 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
393 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
394 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
394 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
395 )
395 )
396
396
397 # Copy the engine args over to each engine launcher.
397 # Copy the engine args over to each engine launcher.
398 el.engine_cmd = copy.deepcopy(self.engine_cmd)
398 el.engine_cmd = copy.deepcopy(self.engine_cmd)
399 el.engine_args = copy.deepcopy(self.engine_args)
399 el.engine_args = copy.deepcopy(self.engine_args)
400 el.on_stop(self._notice_engine_stopped)
400 el.on_stop(self._notice_engine_stopped)
401 d = el.start()
401 d = el.start()
402 self.launchers[i] = el
402 self.launchers[i] = el
403 dlist.append(d)
403 dlist.append(d)
404 self.notify_start(dlist)
404 self.notify_start(dlist)
405 return dlist
405 return dlist
406
406
407 def find_args(self):
407 def find_args(self):
408 return ['engine set']
408 return ['engine set']
409
409
410 def signal(self, sig):
410 def signal(self, sig):
411 dlist = []
411 dlist = []
412 for el in itervalues(self.launchers):
412 for el in itervalues(self.launchers):
413 d = el.signal(sig)
413 d = el.signal(sig)
414 dlist.append(d)
414 dlist.append(d)
415 return dlist
415 return dlist
416
416
417 def interrupt_then_kill(self, delay=1.0):
417 def interrupt_then_kill(self, delay=1.0):
418 dlist = []
418 dlist = []
419 for el in itervalues(self.launchers):
419 for el in itervalues(self.launchers):
420 d = el.interrupt_then_kill(delay)
420 d = el.interrupt_then_kill(delay)
421 dlist.append(d)
421 dlist.append(d)
422 return dlist
422 return dlist
423
423
424 def stop(self):
424 def stop(self):
425 return self.interrupt_then_kill()
425 return self.interrupt_then_kill()
426
426
427 def _notice_engine_stopped(self, data):
427 def _notice_engine_stopped(self, data):
428 pid = data['pid']
428 pid = data['pid']
429 for idx,el in iteritems(self.launchers):
429 for idx,el in iteritems(self.launchers):
430 if el.process.pid == pid:
430 if el.process.pid == pid:
431 break
431 break
432 self.launchers.pop(idx)
432 self.launchers.pop(idx)
433 self.stop_data[idx] = data
433 self.stop_data[idx] = data
434 if not self.launchers:
434 if not self.launchers:
435 self.notify_stop(self.stop_data)
435 self.notify_stop(self.stop_data)
436
436
437
437
438 #-----------------------------------------------------------------------------
438 #-----------------------------------------------------------------------------
439 # MPI launchers
439 # MPI launchers
440 #-----------------------------------------------------------------------------
440 #-----------------------------------------------------------------------------
441
441
442
442
443 class MPILauncher(LocalProcessLauncher):
443 class MPILauncher(LocalProcessLauncher):
444 """Launch an external process using mpiexec."""
444 """Launch an external process using mpiexec."""
445
445
446 mpi_cmd = List(['mpiexec'], config=True,
446 mpi_cmd = List(['mpiexec'], config=True,
447 help="The mpiexec command to use in starting the process."
447 help="The mpiexec command to use in starting the process."
448 )
448 )
449 mpi_args = List([], config=True,
449 mpi_args = List([], config=True,
450 help="The command line arguments to pass to mpiexec."
450 help="The command line arguments to pass to mpiexec."
451 )
451 )
452 program = List(['date'],
452 program = List(['date'],
453 help="The program to start via mpiexec.")
453 help="The program to start via mpiexec.")
454 program_args = List([],
454 program_args = List([],
455 help="The command line argument to the program."
455 help="The command line argument to the program."
456 )
456 )
457 n = Integer(1)
457 n = Integer(1)
458
458
459 def __init__(self, *args, **kwargs):
459 def __init__(self, *args, **kwargs):
460 # deprecation for old MPIExec names:
460 # deprecation for old MPIExec names:
461 config = kwargs.get('config', {})
461 config = kwargs.get('config', {})
462 for oldname in ('MPIExecLauncher', 'MPIExecControllerLauncher', 'MPIExecEngineSetLauncher'):
462 for oldname in ('MPIExecLauncher', 'MPIExecControllerLauncher', 'MPIExecEngineSetLauncher'):
463 deprecated = config.get(oldname)
463 deprecated = config.get(oldname)
464 if deprecated:
464 if deprecated:
465 newname = oldname.replace('MPIExec', 'MPI')
465 newname = oldname.replace('MPIExec', 'MPI')
466 config[newname].update(deprecated)
466 config[newname].update(deprecated)
467 self.log.warn("WARNING: %s name has been deprecated, use %s", oldname, newname)
467 self.log.warn("WARNING: %s name has been deprecated, use %s", oldname, newname)
468
468
469 super(MPILauncher, self).__init__(*args, **kwargs)
469 super(MPILauncher, self).__init__(*args, **kwargs)
470
470
471 def find_args(self):
471 def find_args(self):
472 """Build self.args using all the fields."""
472 """Build self.args using all the fields."""
473 return self.mpi_cmd + ['-n', str(self.n)] + self.mpi_args + \
473 return self.mpi_cmd + ['-n', str(self.n)] + self.mpi_args + \
474 self.program + self.program_args
474 self.program + self.program_args
475
475
476 def start(self, n):
476 def start(self, n):
477 """Start n instances of the program using mpiexec."""
477 """Start n instances of the program using mpiexec."""
478 self.n = n
478 self.n = n
479 return super(MPILauncher, self).start()
479 return super(MPILauncher, self).start()
480
480
481
481
482 class MPIControllerLauncher(MPILauncher, ControllerMixin):
482 class MPIControllerLauncher(MPILauncher, ControllerMixin):
483 """Launch a controller using mpiexec."""
483 """Launch a controller using mpiexec."""
484
484
485 # alias back to *non-configurable* program[_args] for use in find_args()
485 # alias back to *non-configurable* program[_args] for use in find_args()
486 # this way all Controller/EngineSetLaunchers have the same form, rather
486 # this way all Controller/EngineSetLaunchers have the same form, rather
487 # than *some* having `program_args` and others `controller_args`
487 # than *some* having `program_args` and others `controller_args`
488 @property
488 @property
489 def program(self):
489 def program(self):
490 return self.controller_cmd
490 return self.controller_cmd
491
491
492 @property
492 @property
493 def program_args(self):
493 def program_args(self):
494 return self.cluster_args + self.controller_args
494 return self.cluster_args + self.controller_args
495
495
496 def start(self):
496 def start(self):
497 """Start the controller by profile_dir."""
497 """Start the controller by profile_dir."""
498 return super(MPIControllerLauncher, self).start(1)
498 return super(MPIControllerLauncher, self).start(1)
499
499
500
500
501 class MPIEngineSetLauncher(MPILauncher, EngineMixin):
501 class MPIEngineSetLauncher(MPILauncher, EngineMixin):
502 """Launch engines using mpiexec"""
502 """Launch engines using mpiexec"""
503
503
504 # alias back to *non-configurable* program[_args] for use in find_args()
504 # alias back to *non-configurable* program[_args] for use in find_args()
505 # this way all Controller/EngineSetLaunchers have the same form, rather
505 # this way all Controller/EngineSetLaunchers have the same form, rather
506 # than *some* having `program_args` and others `controller_args`
506 # than *some* having `program_args` and others `controller_args`
507 @property
507 @property
508 def program(self):
508 def program(self):
509 return self.engine_cmd
509 return self.engine_cmd
510
510
511 @property
511 @property
512 def program_args(self):
512 def program_args(self):
513 return self.cluster_args + self.engine_args
513 return self.cluster_args + self.engine_args
514
514
515 def start(self, n):
515 def start(self, n):
516 """Start n engines by profile or profile_dir."""
516 """Start n engines by profile or profile_dir."""
517 self.n = n
517 self.n = n
518 return super(MPIEngineSetLauncher, self).start(n)
518 return super(MPIEngineSetLauncher, self).start(n)
519
519
520 # deprecated MPIExec names
520 # deprecated MPIExec names
521 class DeprecatedMPILauncher(object):
521 class DeprecatedMPILauncher(object):
522 def warn(self):
522 def warn(self):
523 oldname = self.__class__.__name__
523 oldname = self.__class__.__name__
524 newname = oldname.replace('MPIExec', 'MPI')
524 newname = oldname.replace('MPIExec', 'MPI')
525 self.log.warn("WARNING: %s name is deprecated, use %s", oldname, newname)
525 self.log.warn("WARNING: %s name is deprecated, use %s", oldname, newname)
526
526
527 class MPIExecLauncher(MPILauncher, DeprecatedMPILauncher):
527 class MPIExecLauncher(MPILauncher, DeprecatedMPILauncher):
528 """Deprecated, use MPILauncher"""
528 """Deprecated, use MPILauncher"""
529 def __init__(self, *args, **kwargs):
529 def __init__(self, *args, **kwargs):
530 super(MPIExecLauncher, self).__init__(*args, **kwargs)
530 super(MPIExecLauncher, self).__init__(*args, **kwargs)
531 self.warn()
531 self.warn()
532
532
533 class MPIExecControllerLauncher(MPIControllerLauncher, DeprecatedMPILauncher):
533 class MPIExecControllerLauncher(MPIControllerLauncher, DeprecatedMPILauncher):
534 """Deprecated, use MPIControllerLauncher"""
534 """Deprecated, use MPIControllerLauncher"""
535 def __init__(self, *args, **kwargs):
535 def __init__(self, *args, **kwargs):
536 super(MPIExecControllerLauncher, self).__init__(*args, **kwargs)
536 super(MPIExecControllerLauncher, self).__init__(*args, **kwargs)
537 self.warn()
537 self.warn()
538
538
539 class MPIExecEngineSetLauncher(MPIEngineSetLauncher, DeprecatedMPILauncher):
539 class MPIExecEngineSetLauncher(MPIEngineSetLauncher, DeprecatedMPILauncher):
540 """Deprecated, use MPIEngineSetLauncher"""
540 """Deprecated, use MPIEngineSetLauncher"""
541 def __init__(self, *args, **kwargs):
541 def __init__(self, *args, **kwargs):
542 super(MPIExecEngineSetLauncher, self).__init__(*args, **kwargs)
542 super(MPIExecEngineSetLauncher, self).__init__(*args, **kwargs)
543 self.warn()
543 self.warn()
544
544
545
545
546 #-----------------------------------------------------------------------------
546 #-----------------------------------------------------------------------------
547 # SSH launchers
547 # SSH launchers
548 #-----------------------------------------------------------------------------
548 #-----------------------------------------------------------------------------
549
549
550 # TODO: Get SSH Launcher back to level of sshx in 0.10.2
550 # TODO: Get SSH Launcher back to level of sshx in 0.10.2
551
551
552 class SSHLauncher(LocalProcessLauncher):
552 class SSHLauncher(LocalProcessLauncher):
553 """A minimal launcher for ssh.
553 """A minimal launcher for ssh.
554
554
555 To be useful this will probably have to be extended to use the ``sshx``
555 To be useful this will probably have to be extended to use the ``sshx``
556 idea for environment variables. There could be other things this needs
556 idea for environment variables. There could be other things this needs
557 as well.
557 as well.
558 """
558 """
559
559
560 ssh_cmd = List(['ssh'], config=True,
560 ssh_cmd = List(['ssh'], config=True,
561 help="command for starting ssh")
561 help="command for starting ssh")
562 ssh_args = List(['-tt'], config=True,
562 ssh_args = List(['-tt'], config=True,
563 help="args to pass to ssh")
563 help="args to pass to ssh")
564 scp_cmd = List(['scp'], config=True,
564 scp_cmd = List(['scp'], config=True,
565 help="command for sending files")
565 help="command for sending files")
566 program = List(['date'],
566 program = List(['date'],
567 help="Program to launch via ssh")
567 help="Program to launch via ssh")
568 program_args = List([],
568 program_args = List([],
569 help="args to pass to remote program")
569 help="args to pass to remote program")
570 hostname = Unicode('', config=True,
570 hostname = Unicode('', config=True,
571 help="hostname on which to launch the program")
571 help="hostname on which to launch the program")
572 user = Unicode('', config=True,
572 user = Unicode('', config=True,
573 help="username for ssh")
573 help="username for ssh")
574 location = Unicode('', config=True,
574 location = Unicode('', config=True,
575 help="user@hostname location for ssh in one setting")
575 help="user@hostname location for ssh in one setting")
576 to_fetch = List([], config=True,
576 to_fetch = List([], config=True,
577 help="List of (remote, local) files to fetch after starting")
577 help="List of (remote, local) files to fetch after starting")
578 to_send = List([], config=True,
578 to_send = List([], config=True,
579 help="List of (local, remote) files to send before starting")
579 help="List of (local, remote) files to send before starting")
580
580
581 def _hostname_changed(self, name, old, new):
581 def _hostname_changed(self, name, old, new):
582 if self.user:
582 if self.user:
583 self.location = u'%s@%s' % (self.user, new)
583 self.location = u'%s@%s' % (self.user, new)
584 else:
584 else:
585 self.location = new
585 self.location = new
586
586
587 def _user_changed(self, name, old, new):
587 def _user_changed(self, name, old, new):
588 self.location = u'%s@%s' % (new, self.hostname)
588 self.location = u'%s@%s' % (new, self.hostname)
589
589
590 def find_args(self):
590 def find_args(self):
591 return self.ssh_cmd + self.ssh_args + [self.location] + \
591 return self.ssh_cmd + self.ssh_args + [self.location] + \
592 list(map(pipes.quote, self.program + self.program_args))
592 list(map(pipes.quote, self.program + self.program_args))
593
593
594 def _send_file(self, local, remote):
594 def _send_file(self, local, remote):
595 """send a single file"""
595 """send a single file"""
596 remote = "%s:%s" % (self.location, remote)
596 full_remote = "%s:%s" % (self.location, remote)
597 for i in range(10):
597 for i in range(10):
598 if not os.path.exists(local):
598 if not os.path.exists(local):
599 self.log.debug("waiting for %s" % local)
599 self.log.debug("waiting for %s" % local)
600 time.sleep(1)
600 time.sleep(1)
601 else:
601 else:
602 break
602 break
603 remote_dir = os.path.dirname(remote)
603 remote_dir = os.path.dirname(remote)
604 self.log.info("ensuring remote %s:%s/ exists", self.location, remote_dir)
604 self.log.info("ensuring remote %s:%s/ exists", self.location, remote_dir)
605 check_output(self.ssh_cmd + self.ssh_args + \
605 check_output(self.ssh_cmd + self.ssh_args + \
606 [self.location, 'mkdir', '-p', '--', remote_dir]
606 [self.location, 'mkdir', '-p', '--', remote_dir]
607 )
607 )
608 self.log.info("sending %s to %s", local, remote)
608 self.log.info("sending %s to %s", local, full_remote)
609 check_output(self.scp_cmd + [local, remote])
609 check_output(self.scp_cmd + [local, full_remote])
610
610
611 def send_files(self):
611 def send_files(self):
612 """send our files (called before start)"""
612 """send our files (called before start)"""
613 if not self.to_send:
613 if not self.to_send:
614 return
614 return
615 for local_file, remote_file in self.to_send:
615 for local_file, remote_file in self.to_send:
616 self._send_file(local_file, remote_file)
616 self._send_file(local_file, remote_file)
617
617
618 def _fetch_file(self, remote, local):
618 def _fetch_file(self, remote, local):
619 """fetch a single file"""
619 """fetch a single file"""
620 full_remote = "%s:%s" % (self.location, remote)
620 full_remote = "%s:%s" % (self.location, remote)
621 self.log.info("fetching %s from %s", local, full_remote)
621 self.log.info("fetching %s from %s", local, full_remote)
622 for i in range(10):
622 for i in range(10):
623 # wait up to 10s for remote file to exist
623 # wait up to 10s for remote file to exist
624 check = check_output(self.ssh_cmd + self.ssh_args + \
624 check = check_output(self.ssh_cmd + self.ssh_args + \
625 [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"])
625 [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"])
626 check = check.decode(DEFAULT_ENCODING, 'replace').strip()
626 check = check.decode(DEFAULT_ENCODING, 'replace').strip()
627 if check == u'no':
627 if check == u'no':
628 time.sleep(1)
628 time.sleep(1)
629 elif check == u'yes':
629 elif check == u'yes':
630 break
630 break
631 local_dir = os.path.dirname(local)
631 local_dir = os.path.dirname(local)
632 if not os.path.exists(local_dir):
632 if not os.path.exists(local_dir):
633 os.makedirs(local_dir, 775)
633 os.makedirs(local_dir, 775)
634 check_output(self.scp_cmd + [full_remote, local])
634 check_output(self.scp_cmd + [full_remote, local])
635
635
636 def fetch_files(self):
636 def fetch_files(self):
637 """fetch remote files (called after start)"""
637 """fetch remote files (called after start)"""
638 if not self.to_fetch:
638 if not self.to_fetch:
639 return
639 return
640 for remote_file, local_file in self.to_fetch:
640 for remote_file, local_file in self.to_fetch:
641 self._fetch_file(remote_file, local_file)
641 self._fetch_file(remote_file, local_file)
642
642
643 def start(self, hostname=None, user=None):
643 def start(self, hostname=None, user=None):
644 if hostname is not None:
644 if hostname is not None:
645 self.hostname = hostname
645 self.hostname = hostname
646 if user is not None:
646 if user is not None:
647 self.user = user
647 self.user = user
648
648
649 self.send_files()
649 self.send_files()
650 super(SSHLauncher, self).start()
650 super(SSHLauncher, self).start()
651 self.fetch_files()
651 self.fetch_files()
652
652
653 def signal(self, sig):
653 def signal(self, sig):
654 if self.state == 'running':
654 if self.state == 'running':
655 # send escaped ssh connection-closer
655 # send escaped ssh connection-closer
656 self.process.stdin.write('~.')
656 self.process.stdin.write('~.')
657 self.process.stdin.flush()
657 self.process.stdin.flush()
658
658
659 class SSHClusterLauncher(SSHLauncher, ClusterAppMixin):
659 class SSHClusterLauncher(SSHLauncher, ClusterAppMixin):
660
660
661 remote_profile_dir = Unicode('', config=True,
661 remote_profile_dir = Unicode('', config=True,
662 help="""The remote profile_dir to use.
662 help="""The remote profile_dir to use.
663
663
664 If not specified, use calling profile, stripping out possible leading homedir.
664 If not specified, use calling profile, stripping out possible leading homedir.
665 """)
665 """)
666
666
667 def _profile_dir_changed(self, name, old, new):
667 def _profile_dir_changed(self, name, old, new):
668 if not self.remote_profile_dir:
668 if not self.remote_profile_dir:
669 # trigger remote_profile_dir_default logic again,
669 # trigger remote_profile_dir_default logic again,
670 # in case it was already triggered before profile_dir was set
670 # in case it was already triggered before profile_dir was set
671 self.remote_profile_dir = self._strip_home(new)
671 self.remote_profile_dir = self._strip_home(new)
672
672
673 @staticmethod
673 @staticmethod
674 def _strip_home(path):
674 def _strip_home(path):
675 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
675 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
676 home = get_home_dir()
676 home = get_home_dir()
677 if not home.endswith('/'):
677 if not home.endswith('/'):
678 home = home+'/'
678 home = home+'/'
679
679
680 if path.startswith(home):
680 if path.startswith(home):
681 return path[len(home):]
681 return path[len(home):]
682 else:
682 else:
683 return path
683 return path
684
684
685 def _remote_profile_dir_default(self):
685 def _remote_profile_dir_default(self):
686 return self._strip_home(self.profile_dir)
686 return self._strip_home(self.profile_dir)
687
687
688 def _cluster_id_changed(self, name, old, new):
688 def _cluster_id_changed(self, name, old, new):
689 if new:
689 if new:
690 raise ValueError("cluster id not supported by SSH launchers")
690 raise ValueError("cluster id not supported by SSH launchers")
691
691
692 @property
692 @property
693 def cluster_args(self):
693 def cluster_args(self):
694 return ['--profile-dir', self.remote_profile_dir]
694 return ['--profile-dir', self.remote_profile_dir]
695
695
696 class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin):
696 class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin):
697
697
698 # alias back to *non-configurable* program[_args] for use in find_args()
698 # alias back to *non-configurable* program[_args] for use in find_args()
699 # this way all Controller/EngineSetLaunchers have the same form, rather
699 # this way all Controller/EngineSetLaunchers have the same form, rather
700 # than *some* having `program_args` and others `controller_args`
700 # than *some* having `program_args` and others `controller_args`
701
701
702 def _controller_cmd_default(self):
702 def _controller_cmd_default(self):
703 return ['ipcontroller']
703 return ['ipcontroller']
704
704
705 @property
705 @property
706 def program(self):
706 def program(self):
707 return self.controller_cmd
707 return self.controller_cmd
708
708
709 @property
709 @property
710 def program_args(self):
710 def program_args(self):
711 return self.cluster_args + self.controller_args
711 return self.cluster_args + self.controller_args
712
712
713 def _to_fetch_default(self):
713 def _to_fetch_default(self):
714 return [
714 return [
715 (os.path.join(self.remote_profile_dir, 'security', cf),
715 (os.path.join(self.remote_profile_dir, 'security', cf),
716 os.path.join(self.profile_dir, 'security', cf),)
716 os.path.join(self.profile_dir, 'security', cf),)
717 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
717 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
718 ]
718 ]
719
719
720 class SSHEngineLauncher(SSHClusterLauncher, EngineMixin):
720 class SSHEngineLauncher(SSHClusterLauncher, EngineMixin):
721
721
722 # alias back to *non-configurable* program[_args] for use in find_args()
722 # alias back to *non-configurable* program[_args] for use in find_args()
723 # this way all Controller/EngineSetLaunchers have the same form, rather
723 # this way all Controller/EngineSetLaunchers have the same form, rather
724 # than *some* having `program_args` and others `controller_args`
724 # than *some* having `program_args` and others `controller_args`
725
725
726 def _engine_cmd_default(self):
726 def _engine_cmd_default(self):
727 return ['ipengine']
727 return ['ipengine']
728
728
729 @property
729 @property
730 def program(self):
730 def program(self):
731 return self.engine_cmd
731 return self.engine_cmd
732
732
733 @property
733 @property
734 def program_args(self):
734 def program_args(self):
735 return self.cluster_args + self.engine_args
735 return self.cluster_args + self.engine_args
736
736
737 def _to_send_default(self):
737 def _to_send_default(self):
738 return [
738 return [
739 (os.path.join(self.profile_dir, 'security', cf),
739 (os.path.join(self.profile_dir, 'security', cf),
740 os.path.join(self.remote_profile_dir, 'security', cf))
740 os.path.join(self.remote_profile_dir, 'security', cf))
741 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
741 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
742 ]
742 ]
743
743
744
744
745 class SSHEngineSetLauncher(LocalEngineSetLauncher):
745 class SSHEngineSetLauncher(LocalEngineSetLauncher):
746 launcher_class = SSHEngineLauncher
746 launcher_class = SSHEngineLauncher
747 engines = Dict(config=True,
747 engines = Dict(config=True,
748 help="""dict of engines to launch. This is a dict by hostname of ints,
748 help="""dict of engines to launch. This is a dict by hostname of ints,
749 corresponding to the number of engines to start on that host.""")
749 corresponding to the number of engines to start on that host.""")
750
750
751 def _engine_cmd_default(self):
751 def _engine_cmd_default(self):
752 return ['ipengine']
752 return ['ipengine']
753
753
754 @property
754 @property
755 def engine_count(self):
755 def engine_count(self):
756 """determine engine count from `engines` dict"""
756 """determine engine count from `engines` dict"""
757 count = 0
757 count = 0
758 for n in itervalues(self.engines):
758 for n in itervalues(self.engines):
759 if isinstance(n, (tuple,list)):
759 if isinstance(n, (tuple,list)):
760 n,args = n
760 n,args = n
761 count += n
761 count += n
762 return count
762 return count
763
763
764 def start(self, n):
764 def start(self, n):
765 """Start engines by profile or profile_dir.
765 """Start engines by profile or profile_dir.
766 `n` is ignored, and the `engines` config property is used instead.
766 `n` is ignored, and the `engines` config property is used instead.
767 """
767 """
768
768
769 dlist = []
769 dlist = []
770 for host, n in iteritems(self.engines):
770 for host, n in iteritems(self.engines):
771 if isinstance(n, (tuple, list)):
771 if isinstance(n, (tuple, list)):
772 n, args = n
772 n, args = n
773 else:
773 else:
774 args = copy.deepcopy(self.engine_args)
774 args = copy.deepcopy(self.engine_args)
775
775
776 if '@' in host:
776 if '@' in host:
777 user,host = host.split('@',1)
777 user,host = host.split('@',1)
778 else:
778 else:
779 user=None
779 user=None
780 for i in range(n):
780 for i in range(n):
781 if i > 0:
781 if i > 0:
782 time.sleep(self.delay)
782 time.sleep(self.delay)
783 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
783 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
784 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
784 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
785 )
785 )
786 if i > 0:
786 if i > 0:
787 # only send files for the first engine on each host
787 # only send files for the first engine on each host
788 el.to_send = []
788 el.to_send = []
789
789
790 # Copy the engine args over to each engine launcher.
790 # Copy the engine args over to each engine launcher.
791 el.engine_cmd = self.engine_cmd
791 el.engine_cmd = self.engine_cmd
792 el.engine_args = args
792 el.engine_args = args
793 el.on_stop(self._notice_engine_stopped)
793 el.on_stop(self._notice_engine_stopped)
794 d = el.start(user=user, hostname=host)
794 d = el.start(user=user, hostname=host)
795 self.launchers[ "%s/%i" % (host,i) ] = el
795 self.launchers[ "%s/%i" % (host,i) ] = el
796 dlist.append(d)
796 dlist.append(d)
797 self.notify_start(dlist)
797 self.notify_start(dlist)
798 return dlist
798 return dlist
799
799
800
800
801 class SSHProxyEngineSetLauncher(SSHClusterLauncher):
801 class SSHProxyEngineSetLauncher(SSHClusterLauncher):
802 """Launcher for calling
802 """Launcher for calling
803 `ipcluster engines` on a remote machine.
803 `ipcluster engines` on a remote machine.
804
804
805 Requires that remote profile is already configured.
805 Requires that remote profile is already configured.
806 """
806 """
807
807
808 n = Integer()
808 n = Integer()
809 ipcluster_cmd = List(['ipcluster'], config=True)
809 ipcluster_cmd = List(['ipcluster'], config=True)
810
810
811 @property
811 @property
812 def program(self):
812 def program(self):
813 return self.ipcluster_cmd + ['engines']
813 return self.ipcluster_cmd + ['engines']
814
814
815 @property
815 @property
816 def program_args(self):
816 def program_args(self):
817 return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir]
817 return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir]
818
818
819 def _to_send_default(self):
819 def _to_send_default(self):
820 return [
820 return [
821 (os.path.join(self.profile_dir, 'security', cf),
821 (os.path.join(self.profile_dir, 'security', cf),
822 os.path.join(self.remote_profile_dir, 'security', cf))
822 os.path.join(self.remote_profile_dir, 'security', cf))
823 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
823 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
824 ]
824 ]
825
825
826 def start(self, n):
826 def start(self, n):
827 self.n = n
827 self.n = n
828 super(SSHProxyEngineSetLauncher, self).start()
828 super(SSHProxyEngineSetLauncher, self).start()
829
829
830
830
831 #-----------------------------------------------------------------------------
831 #-----------------------------------------------------------------------------
832 # Windows HPC Server 2008 scheduler launchers
832 # Windows HPC Server 2008 scheduler launchers
833 #-----------------------------------------------------------------------------
833 #-----------------------------------------------------------------------------
834
834
835
835
836 # This is only used on Windows.
836 # This is only used on Windows.
837 def find_job_cmd():
837 def find_job_cmd():
838 if WINDOWS:
838 if WINDOWS:
839 try:
839 try:
840 return find_cmd('job')
840 return find_cmd('job')
841 except (FindCmdError, ImportError):
841 except (FindCmdError, ImportError):
842 # ImportError will be raised if win32api is not installed
842 # ImportError will be raised if win32api is not installed
843 return 'job'
843 return 'job'
844 else:
844 else:
845 return 'job'
845 return 'job'
846
846
847
847
848 class WindowsHPCLauncher(BaseLauncher):
848 class WindowsHPCLauncher(BaseLauncher):
849
849
850 job_id_regexp = CRegExp(r'\d+', config=True,
850 job_id_regexp = CRegExp(r'\d+', config=True,
851 help="""A regular expression used to get the job id from the output of the
851 help="""A regular expression used to get the job id from the output of the
852 submit_command. """
852 submit_command. """
853 )
853 )
854 job_file_name = Unicode(u'ipython_job.xml', config=True,
854 job_file_name = Unicode(u'ipython_job.xml', config=True,
855 help="The filename of the instantiated job script.")
855 help="The filename of the instantiated job script.")
856 # The full path to the instantiated job script. This gets made dynamically
856 # The full path to the instantiated job script. This gets made dynamically
857 # by combining the work_dir with the job_file_name.
857 # by combining the work_dir with the job_file_name.
858 job_file = Unicode(u'')
858 job_file = Unicode(u'')
859 scheduler = Unicode('', config=True,
859 scheduler = Unicode('', config=True,
860 help="The hostname of the scheduler to submit the job to.")
860 help="The hostname of the scheduler to submit the job to.")
861 job_cmd = Unicode(find_job_cmd(), config=True,
861 job_cmd = Unicode(find_job_cmd(), config=True,
862 help="The command for submitting jobs.")
862 help="The command for submitting jobs.")
863
863
864 def __init__(self, work_dir=u'.', config=None, **kwargs):
864 def __init__(self, work_dir=u'.', config=None, **kwargs):
865 super(WindowsHPCLauncher, self).__init__(
865 super(WindowsHPCLauncher, self).__init__(
866 work_dir=work_dir, config=config, **kwargs
866 work_dir=work_dir, config=config, **kwargs
867 )
867 )
868
868
869 @property
869 @property
870 def job_file(self):
870 def job_file(self):
871 return os.path.join(self.work_dir, self.job_file_name)
871 return os.path.join(self.work_dir, self.job_file_name)
872
872
873 def write_job_file(self, n):
873 def write_job_file(self, n):
874 raise NotImplementedError("Implement write_job_file in a subclass.")
874 raise NotImplementedError("Implement write_job_file in a subclass.")
875
875
876 def find_args(self):
876 def find_args(self):
877 return [u'job.exe']
877 return [u'job.exe']
878
878
879 def parse_job_id(self, output):
879 def parse_job_id(self, output):
880 """Take the output of the submit command and return the job id."""
880 """Take the output of the submit command and return the job id."""
881 m = self.job_id_regexp.search(output)
881 m = self.job_id_regexp.search(output)
882 if m is not None:
882 if m is not None:
883 job_id = m.group()
883 job_id = m.group()
884 else:
884 else:
885 raise LauncherError("Job id couldn't be determined: %s" % output)
885 raise LauncherError("Job id couldn't be determined: %s" % output)
886 self.job_id = job_id
886 self.job_id = job_id
887 self.log.info('Job started with id: %r', job_id)
887 self.log.info('Job started with id: %r', job_id)
888 return job_id
888 return job_id
889
889
890 def start(self, n):
890 def start(self, n):
891 """Start n copies of the process using the Win HPC job scheduler."""
891 """Start n copies of the process using the Win HPC job scheduler."""
892 self.write_job_file(n)
892 self.write_job_file(n)
893 args = [
893 args = [
894 'submit',
894 'submit',
895 '/jobfile:%s' % self.job_file,
895 '/jobfile:%s' % self.job_file,
896 '/scheduler:%s' % self.scheduler
896 '/scheduler:%s' % self.scheduler
897 ]
897 ]
898 self.log.debug("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
898 self.log.debug("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
899
899
900 output = check_output([self.job_cmd]+args,
900 output = check_output([self.job_cmd]+args,
901 env=os.environ,
901 env=os.environ,
902 cwd=self.work_dir,
902 cwd=self.work_dir,
903 stderr=STDOUT
903 stderr=STDOUT
904 )
904 )
905 output = output.decode(DEFAULT_ENCODING, 'replace')
905 output = output.decode(DEFAULT_ENCODING, 'replace')
906 job_id = self.parse_job_id(output)
906 job_id = self.parse_job_id(output)
907 self.notify_start(job_id)
907 self.notify_start(job_id)
908 return job_id
908 return job_id
909
909
910 def stop(self):
910 def stop(self):
911 args = [
911 args = [
912 'cancel',
912 'cancel',
913 self.job_id,
913 self.job_id,
914 '/scheduler:%s' % self.scheduler
914 '/scheduler:%s' % self.scheduler
915 ]
915 ]
916 self.log.info("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
916 self.log.info("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
917 try:
917 try:
918 output = check_output([self.job_cmd]+args,
918 output = check_output([self.job_cmd]+args,
919 env=os.environ,
919 env=os.environ,
920 cwd=self.work_dir,
920 cwd=self.work_dir,
921 stderr=STDOUT
921 stderr=STDOUT
922 )
922 )
923 output = output.decode(DEFAULT_ENCODING, 'replace')
923 output = output.decode(DEFAULT_ENCODING, 'replace')
924 except:
924 except:
925 output = u'The job already appears to be stopped: %r' % self.job_id
925 output = u'The job already appears to be stopped: %r' % self.job_id
926 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
926 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
927 return output
927 return output
928
928
929
929
930 class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):
930 class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):
931
931
932 job_file_name = Unicode(u'ipcontroller_job.xml', config=True,
932 job_file_name = Unicode(u'ipcontroller_job.xml', config=True,
933 help="WinHPC xml job file.")
933 help="WinHPC xml job file.")
934 controller_args = List([], config=False,
934 controller_args = List([], config=False,
935 help="extra args to pass to ipcontroller")
935 help="extra args to pass to ipcontroller")
936
936
937 def write_job_file(self, n):
937 def write_job_file(self, n):
938 job = IPControllerJob(parent=self)
938 job = IPControllerJob(parent=self)
939
939
940 t = IPControllerTask(parent=self)
940 t = IPControllerTask(parent=self)
941 # The tasks work directory is *not* the actual work directory of
941 # The tasks work directory is *not* the actual work directory of
942 # the controller. It is used as the base path for the stdout/stderr
942 # the controller. It is used as the base path for the stdout/stderr
943 # files that the scheduler redirects to.
943 # files that the scheduler redirects to.
944 t.work_directory = self.profile_dir
944 t.work_directory = self.profile_dir
945 # Add the profile_dir and from self.start().
945 # Add the profile_dir and from self.start().
946 t.controller_args.extend(self.cluster_args)
946 t.controller_args.extend(self.cluster_args)
947 t.controller_args.extend(self.controller_args)
947 t.controller_args.extend(self.controller_args)
948 job.add_task(t)
948 job.add_task(t)
949
949
950 self.log.debug("Writing job description file: %s", self.job_file)
950 self.log.debug("Writing job description file: %s", self.job_file)
951 job.write(self.job_file)
951 job.write(self.job_file)
952
952
953 @property
953 @property
954 def job_file(self):
954 def job_file(self):
955 return os.path.join(self.profile_dir, self.job_file_name)
955 return os.path.join(self.profile_dir, self.job_file_name)
956
956
957 def start(self):
957 def start(self):
958 """Start the controller by profile_dir."""
958 """Start the controller by profile_dir."""
959 return super(WindowsHPCControllerLauncher, self).start(1)
959 return super(WindowsHPCControllerLauncher, self).start(1)
960
960
961
961
962 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):
962 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):
963
963
964 job_file_name = Unicode(u'ipengineset_job.xml', config=True,
964 job_file_name = Unicode(u'ipengineset_job.xml', config=True,
965 help="jobfile for ipengines job")
965 help="jobfile for ipengines job")
966 engine_args = List([], config=False,
966 engine_args = List([], config=False,
967 help="extra args to pas to ipengine")
967 help="extra args to pas to ipengine")
968
968
969 def write_job_file(self, n):
969 def write_job_file(self, n):
970 job = IPEngineSetJob(parent=self)
970 job = IPEngineSetJob(parent=self)
971
971
972 for i in range(n):
972 for i in range(n):
973 t = IPEngineTask(parent=self)
973 t = IPEngineTask(parent=self)
974 # The tasks work directory is *not* the actual work directory of
974 # The tasks work directory is *not* the actual work directory of
975 # the engine. It is used as the base path for the stdout/stderr
975 # the engine. It is used as the base path for the stdout/stderr
976 # files that the scheduler redirects to.
976 # files that the scheduler redirects to.
977 t.work_directory = self.profile_dir
977 t.work_directory = self.profile_dir
978 # Add the profile_dir and from self.start().
978 # Add the profile_dir and from self.start().
979 t.engine_args.extend(self.cluster_args)
979 t.engine_args.extend(self.cluster_args)
980 t.engine_args.extend(self.engine_args)
980 t.engine_args.extend(self.engine_args)
981 job.add_task(t)
981 job.add_task(t)
982
982
983 self.log.debug("Writing job description file: %s", self.job_file)
983 self.log.debug("Writing job description file: %s", self.job_file)
984 job.write(self.job_file)
984 job.write(self.job_file)
985
985
986 @property
986 @property
987 def job_file(self):
987 def job_file(self):
988 return os.path.join(self.profile_dir, self.job_file_name)
988 return os.path.join(self.profile_dir, self.job_file_name)
989
989
990 def start(self, n):
990 def start(self, n):
991 """Start the controller by profile_dir."""
991 """Start the controller by profile_dir."""
992 return super(WindowsHPCEngineSetLauncher, self).start(n)
992 return super(WindowsHPCEngineSetLauncher, self).start(n)
993
993
994
994
995 #-----------------------------------------------------------------------------
995 #-----------------------------------------------------------------------------
996 # Batch (PBS) system launchers
996 # Batch (PBS) system launchers
997 #-----------------------------------------------------------------------------
997 #-----------------------------------------------------------------------------
998
998
999 class BatchClusterAppMixin(ClusterAppMixin):
999 class BatchClusterAppMixin(ClusterAppMixin):
1000 """ClusterApp mixin that updates the self.context dict, rather than cl-args."""
1000 """ClusterApp mixin that updates the self.context dict, rather than cl-args."""
1001 def _profile_dir_changed(self, name, old, new):
1001 def _profile_dir_changed(self, name, old, new):
1002 self.context[name] = new
1002 self.context[name] = new
1003 _cluster_id_changed = _profile_dir_changed
1003 _cluster_id_changed = _profile_dir_changed
1004
1004
1005 def _profile_dir_default(self):
1005 def _profile_dir_default(self):
1006 self.context['profile_dir'] = ''
1006 self.context['profile_dir'] = ''
1007 return ''
1007 return ''
1008 def _cluster_id_default(self):
1008 def _cluster_id_default(self):
1009 self.context['cluster_id'] = ''
1009 self.context['cluster_id'] = ''
1010 return ''
1010 return ''
1011
1011
1012
1012
1013 class BatchSystemLauncher(BaseLauncher):
1013 class BatchSystemLauncher(BaseLauncher):
1014 """Launch an external process using a batch system.
1014 """Launch an external process using a batch system.
1015
1015
1016 This class is designed to work with UNIX batch systems like PBS, LSF,
1016 This class is designed to work with UNIX batch systems like PBS, LSF,
1017 GridEngine, etc. The overall model is that there are different commands
1017 GridEngine, etc. The overall model is that there are different commands
1018 like qsub, qdel, etc. that handle the starting and stopping of the process.
1018 like qsub, qdel, etc. that handle the starting and stopping of the process.
1019
1019
1020 This class also has the notion of a batch script. The ``batch_template``
1020 This class also has the notion of a batch script. The ``batch_template``
1021 attribute can be set to a string that is a template for the batch script.
1021 attribute can be set to a string that is a template for the batch script.
1022 This template is instantiated using string formatting. Thus the template can
1022 This template is instantiated using string formatting. Thus the template can
1023 use {n} fot the number of instances. Subclasses can add additional variables
1023 use {n} fot the number of instances. Subclasses can add additional variables
1024 to the template dict.
1024 to the template dict.
1025 """
1025 """
1026
1026
1027 # Subclasses must fill these in. See PBSEngineSet
1027 # Subclasses must fill these in. See PBSEngineSet
1028 submit_command = List([''], config=True,
1028 submit_command = List([''], config=True,
1029 help="The name of the command line program used to submit jobs.")
1029 help="The name of the command line program used to submit jobs.")
1030 delete_command = List([''], config=True,
1030 delete_command = List([''], config=True,
1031 help="The name of the command line program used to delete jobs.")
1031 help="The name of the command line program used to delete jobs.")
1032 job_id_regexp = CRegExp('', config=True,
1032 job_id_regexp = CRegExp('', config=True,
1033 help="""A regular expression used to get the job id from the output of the
1033 help="""A regular expression used to get the job id from the output of the
1034 submit_command.""")
1034 submit_command.""")
1035 job_id_regexp_group = Integer(0, config=True,
1035 job_id_regexp_group = Integer(0, config=True,
1036 help="""The group we wish to match in job_id_regexp (0 to match all)""")
1036 help="""The group we wish to match in job_id_regexp (0 to match all)""")
1037 batch_template = Unicode('', config=True,
1037 batch_template = Unicode('', config=True,
1038 help="The string that is the batch script template itself.")
1038 help="The string that is the batch script template itself.")
1039 batch_template_file = Unicode(u'', config=True,
1039 batch_template_file = Unicode(u'', config=True,
1040 help="The file that contains the batch template.")
1040 help="The file that contains the batch template.")
1041 batch_file_name = Unicode(u'batch_script', config=True,
1041 batch_file_name = Unicode(u'batch_script', config=True,
1042 help="The filename of the instantiated batch script.")
1042 help="The filename of the instantiated batch script.")
1043 queue = Unicode(u'', config=True,
1043 queue = Unicode(u'', config=True,
1044 help="The PBS Queue.")
1044 help="The PBS Queue.")
1045
1045
1046 def _queue_changed(self, name, old, new):
1046 def _queue_changed(self, name, old, new):
1047 self.context[name] = new
1047 self.context[name] = new
1048
1048
1049 n = Integer(1)
1049 n = Integer(1)
1050 _n_changed = _queue_changed
1050 _n_changed = _queue_changed
1051
1051
1052 # not configurable, override in subclasses
1052 # not configurable, override in subclasses
1053 # PBS Job Array regex
1053 # PBS Job Array regex
1054 job_array_regexp = CRegExp('')
1054 job_array_regexp = CRegExp('')
1055 job_array_template = Unicode('')
1055 job_array_template = Unicode('')
1056 # PBS Queue regex
1056 # PBS Queue regex
1057 queue_regexp = CRegExp('')
1057 queue_regexp = CRegExp('')
1058 queue_template = Unicode('')
1058 queue_template = Unicode('')
1059 # The default batch template, override in subclasses
1059 # The default batch template, override in subclasses
1060 default_template = Unicode('')
1060 default_template = Unicode('')
1061 # The full path to the instantiated batch script.
1061 # The full path to the instantiated batch script.
1062 batch_file = Unicode(u'')
1062 batch_file = Unicode(u'')
1063 # the format dict used with batch_template:
1063 # the format dict used with batch_template:
1064 context = Dict()
1064 context = Dict()
1065
1065
1066 def _context_default(self):
1066 def _context_default(self):
1067 """load the default context with the default values for the basic keys
1067 """load the default context with the default values for the basic keys
1068
1068
1069 because the _trait_changed methods only load the context if they
1069 because the _trait_changed methods only load the context if they
1070 are set to something other than the default value.
1070 are set to something other than the default value.
1071 """
1071 """
1072 return dict(n=1, queue=u'', profile_dir=u'', cluster_id=u'')
1072 return dict(n=1, queue=u'', profile_dir=u'', cluster_id=u'')
1073
1073
1074 # the Formatter instance for rendering the templates:
1074 # the Formatter instance for rendering the templates:
1075 formatter = Instance(EvalFormatter, (), {})
1075 formatter = Instance(EvalFormatter, (), {})
1076
1076
1077 def find_args(self):
1077 def find_args(self):
1078 return self.submit_command + [self.batch_file]
1078 return self.submit_command + [self.batch_file]
1079
1079
1080 def __init__(self, work_dir=u'.', config=None, **kwargs):
1080 def __init__(self, work_dir=u'.', config=None, **kwargs):
1081 super(BatchSystemLauncher, self).__init__(
1081 super(BatchSystemLauncher, self).__init__(
1082 work_dir=work_dir, config=config, **kwargs
1082 work_dir=work_dir, config=config, **kwargs
1083 )
1083 )
1084 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
1084 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
1085
1085
1086 def parse_job_id(self, output):
1086 def parse_job_id(self, output):
1087 """Take the output of the submit command and return the job id."""
1087 """Take the output of the submit command and return the job id."""
1088 m = self.job_id_regexp.search(output)
1088 m = self.job_id_regexp.search(output)
1089 if m is not None:
1089 if m is not None:
1090 job_id = m.group(self.job_id_regexp_group)
1090 job_id = m.group(self.job_id_regexp_group)
1091 else:
1091 else:
1092 raise LauncherError("Job id couldn't be determined: %s" % output)
1092 raise LauncherError("Job id couldn't be determined: %s" % output)
1093 self.job_id = job_id
1093 self.job_id = job_id
1094 self.log.info('Job submitted with job id: %r', job_id)
1094 self.log.info('Job submitted with job id: %r', job_id)
1095 return job_id
1095 return job_id
1096
1096
1097 def write_batch_script(self, n):
1097 def write_batch_script(self, n):
1098 """Instantiate and write the batch script to the work_dir."""
1098 """Instantiate and write the batch script to the work_dir."""
1099 self.n = n
1099 self.n = n
1100 # first priority is batch_template if set
1100 # first priority is batch_template if set
1101 if self.batch_template_file and not self.batch_template:
1101 if self.batch_template_file and not self.batch_template:
1102 # second priority is batch_template_file
1102 # second priority is batch_template_file
1103 with open(self.batch_template_file) as f:
1103 with open(self.batch_template_file) as f:
1104 self.batch_template = f.read()
1104 self.batch_template = f.read()
1105 if not self.batch_template:
1105 if not self.batch_template:
1106 # third (last) priority is default_template
1106 # third (last) priority is default_template
1107 self.batch_template = self.default_template
1107 self.batch_template = self.default_template
1108 # add jobarray or queue lines to user-specified template
1108 # add jobarray or queue lines to user-specified template
1109 # note that this is *only* when user did not specify a template.
1109 # note that this is *only* when user did not specify a template.
1110 self._insert_queue_in_script()
1110 self._insert_queue_in_script()
1111 self._insert_job_array_in_script()
1111 self._insert_job_array_in_script()
1112 script_as_string = self.formatter.format(self.batch_template, **self.context)
1112 script_as_string = self.formatter.format(self.batch_template, **self.context)
1113 self.log.debug('Writing batch script: %s', self.batch_file)
1113 self.log.debug('Writing batch script: %s', self.batch_file)
1114 with open(self.batch_file, 'w') as f:
1114 with open(self.batch_file, 'w') as f:
1115 f.write(script_as_string)
1115 f.write(script_as_string)
1116 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1116 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1117
1117
1118 def _insert_queue_in_script(self):
1118 def _insert_queue_in_script(self):
1119 """Inserts a queue if required into the batch script.
1119 """Inserts a queue if required into the batch script.
1120 """
1120 """
1121 if self.queue and not self.queue_regexp.search(self.batch_template):
1121 if self.queue and not self.queue_regexp.search(self.batch_template):
1122 self.log.debug("adding PBS queue settings to batch script")
1122 self.log.debug("adding PBS queue settings to batch script")
1123 firstline, rest = self.batch_template.split('\n',1)
1123 firstline, rest = self.batch_template.split('\n',1)
1124 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
1124 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
1125
1125
1126 def _insert_job_array_in_script(self):
1126 def _insert_job_array_in_script(self):
1127 """Inserts a job array if required into the batch script.
1127 """Inserts a job array if required into the batch script.
1128 """
1128 """
1129 if not self.job_array_regexp.search(self.batch_template):
1129 if not self.job_array_regexp.search(self.batch_template):
1130 self.log.debug("adding job array settings to batch script")
1130 self.log.debug("adding job array settings to batch script")
1131 firstline, rest = self.batch_template.split('\n',1)
1131 firstline, rest = self.batch_template.split('\n',1)
1132 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
1132 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
1133
1133
1134 def start(self, n):
1134 def start(self, n):
1135 """Start n copies of the process using a batch system."""
1135 """Start n copies of the process using a batch system."""
1136 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
1136 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
1137 # Here we save profile_dir in the context so they
1137 # Here we save profile_dir in the context so they
1138 # can be used in the batch script template as {profile_dir}
1138 # can be used in the batch script template as {profile_dir}
1139 self.write_batch_script(n)
1139 self.write_batch_script(n)
1140 output = check_output(self.args, env=os.environ)
1140 output = check_output(self.args, env=os.environ)
1141 output = output.decode(DEFAULT_ENCODING, 'replace')
1141 output = output.decode(DEFAULT_ENCODING, 'replace')
1142
1142
1143 job_id = self.parse_job_id(output)
1143 job_id = self.parse_job_id(output)
1144 self.notify_start(job_id)
1144 self.notify_start(job_id)
1145 return job_id
1145 return job_id
1146
1146
1147 def stop(self):
1147 def stop(self):
1148 try:
1148 try:
1149 p = Popen(self.delete_command+[self.job_id], env=os.environ,
1149 p = Popen(self.delete_command+[self.job_id], env=os.environ,
1150 stdout=PIPE, stderr=PIPE)
1150 stdout=PIPE, stderr=PIPE)
1151 out, err = p.communicate()
1151 out, err = p.communicate()
1152 output = out + err
1152 output = out + err
1153 except:
1153 except:
1154 self.log.exception("Problem stopping cluster with command: %s" %
1154 self.log.exception("Problem stopping cluster with command: %s" %
1155 (self.delete_command + [self.job_id]))
1155 (self.delete_command + [self.job_id]))
1156 output = ""
1156 output = ""
1157 output = output.decode(DEFAULT_ENCODING, 'replace')
1157 output = output.decode(DEFAULT_ENCODING, 'replace')
1158 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
1158 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
1159 return output
1159 return output
1160
1160
1161
1161
1162 class PBSLauncher(BatchSystemLauncher):
1162 class PBSLauncher(BatchSystemLauncher):
1163 """A BatchSystemLauncher subclass for PBS."""
1163 """A BatchSystemLauncher subclass for PBS."""
1164
1164
1165 submit_command = List(['qsub'], config=True,
1165 submit_command = List(['qsub'], config=True,
1166 help="The PBS submit command ['qsub']")
1166 help="The PBS submit command ['qsub']")
1167 delete_command = List(['qdel'], config=True,
1167 delete_command = List(['qdel'], config=True,
1168 help="The PBS delete command ['qsub']")
1168 help="The PBS delete command ['qsub']")
1169 job_id_regexp = CRegExp(r'\d+', config=True,
1169 job_id_regexp = CRegExp(r'\d+', config=True,
1170 help="Regular expresion for identifying the job ID [r'\d+']")
1170 help="Regular expresion for identifying the job ID [r'\d+']")
1171
1171
1172 batch_file = Unicode(u'')
1172 batch_file = Unicode(u'')
1173 job_array_regexp = CRegExp('#PBS\W+-t\W+[\w\d\-\$]+')
1173 job_array_regexp = CRegExp('#PBS\W+-t\W+[\w\d\-\$]+')
1174 job_array_template = Unicode('#PBS -t 1-{n}')
1174 job_array_template = Unicode('#PBS -t 1-{n}')
1175 queue_regexp = CRegExp('#PBS\W+-q\W+\$?\w+')
1175 queue_regexp = CRegExp('#PBS\W+-q\W+\$?\w+')
1176 queue_template = Unicode('#PBS -q {queue}')
1176 queue_template = Unicode('#PBS -q {queue}')
1177
1177
1178
1178
1179 class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):
1179 class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):
1180 """Launch a controller using PBS."""
1180 """Launch a controller using PBS."""
1181
1181
1182 batch_file_name = Unicode(u'pbs_controller', config=True,
1182 batch_file_name = Unicode(u'pbs_controller', config=True,
1183 help="batch file name for the controller job.")
1183 help="batch file name for the controller job.")
1184 default_template= Unicode("""#!/bin/sh
1184 default_template= Unicode("""#!/bin/sh
1185 #PBS -V
1185 #PBS -V
1186 #PBS -N ipcontroller
1186 #PBS -N ipcontroller
1187 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1187 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1188 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1188 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1189
1189
1190 def start(self):
1190 def start(self):
1191 """Start the controller by profile or profile_dir."""
1191 """Start the controller by profile or profile_dir."""
1192 return super(PBSControllerLauncher, self).start(1)
1192 return super(PBSControllerLauncher, self).start(1)
1193
1193
1194
1194
1195 class PBSEngineSetLauncher(PBSLauncher, BatchClusterAppMixin):
1195 class PBSEngineSetLauncher(PBSLauncher, BatchClusterAppMixin):
1196 """Launch Engines using PBS"""
1196 """Launch Engines using PBS"""
1197 batch_file_name = Unicode(u'pbs_engines', config=True,
1197 batch_file_name = Unicode(u'pbs_engines', config=True,
1198 help="batch file name for the engine(s) job.")
1198 help="batch file name for the engine(s) job.")
1199 default_template= Unicode(u"""#!/bin/sh
1199 default_template= Unicode(u"""#!/bin/sh
1200 #PBS -V
1200 #PBS -V
1201 #PBS -N ipengine
1201 #PBS -N ipengine
1202 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1202 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1203 """%(' '.join(map(pipes.quote,ipengine_cmd_argv))))
1203 """%(' '.join(map(pipes.quote,ipengine_cmd_argv))))
1204
1204
1205
1205
1206 #SGE is very similar to PBS
1206 #SGE is very similar to PBS
1207
1207
1208 class SGELauncher(PBSLauncher):
1208 class SGELauncher(PBSLauncher):
1209 """Sun GridEngine is a PBS clone with slightly different syntax"""
1209 """Sun GridEngine is a PBS clone with slightly different syntax"""
1210 job_array_regexp = CRegExp('#\$\W+\-t')
1210 job_array_regexp = CRegExp('#\$\W+\-t')
1211 job_array_template = Unicode('#$ -t 1-{n}')
1211 job_array_template = Unicode('#$ -t 1-{n}')
1212 queue_regexp = CRegExp('#\$\W+-q\W+\$?\w+')
1212 queue_regexp = CRegExp('#\$\W+-q\W+\$?\w+')
1213 queue_template = Unicode('#$ -q {queue}')
1213 queue_template = Unicode('#$ -q {queue}')
1214
1214
1215
1215
1216 class SGEControllerLauncher(SGELauncher, BatchClusterAppMixin):
1216 class SGEControllerLauncher(SGELauncher, BatchClusterAppMixin):
1217 """Launch a controller using SGE."""
1217 """Launch a controller using SGE."""
1218
1218
1219 batch_file_name = Unicode(u'sge_controller', config=True,
1219 batch_file_name = Unicode(u'sge_controller', config=True,
1220 help="batch file name for the ipontroller job.")
1220 help="batch file name for the ipontroller job.")
1221 default_template= Unicode(u"""#$ -V
1221 default_template= Unicode(u"""#$ -V
1222 #$ -S /bin/sh
1222 #$ -S /bin/sh
1223 #$ -N ipcontroller
1223 #$ -N ipcontroller
1224 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1224 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1225 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1225 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1226
1226
1227 def start(self):
1227 def start(self):
1228 """Start the controller by profile or profile_dir."""
1228 """Start the controller by profile or profile_dir."""
1229 return super(SGEControllerLauncher, self).start(1)
1229 return super(SGEControllerLauncher, self).start(1)
1230
1230
1231
1231
1232 class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):
1232 class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):
1233 """Launch Engines with SGE"""
1233 """Launch Engines with SGE"""
1234 batch_file_name = Unicode(u'sge_engines', config=True,
1234 batch_file_name = Unicode(u'sge_engines', config=True,
1235 help="batch file name for the engine(s) job.")
1235 help="batch file name for the engine(s) job.")
1236 default_template = Unicode("""#$ -V
1236 default_template = Unicode("""#$ -V
1237 #$ -S /bin/sh
1237 #$ -S /bin/sh
1238 #$ -N ipengine
1238 #$ -N ipengine
1239 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1239 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1240 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1240 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1241
1241
1242
1242
1243 # LSF launchers
1243 # LSF launchers
1244
1244
1245 class LSFLauncher(BatchSystemLauncher):
1245 class LSFLauncher(BatchSystemLauncher):
1246 """A BatchSystemLauncher subclass for LSF."""
1246 """A BatchSystemLauncher subclass for LSF."""
1247
1247
1248 submit_command = List(['bsub'], config=True,
1248 submit_command = List(['bsub'], config=True,
1249 help="The PBS submit command ['bsub']")
1249 help="The PBS submit command ['bsub']")
1250 delete_command = List(['bkill'], config=True,
1250 delete_command = List(['bkill'], config=True,
1251 help="The PBS delete command ['bkill']")
1251 help="The PBS delete command ['bkill']")
1252 job_id_regexp = CRegExp(r'\d+', config=True,
1252 job_id_regexp = CRegExp(r'\d+', config=True,
1253 help="Regular expresion for identifying the job ID [r'\d+']")
1253 help="Regular expresion for identifying the job ID [r'\d+']")
1254
1254
1255 batch_file = Unicode(u'')
1255 batch_file = Unicode(u'')
1256 job_array_regexp = CRegExp('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1256 job_array_regexp = CRegExp('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1257 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1257 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1258 queue_regexp = CRegExp('#BSUB[ \t]+-q[ \t]+\w+')
1258 queue_regexp = CRegExp('#BSUB[ \t]+-q[ \t]+\w+')
1259 queue_template = Unicode('#BSUB -q {queue}')
1259 queue_template = Unicode('#BSUB -q {queue}')
1260
1260
1261 def start(self, n):
1261 def start(self, n):
1262 """Start n copies of the process using LSF batch system.
1262 """Start n copies of the process using LSF batch system.
1263 This cant inherit from the base class because bsub expects
1263 This cant inherit from the base class because bsub expects
1264 to be piped a shell script in order to honor the #BSUB directives :
1264 to be piped a shell script in order to honor the #BSUB directives :
1265 bsub < script
1265 bsub < script
1266 """
1266 """
1267 # Here we save profile_dir in the context so they
1267 # Here we save profile_dir in the context so they
1268 # can be used in the batch script template as {profile_dir}
1268 # can be used in the batch script template as {profile_dir}
1269 self.write_batch_script(n)
1269 self.write_batch_script(n)
1270 piped_cmd = self.args[0]+'<\"'+self.args[1]+'\"'
1270 piped_cmd = self.args[0]+'<\"'+self.args[1]+'\"'
1271 self.log.debug("Starting %s: %s", self.__class__.__name__, piped_cmd)
1271 self.log.debug("Starting %s: %s", self.__class__.__name__, piped_cmd)
1272 p = Popen(piped_cmd, shell=True,env=os.environ,stdout=PIPE)
1272 p = Popen(piped_cmd, shell=True,env=os.environ,stdout=PIPE)
1273 output,err = p.communicate()
1273 output,err = p.communicate()
1274 output = output.decode(DEFAULT_ENCODING, 'replace')
1274 output = output.decode(DEFAULT_ENCODING, 'replace')
1275 job_id = self.parse_job_id(output)
1275 job_id = self.parse_job_id(output)
1276 self.notify_start(job_id)
1276 self.notify_start(job_id)
1277 return job_id
1277 return job_id
1278
1278
1279
1279
1280 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1280 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1281 """Launch a controller using LSF."""
1281 """Launch a controller using LSF."""
1282
1282
1283 batch_file_name = Unicode(u'lsf_controller', config=True,
1283 batch_file_name = Unicode(u'lsf_controller', config=True,
1284 help="batch file name for the controller job.")
1284 help="batch file name for the controller job.")
1285 default_template= Unicode("""#!/bin/sh
1285 default_template= Unicode("""#!/bin/sh
1286 #BSUB -J ipcontroller
1286 #BSUB -J ipcontroller
1287 #BSUB -oo ipcontroller.o.%%J
1287 #BSUB -oo ipcontroller.o.%%J
1288 #BSUB -eo ipcontroller.e.%%J
1288 #BSUB -eo ipcontroller.e.%%J
1289 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1289 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1290 """%(' '.join(map(pipes.quote,ipcontroller_cmd_argv))))
1290 """%(' '.join(map(pipes.quote,ipcontroller_cmd_argv))))
1291
1291
1292 def start(self):
1292 def start(self):
1293 """Start the controller by profile or profile_dir."""
1293 """Start the controller by profile or profile_dir."""
1294 return super(LSFControllerLauncher, self).start(1)
1294 return super(LSFControllerLauncher, self).start(1)
1295
1295
1296
1296
1297 class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):
1297 class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):
1298 """Launch Engines using LSF"""
1298 """Launch Engines using LSF"""
1299 batch_file_name = Unicode(u'lsf_engines', config=True,
1299 batch_file_name = Unicode(u'lsf_engines', config=True,
1300 help="batch file name for the engine(s) job.")
1300 help="batch file name for the engine(s) job.")
1301 default_template= Unicode(u"""#!/bin/sh
1301 default_template= Unicode(u"""#!/bin/sh
1302 #BSUB -oo ipengine.o.%%J
1302 #BSUB -oo ipengine.o.%%J
1303 #BSUB -eo ipengine.e.%%J
1303 #BSUB -eo ipengine.e.%%J
1304 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1304 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1305 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1305 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1306
1306
1307
1307
1308
1308
1309 class HTCondorLauncher(BatchSystemLauncher):
1309 class HTCondorLauncher(BatchSystemLauncher):
1310 """A BatchSystemLauncher subclass for HTCondor.
1310 """A BatchSystemLauncher subclass for HTCondor.
1311
1311
1312 HTCondor requires that we launch the ipengine/ipcontroller scripts rather
1312 HTCondor requires that we launch the ipengine/ipcontroller scripts rather
1313 that the python instance but otherwise is very similar to PBS. This is because
1313 that the python instance but otherwise is very similar to PBS. This is because
1314 HTCondor destroys sys.executable when launching remote processes - a launched
1314 HTCondor destroys sys.executable when launching remote processes - a launched
1315 python process depends on sys.executable to effectively evaluate its
1315 python process depends on sys.executable to effectively evaluate its
1316 module search paths. Without it, regardless of which python interpreter you launch
1316 module search paths. Without it, regardless of which python interpreter you launch
1317 you will get the to built in module search paths.
1317 you will get the to built in module search paths.
1318
1318
1319 We use the ip{cluster, engine, controller} scripts as our executable to circumvent
1319 We use the ip{cluster, engine, controller} scripts as our executable to circumvent
1320 this - the mechanism of shebanged scripts means that the python binary will be
1320 this - the mechanism of shebanged scripts means that the python binary will be
1321 launched with argv[0] set to the *location of the ip{cluster, engine, controller}
1321 launched with argv[0] set to the *location of the ip{cluster, engine, controller}
1322 scripts on the remote node*. This means you need to take care that:
1322 scripts on the remote node*. This means you need to take care that:
1323
1323
1324 a. Your remote nodes have their paths configured correctly, with the ipengine and ipcontroller
1324 a. Your remote nodes have their paths configured correctly, with the ipengine and ipcontroller
1325 of the python environment you wish to execute code in having top precedence.
1325 of the python environment you wish to execute code in having top precedence.
1326 b. This functionality is untested on Windows.
1326 b. This functionality is untested on Windows.
1327
1327
1328 If you need different behavior, consider making you own template.
1328 If you need different behavior, consider making you own template.
1329 """
1329 """
1330
1330
1331 submit_command = List(['condor_submit'], config=True,
1331 submit_command = List(['condor_submit'], config=True,
1332 help="The HTCondor submit command ['condor_submit']")
1332 help="The HTCondor submit command ['condor_submit']")
1333 delete_command = List(['condor_rm'], config=True,
1333 delete_command = List(['condor_rm'], config=True,
1334 help="The HTCondor delete command ['condor_rm']")
1334 help="The HTCondor delete command ['condor_rm']")
1335 job_id_regexp = CRegExp(r'(\d+)\.$', config=True,
1335 job_id_regexp = CRegExp(r'(\d+)\.$', config=True,
1336 help="Regular expression for identifying the job ID [r'(\d+)\.$']")
1336 help="Regular expression for identifying the job ID [r'(\d+)\.$']")
1337 job_id_regexp_group = Integer(1, config=True,
1337 job_id_regexp_group = Integer(1, config=True,
1338 help="""The group we wish to match in job_id_regexp [1]""")
1338 help="""The group we wish to match in job_id_regexp [1]""")
1339
1339
1340 job_array_regexp = CRegExp('queue\W+\$')
1340 job_array_regexp = CRegExp('queue\W+\$')
1341 job_array_template = Unicode('queue {n}')
1341 job_array_template = Unicode('queue {n}')
1342
1342
1343
1343
1344 def _insert_job_array_in_script(self):
1344 def _insert_job_array_in_script(self):
1345 """Inserts a job array if required into the batch script.
1345 """Inserts a job array if required into the batch script.
1346 """
1346 """
1347 if not self.job_array_regexp.search(self.batch_template):
1347 if not self.job_array_regexp.search(self.batch_template):
1348 self.log.debug("adding job array settings to batch script")
1348 self.log.debug("adding job array settings to batch script")
1349 #HTCondor requires that the job array goes at the bottom of the script
1349 #HTCondor requires that the job array goes at the bottom of the script
1350 self.batch_template = '\n'.join([self.batch_template,
1350 self.batch_template = '\n'.join([self.batch_template,
1351 self.job_array_template])
1351 self.job_array_template])
1352
1352
1353 def _insert_queue_in_script(self):
1353 def _insert_queue_in_script(self):
1354 """AFAIK, HTCondor doesn't have a concept of multiple queues that can be
1354 """AFAIK, HTCondor doesn't have a concept of multiple queues that can be
1355 specified in the script.
1355 specified in the script.
1356 """
1356 """
1357 pass
1357 pass
1358
1358
1359
1359
1360 class HTCondorControllerLauncher(HTCondorLauncher, BatchClusterAppMixin):
1360 class HTCondorControllerLauncher(HTCondorLauncher, BatchClusterAppMixin):
1361 """Launch a controller using HTCondor."""
1361 """Launch a controller using HTCondor."""
1362
1362
1363 batch_file_name = Unicode(u'htcondor_controller', config=True,
1363 batch_file_name = Unicode(u'htcondor_controller', config=True,
1364 help="batch file name for the controller job.")
1364 help="batch file name for the controller job.")
1365 default_template = Unicode(r"""
1365 default_template = Unicode(r"""
1366 universe = vanilla
1366 universe = vanilla
1367 executable = ipcontroller
1367 executable = ipcontroller
1368 # by default we expect a shared file system
1368 # by default we expect a shared file system
1369 transfer_executable = False
1369 transfer_executable = False
1370 arguments = --log-to-file '--profile-dir={profile_dir}' --cluster-id='{cluster_id}'
1370 arguments = --log-to-file '--profile-dir={profile_dir}' --cluster-id='{cluster_id}'
1371 """)
1371 """)
1372
1372
1373 def start(self):
1373 def start(self):
1374 """Start the controller by profile or profile_dir."""
1374 """Start the controller by profile or profile_dir."""
1375 return super(HTCondorControllerLauncher, self).start(1)
1375 return super(HTCondorControllerLauncher, self).start(1)
1376
1376
1377
1377
1378 class HTCondorEngineSetLauncher(HTCondorLauncher, BatchClusterAppMixin):
1378 class HTCondorEngineSetLauncher(HTCondorLauncher, BatchClusterAppMixin):
1379 """Launch Engines using HTCondor"""
1379 """Launch Engines using HTCondor"""
1380 batch_file_name = Unicode(u'htcondor_engines', config=True,
1380 batch_file_name = Unicode(u'htcondor_engines', config=True,
1381 help="batch file name for the engine(s) job.")
1381 help="batch file name for the engine(s) job.")
1382 default_template = Unicode("""
1382 default_template = Unicode("""
1383 universe = vanilla
1383 universe = vanilla
1384 executable = ipengine
1384 executable = ipengine
1385 # by default we expect a shared file system
1385 # by default we expect a shared file system
1386 transfer_executable = False
1386 transfer_executable = False
1387 arguments = "--log-to-file '--profile-dir={profile_dir}' '--cluster-id={cluster_id}'"
1387 arguments = "--log-to-file '--profile-dir={profile_dir}' '--cluster-id={cluster_id}'"
1388 """)
1388 """)
1389
1389
1390
1390
1391 #-----------------------------------------------------------------------------
1391 #-----------------------------------------------------------------------------
1392 # A launcher for ipcluster itself!
1392 # A launcher for ipcluster itself!
1393 #-----------------------------------------------------------------------------
1393 #-----------------------------------------------------------------------------
1394
1394
1395
1395
1396 class IPClusterLauncher(LocalProcessLauncher):
1396 class IPClusterLauncher(LocalProcessLauncher):
1397 """Launch the ipcluster program in an external process."""
1397 """Launch the ipcluster program in an external process."""
1398
1398
1399 ipcluster_cmd = List(ipcluster_cmd_argv, config=True,
1399 ipcluster_cmd = List(ipcluster_cmd_argv, config=True,
1400 help="Popen command for ipcluster")
1400 help="Popen command for ipcluster")
1401 ipcluster_args = List(
1401 ipcluster_args = List(
1402 ['--clean-logs=True', '--log-to-file', '--log-level=%i'%logging.INFO], config=True,
1402 ['--clean-logs=True', '--log-to-file', '--log-level=%i'%logging.INFO], config=True,
1403 help="Command line arguments to pass to ipcluster.")
1403 help="Command line arguments to pass to ipcluster.")
1404 ipcluster_subcommand = Unicode('start')
1404 ipcluster_subcommand = Unicode('start')
1405 profile = Unicode('default')
1405 profile = Unicode('default')
1406 n = Integer(2)
1406 n = Integer(2)
1407
1407
1408 def find_args(self):
1408 def find_args(self):
1409 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
1409 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
1410 ['--n=%i'%self.n, '--profile=%s'%self.profile] + \
1410 ['--n=%i'%self.n, '--profile=%s'%self.profile] + \
1411 self.ipcluster_args
1411 self.ipcluster_args
1412
1412
1413 def start(self):
1413 def start(self):
1414 return super(IPClusterLauncher, self).start()
1414 return super(IPClusterLauncher, self).start()
1415
1415
1416 #-----------------------------------------------------------------------------
1416 #-----------------------------------------------------------------------------
1417 # Collections of launchers
1417 # Collections of launchers
1418 #-----------------------------------------------------------------------------
1418 #-----------------------------------------------------------------------------
1419
1419
1420 local_launchers = [
1420 local_launchers = [
1421 LocalControllerLauncher,
1421 LocalControllerLauncher,
1422 LocalEngineLauncher,
1422 LocalEngineLauncher,
1423 LocalEngineSetLauncher,
1423 LocalEngineSetLauncher,
1424 ]
1424 ]
1425 mpi_launchers = [
1425 mpi_launchers = [
1426 MPILauncher,
1426 MPILauncher,
1427 MPIControllerLauncher,
1427 MPIControllerLauncher,
1428 MPIEngineSetLauncher,
1428 MPIEngineSetLauncher,
1429 ]
1429 ]
1430 ssh_launchers = [
1430 ssh_launchers = [
1431 SSHLauncher,
1431 SSHLauncher,
1432 SSHControllerLauncher,
1432 SSHControllerLauncher,
1433 SSHEngineLauncher,
1433 SSHEngineLauncher,
1434 SSHEngineSetLauncher,
1434 SSHEngineSetLauncher,
1435 SSHProxyEngineSetLauncher,
1435 SSHProxyEngineSetLauncher,
1436 ]
1436 ]
1437 winhpc_launchers = [
1437 winhpc_launchers = [
1438 WindowsHPCLauncher,
1438 WindowsHPCLauncher,
1439 WindowsHPCControllerLauncher,
1439 WindowsHPCControllerLauncher,
1440 WindowsHPCEngineSetLauncher,
1440 WindowsHPCEngineSetLauncher,
1441 ]
1441 ]
1442 pbs_launchers = [
1442 pbs_launchers = [
1443 PBSLauncher,
1443 PBSLauncher,
1444 PBSControllerLauncher,
1444 PBSControllerLauncher,
1445 PBSEngineSetLauncher,
1445 PBSEngineSetLauncher,
1446 ]
1446 ]
1447 sge_launchers = [
1447 sge_launchers = [
1448 SGELauncher,
1448 SGELauncher,
1449 SGEControllerLauncher,
1449 SGEControllerLauncher,
1450 SGEEngineSetLauncher,
1450 SGEEngineSetLauncher,
1451 ]
1451 ]
1452 lsf_launchers = [
1452 lsf_launchers = [
1453 LSFLauncher,
1453 LSFLauncher,
1454 LSFControllerLauncher,
1454 LSFControllerLauncher,
1455 LSFEngineSetLauncher,
1455 LSFEngineSetLauncher,
1456 ]
1456 ]
1457 htcondor_launchers = [
1457 htcondor_launchers = [
1458 HTCondorLauncher,
1458 HTCondorLauncher,
1459 HTCondorControllerLauncher,
1459 HTCondorControllerLauncher,
1460 HTCondorEngineSetLauncher,
1460 HTCondorEngineSetLauncher,
1461 ]
1461 ]
1462 all_launchers = local_launchers + mpi_launchers + ssh_launchers + winhpc_launchers\
1462 all_launchers = local_launchers + mpi_launchers + ssh_launchers + winhpc_launchers\
1463 + pbs_launchers + sge_launchers + lsf_launchers + htcondor_launchers
1463 + pbs_launchers + sge_launchers + lsf_launchers + htcondor_launchers
@@ -1,524 +1,524 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) recursively. This
8 calling this script (with different arguments) recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2009-2011 The IPython Development Team
18 # Copyright (C) 2009-2011 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 from __future__ import print_function
27 from __future__ import print_function
28
28
29 # Stdlib
29 # Stdlib
30 import glob
30 import glob
31 from io import BytesIO
31 from io import BytesIO
32 import os
32 import os
33 import os.path as path
33 import os.path as path
34 import sys
34 import sys
35 from threading import Thread, Lock, Event
35 from threading import Thread, Lock, Event
36 import warnings
36 import warnings
37
37
38 # Now, proceed to import nose itself
38 # Now, proceed to import nose itself
39 import nose.plugins.builtin
39 import nose.plugins.builtin
40 from nose.plugins.xunit import Xunit
40 from nose.plugins.xunit import Xunit
41 from nose import SkipTest
41 from nose import SkipTest
42 from nose.core import TestProgram
42 from nose.core import TestProgram
43 from nose.plugins import Plugin
43 from nose.plugins import Plugin
44 from nose.util import safe_str
44 from nose.util import safe_str
45
45
46 # Our own imports
46 # Our own imports
47 from IPython.utils.process import is_cmd_found
47 from IPython.utils.process import is_cmd_found
48 from IPython.utils.importstring import import_item
48 from IPython.utils.importstring import import_item
49 from IPython.testing.plugin.ipdoctest import IPythonDoctest
49 from IPython.testing.plugin.ipdoctest import IPythonDoctest
50 from IPython.external.decorators import KnownFailure, knownfailureif
50 from IPython.external.decorators import KnownFailure, knownfailureif
51
51
52 pjoin = path.join
52 pjoin = path.join
53
53
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Globals
56 # Globals
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59
59
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61 # Warnings control
61 # Warnings control
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63
63
64 # Twisted generates annoying warnings with Python 2.6, as will do other code
64 # Twisted generates annoying warnings with Python 2.6, as will do other code
65 # that imports 'sets' as of today
65 # that imports 'sets' as of today
66 warnings.filterwarnings('ignore', 'the sets module is deprecated',
66 warnings.filterwarnings('ignore', 'the sets module is deprecated',
67 DeprecationWarning )
67 DeprecationWarning )
68
68
69 # This one also comes from Twisted
69 # This one also comes from Twisted
70 warnings.filterwarnings('ignore', 'the sha module is deprecated',
70 warnings.filterwarnings('ignore', 'the sha module is deprecated',
71 DeprecationWarning)
71 DeprecationWarning)
72
72
73 # Wx on Fedora11 spits these out
73 # Wx on Fedora11 spits these out
74 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
74 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
75 UserWarning)
75 UserWarning)
76
76
77 # ------------------------------------------------------------------------------
77 # ------------------------------------------------------------------------------
78 # Monkeypatch Xunit to count known failures as skipped.
78 # Monkeypatch Xunit to count known failures as skipped.
79 # ------------------------------------------------------------------------------
79 # ------------------------------------------------------------------------------
80 def monkeypatch_xunit():
80 def monkeypatch_xunit():
81 try:
81 try:
82 knownfailureif(True)(lambda: None)()
82 knownfailureif(True)(lambda: None)()
83 except Exception as e:
83 except Exception as e:
84 KnownFailureTest = type(e)
84 KnownFailureTest = type(e)
85
85
86 def addError(self, test, err, capt=None):
86 def addError(self, test, err, capt=None):
87 if issubclass(err[0], KnownFailureTest):
87 if issubclass(err[0], KnownFailureTest):
88 err = (SkipTest,) + err[1:]
88 err = (SkipTest,) + err[1:]
89 return self.orig_addError(test, err, capt)
89 return self.orig_addError(test, err, capt)
90
90
91 Xunit.orig_addError = Xunit.addError
91 Xunit.orig_addError = Xunit.addError
92 Xunit.addError = addError
92 Xunit.addError = addError
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Check which dependencies are installed and greater than minimum version.
95 # Check which dependencies are installed and greater than minimum version.
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 def extract_version(mod):
97 def extract_version(mod):
98 return mod.__version__
98 return mod.__version__
99
99
100 def test_for(item, min_version=None, callback=extract_version):
100 def test_for(item, min_version=None, callback=extract_version):
101 """Test to see if item is importable, and optionally check against a minimum
101 """Test to see if item is importable, and optionally check against a minimum
102 version.
102 version.
103
103
104 If min_version is given, the default behavior is to check against the
104 If min_version is given, the default behavior is to check against the
105 `__version__` attribute of the item, but specifying `callback` allows you to
105 `__version__` attribute of the item, but specifying `callback` allows you to
106 extract the value you are interested in. e.g::
106 extract the value you are interested in. e.g::
107
107
108 In [1]: import sys
108 In [1]: import sys
109
109
110 In [2]: from IPython.testing.iptest import test_for
110 In [2]: from IPython.testing.iptest import test_for
111
111
112 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
112 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
113 Out[3]: True
113 Out[3]: True
114
114
115 """
115 """
116 try:
116 try:
117 check = import_item(item)
117 check = import_item(item)
118 except (ImportError, RuntimeError):
118 except (ImportError, RuntimeError):
119 # GTK reports Runtime error if it can't be initialized even if it's
119 # GTK reports Runtime error if it can't be initialized even if it's
120 # importable.
120 # importable.
121 return False
121 return False
122 else:
122 else:
123 if min_version:
123 if min_version:
124 if callback:
124 if callback:
125 # extra processing step to get version to compare
125 # extra processing step to get version to compare
126 check = callback(check)
126 check = callback(check)
127
127
128 return check >= min_version
128 return check >= min_version
129 else:
129 else:
130 return True
130 return True
131
131
132 # Global dict where we can store information on what we have and what we don't
132 # Global dict where we can store information on what we have and what we don't
133 # have available at test run time
133 # have available at test run time
134 have = {}
134 have = {}
135
135
136 have['curses'] = test_for('_curses')
136 have['curses'] = test_for('_curses')
137 have['matplotlib'] = test_for('matplotlib')
137 have['matplotlib'] = test_for('matplotlib')
138 have['numpy'] = test_for('numpy')
138 have['numpy'] = test_for('numpy')
139 have['pexpect'] = test_for('IPython.external.pexpect')
139 have['pexpect'] = test_for('IPython.external.pexpect')
140 have['pymongo'] = test_for('pymongo')
140 have['pymongo'] = test_for('pymongo')
141 have['pygments'] = test_for('pygments')
141 have['pygments'] = test_for('pygments')
142 have['qt'] = test_for('IPython.external.qt')
142 have['qt'] = test_for('IPython.external.qt')
143 have['rpy2'] = test_for('rpy2')
143 have['rpy2'] = test_for('rpy2')
144 have['sqlite3'] = test_for('sqlite3')
144 have['sqlite3'] = test_for('sqlite3')
145 have['cython'] = test_for('Cython')
145 have['cython'] = test_for('Cython')
146 have['oct2py'] = test_for('oct2py')
146 have['oct2py'] = test_for('oct2py')
147 have['tornado'] = test_for('tornado.version_info', (3,1,0), callback=None)
147 have['tornado'] = test_for('tornado.version_info', (3,1,0), callback=None)
148 have['jinja2'] = test_for('jinja2')
148 have['jinja2'] = test_for('jinja2')
149 have['requests'] = test_for('requests')
149 have['requests'] = test_for('requests')
150 have['sphinx'] = test_for('sphinx')
150 have['sphinx'] = test_for('sphinx')
151 have['casperjs'] = is_cmd_found('casperjs')
151 have['casperjs'] = is_cmd_found('casperjs')
152
152
153 min_zmq = (2,1,11)
153 min_zmq = (2,1,11)
154
154
155 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
155 have['zmq'] = test_for('zmq.pyzmq_version_info', min_zmq, callback=lambda x: x())
156
156
157 #-----------------------------------------------------------------------------
157 #-----------------------------------------------------------------------------
158 # Test suite definitions
158 # Test suite definitions
159 #-----------------------------------------------------------------------------
159 #-----------------------------------------------------------------------------
160
160
161 test_group_names = ['parallel', 'kernel', 'kernel.inprocess', 'config', 'core',
161 test_group_names = ['parallel', 'kernel', 'kernel.inprocess', 'config', 'core',
162 'extensions', 'lib', 'terminal', 'testing', 'utils',
162 'extensions', 'lib', 'terminal', 'testing', 'utils',
163 'nbformat', 'qt', 'html', 'nbconvert'
163 'nbformat', 'qt', 'html', 'nbconvert'
164 ]
164 ]
165
165
166 class TestSection(object):
166 class TestSection(object):
167 def __init__(self, name, includes):
167 def __init__(self, name, includes):
168 self.name = name
168 self.name = name
169 self.includes = includes
169 self.includes = includes
170 self.excludes = []
170 self.excludes = []
171 self.dependencies = []
171 self.dependencies = []
172 self.enabled = True
172 self.enabled = True
173
173
174 def exclude(self, module):
174 def exclude(self, module):
175 if not module.startswith('IPython'):
175 if not module.startswith('IPython'):
176 module = self.includes[0] + "." + module
176 module = self.includes[0] + "." + module
177 self.excludes.append(module.replace('.', os.sep))
177 self.excludes.append(module.replace('.', os.sep))
178
178
179 def requires(self, *packages):
179 def requires(self, *packages):
180 self.dependencies.extend(packages)
180 self.dependencies.extend(packages)
181
181
182 @property
182 @property
183 def will_run(self):
183 def will_run(self):
184 return self.enabled and all(have[p] for p in self.dependencies)
184 return self.enabled and all(have[p] for p in self.dependencies)
185
185
186 # Name -> (include, exclude, dependencies_met)
186 # Name -> (include, exclude, dependencies_met)
187 test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
187 test_sections = {n:TestSection(n, ['IPython.%s' % n]) for n in test_group_names}
188
188
189 # Exclusions and dependencies
189 # Exclusions and dependencies
190 # ---------------------------
190 # ---------------------------
191
191
192 # core:
192 # core:
193 sec = test_sections['core']
193 sec = test_sections['core']
194 if not have['sqlite3']:
194 if not have['sqlite3']:
195 sec.exclude('tests.test_history')
195 sec.exclude('tests.test_history')
196 sec.exclude('history')
196 sec.exclude('history')
197 if not have['matplotlib']:
197 if not have['matplotlib']:
198 sec.exclude('pylabtools'),
198 sec.exclude('pylabtools'),
199 sec.exclude('tests.test_pylabtools')
199 sec.exclude('tests.test_pylabtools')
200
200
201 # lib:
201 # lib:
202 sec = test_sections['lib']
202 sec = test_sections['lib']
203 if not have['zmq']:
203 if not have['zmq']:
204 sec.exclude('kernel')
204 sec.exclude('kernel')
205 # We do this unconditionally, so that the test suite doesn't import
205 # We do this unconditionally, so that the test suite doesn't import
206 # gtk, changing the default encoding and masking some unicode bugs.
206 # gtk, changing the default encoding and masking some unicode bugs.
207 sec.exclude('inputhookgtk')
207 sec.exclude('inputhookgtk')
208 # We also do this unconditionally, because wx can interfere with Unix signals.
208 # We also do this unconditionally, because wx can interfere with Unix signals.
209 # There are currently no tests for it anyway.
209 # There are currently no tests for it anyway.
210 sec.exclude('inputhookwx')
210 sec.exclude('inputhookwx')
211 # Testing inputhook will need a lot of thought, to figure out
211 # Testing inputhook will need a lot of thought, to figure out
212 # how to have tests that don't lock up with the gui event
212 # how to have tests that don't lock up with the gui event
213 # loops in the picture
213 # loops in the picture
214 sec.exclude('inputhook')
214 sec.exclude('inputhook')
215
215
216 # testing:
216 # testing:
217 sec = test_sections['testing']
217 sec = test_sections['testing']
218 # These have to be skipped on win32 because they use echo, rm, cd, etc.
218 # These have to be skipped on win32 because they use echo, rm, cd, etc.
219 # See ticket https://github.com/ipython/ipython/issues/87
219 # See ticket https://github.com/ipython/ipython/issues/87
220 if sys.platform == 'win32':
220 if sys.platform == 'win32':
221 sec.exclude('plugin.test_exampleip')
221 sec.exclude('plugin.test_exampleip')
222 sec.exclude('plugin.dtexample')
222 sec.exclude('plugin.dtexample')
223
223
224 # terminal:
224 # terminal:
225 if (not have['pexpect']) or (not have['zmq']):
225 if (not have['pexpect']) or (not have['zmq']):
226 test_sections['terminal'].exclude('console')
226 test_sections['terminal'].exclude('console')
227
227
228 # parallel
228 # parallel
229 sec = test_sections['parallel']
229 sec = test_sections['parallel']
230 sec.requires('zmq')
230 sec.requires('zmq')
231 if not have['pymongo']:
231 if not have['pymongo']:
232 sec.exclude('controller.mongodb')
232 sec.exclude('controller.mongodb')
233 sec.exclude('tests.test_mongodb')
233 sec.exclude('tests.test_mongodb')
234
234
235 # kernel:
235 # kernel:
236 sec = test_sections['kernel']
236 sec = test_sections['kernel']
237 sec.requires('zmq')
237 sec.requires('zmq')
238 # The in-process kernel tests are done in a separate section
238 # The in-process kernel tests are done in a separate section
239 sec.exclude('inprocess')
239 sec.exclude('inprocess')
240 # importing gtk sets the default encoding, which we want to avoid
240 # importing gtk sets the default encoding, which we want to avoid
241 sec.exclude('zmq.gui.gtkembed')
241 sec.exclude('zmq.gui.gtkembed')
242 if not have['matplotlib']:
242 if not have['matplotlib']:
243 sec.exclude('zmq.pylab')
243 sec.exclude('zmq.pylab')
244
244
245 # kernel.inprocess:
245 # kernel.inprocess:
246 test_sections['kernel.inprocess'].requires('zmq')
246 test_sections['kernel.inprocess'].requires('zmq')
247
247
248 # extensions:
248 # extensions:
249 sec = test_sections['extensions']
249 sec = test_sections['extensions']
250 if not have['cython']:
250 if not have['cython']:
251 sec.exclude('cythonmagic')
251 sec.exclude('cythonmagic')
252 sec.exclude('tests.test_cythonmagic')
252 sec.exclude('tests.test_cythonmagic')
253 if not have['oct2py']:
253 if not have['oct2py']:
254 sec.exclude('octavemagic')
254 sec.exclude('octavemagic')
255 sec.exclude('tests.test_octavemagic')
255 sec.exclude('tests.test_octavemagic')
256 if not have['rpy2'] or not have['numpy']:
256 if not have['rpy2'] or not have['numpy']:
257 sec.exclude('rmagic')
257 sec.exclude('rmagic')
258 sec.exclude('tests.test_rmagic')
258 sec.exclude('tests.test_rmagic')
259 # autoreload does some strange stuff, so move it to its own test section
259 # autoreload does some strange stuff, so move it to its own test section
260 sec.exclude('autoreload')
260 sec.exclude('autoreload')
261 sec.exclude('tests.test_autoreload')
261 sec.exclude('tests.test_autoreload')
262 test_sections['autoreload'] = TestSection('autoreload',
262 test_sections['autoreload'] = TestSection('autoreload',
263 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
263 ['IPython.extensions.autoreload', 'IPython.extensions.tests.test_autoreload'])
264 test_group_names.append('autoreload')
264 test_group_names.append('autoreload')
265
265
266 # qt:
266 # qt:
267 test_sections['qt'].requires('zmq', 'qt', 'pygments')
267 test_sections['qt'].requires('zmq', 'qt', 'pygments')
268
268
269 # html:
269 # html:
270 sec = test_sections['html']
270 sec = test_sections['html']
271 sec.requires('zmq', 'tornado', 'requests')
271 sec.requires('zmq', 'tornado', 'requests', 'sqlite3')
272 # The notebook 'static' directory contains JS, css and other
272 # The notebook 'static' directory contains JS, css and other
273 # files for web serving. Occasionally projects may put a .py
273 # files for web serving. Occasionally projects may put a .py
274 # file in there (MathJax ships a conf.py), so we might as
274 # file in there (MathJax ships a conf.py), so we might as
275 # well play it safe and skip the whole thing.
275 # well play it safe and skip the whole thing.
276 sec.exclude('static')
276 sec.exclude('static')
277 sec.exclude('fabfile')
277 sec.exclude('fabfile')
278 if not have['jinja2']:
278 if not have['jinja2']:
279 sec.exclude('notebookapp')
279 sec.exclude('notebookapp')
280 if not have['pygments'] or not have['jinja2']:
280 if not have['pygments'] or not have['jinja2']:
281 sec.exclude('nbconvert')
281 sec.exclude('nbconvert')
282
282
283 # config:
283 # config:
284 # Config files aren't really importable stand-alone
284 # Config files aren't really importable stand-alone
285 test_sections['config'].exclude('profile')
285 test_sections['config'].exclude('profile')
286
286
287 # nbconvert:
287 # nbconvert:
288 sec = test_sections['nbconvert']
288 sec = test_sections['nbconvert']
289 sec.requires('pygments', 'jinja2')
289 sec.requires('pygments', 'jinja2')
290 # Exclude nbconvert directories containing config files used to test.
290 # Exclude nbconvert directories containing config files used to test.
291 # Executing the config files with iptest would cause an exception.
291 # Executing the config files with iptest would cause an exception.
292 sec.exclude('tests.files')
292 sec.exclude('tests.files')
293 sec.exclude('exporters.tests.files')
293 sec.exclude('exporters.tests.files')
294 if not have['tornado']:
294 if not have['tornado']:
295 sec.exclude('nbconvert.post_processors.serve')
295 sec.exclude('nbconvert.post_processors.serve')
296 sec.exclude('nbconvert.post_processors.tests.test_serve')
296 sec.exclude('nbconvert.post_processors.tests.test_serve')
297
297
298 #-----------------------------------------------------------------------------
298 #-----------------------------------------------------------------------------
299 # Functions and classes
299 # Functions and classes
300 #-----------------------------------------------------------------------------
300 #-----------------------------------------------------------------------------
301
301
302 def check_exclusions_exist():
302 def check_exclusions_exist():
303 from IPython.utils.path import get_ipython_package_dir
303 from IPython.utils.path import get_ipython_package_dir
304 from IPython.utils.warn import warn
304 from IPython.utils.warn import warn
305 parent = os.path.dirname(get_ipython_package_dir())
305 parent = os.path.dirname(get_ipython_package_dir())
306 for sec in test_sections:
306 for sec in test_sections:
307 for pattern in sec.exclusions:
307 for pattern in sec.exclusions:
308 fullpath = pjoin(parent, pattern)
308 fullpath = pjoin(parent, pattern)
309 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
309 if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
310 warn("Excluding nonexistent file: %r" % pattern)
310 warn("Excluding nonexistent file: %r" % pattern)
311
311
312
312
313 class ExclusionPlugin(Plugin):
313 class ExclusionPlugin(Plugin):
314 """A nose plugin to effect our exclusions of files and directories.
314 """A nose plugin to effect our exclusions of files and directories.
315 """
315 """
316 name = 'exclusions'
316 name = 'exclusions'
317 score = 3000 # Should come before any other plugins
317 score = 3000 # Should come before any other plugins
318
318
319 def __init__(self, exclude_patterns=None):
319 def __init__(self, exclude_patterns=None):
320 """
320 """
321 Parameters
321 Parameters
322 ----------
322 ----------
323
323
324 exclude_patterns : sequence of strings, optional
324 exclude_patterns : sequence of strings, optional
325 Filenames containing these patterns (as raw strings, not as regular
325 Filenames containing these patterns (as raw strings, not as regular
326 expressions) are excluded from the tests.
326 expressions) are excluded from the tests.
327 """
327 """
328 self.exclude_patterns = exclude_patterns or []
328 self.exclude_patterns = exclude_patterns or []
329 super(ExclusionPlugin, self).__init__()
329 super(ExclusionPlugin, self).__init__()
330
330
331 def options(self, parser, env=os.environ):
331 def options(self, parser, env=os.environ):
332 Plugin.options(self, parser, env)
332 Plugin.options(self, parser, env)
333
333
334 def configure(self, options, config):
334 def configure(self, options, config):
335 Plugin.configure(self, options, config)
335 Plugin.configure(self, options, config)
336 # Override nose trying to disable plugin.
336 # Override nose trying to disable plugin.
337 self.enabled = True
337 self.enabled = True
338
338
339 def wantFile(self, filename):
339 def wantFile(self, filename):
340 """Return whether the given filename should be scanned for tests.
340 """Return whether the given filename should be scanned for tests.
341 """
341 """
342 if any(pat in filename for pat in self.exclude_patterns):
342 if any(pat in filename for pat in self.exclude_patterns):
343 return False
343 return False
344 return None
344 return None
345
345
346 def wantDirectory(self, directory):
346 def wantDirectory(self, directory):
347 """Return whether the given directory should be scanned for tests.
347 """Return whether the given directory should be scanned for tests.
348 """
348 """
349 if any(pat in directory for pat in self.exclude_patterns):
349 if any(pat in directory for pat in self.exclude_patterns):
350 return False
350 return False
351 return None
351 return None
352
352
353
353
354 class StreamCapturer(Thread):
354 class StreamCapturer(Thread):
355 daemon = True # Don't hang if main thread crashes
355 daemon = True # Don't hang if main thread crashes
356 started = False
356 started = False
357 def __init__(self):
357 def __init__(self):
358 super(StreamCapturer, self).__init__()
358 super(StreamCapturer, self).__init__()
359 self.streams = []
359 self.streams = []
360 self.buffer = BytesIO()
360 self.buffer = BytesIO()
361 self.readfd, self.writefd = os.pipe()
361 self.readfd, self.writefd = os.pipe()
362 self.buffer_lock = Lock()
362 self.buffer_lock = Lock()
363 self.stop = Event()
363 self.stop = Event()
364
364
365 def run(self):
365 def run(self):
366 self.started = True
366 self.started = True
367
367
368 while not self.stop.is_set():
368 while not self.stop.is_set():
369 chunk = os.read(self.readfd, 1024)
369 chunk = os.read(self.readfd, 1024)
370
370
371 with self.buffer_lock:
371 with self.buffer_lock:
372 self.buffer.write(chunk)
372 self.buffer.write(chunk)
373
373
374 os.close(self.readfd)
374 os.close(self.readfd)
375 os.close(self.writefd)
375 os.close(self.writefd)
376
376
377 def reset_buffer(self):
377 def reset_buffer(self):
378 with self.buffer_lock:
378 with self.buffer_lock:
379 self.buffer.truncate(0)
379 self.buffer.truncate(0)
380 self.buffer.seek(0)
380 self.buffer.seek(0)
381
381
382 def get_buffer(self):
382 def get_buffer(self):
383 with self.buffer_lock:
383 with self.buffer_lock:
384 return self.buffer.getvalue()
384 return self.buffer.getvalue()
385
385
386 def ensure_started(self):
386 def ensure_started(self):
387 if not self.started:
387 if not self.started:
388 self.start()
388 self.start()
389
389
390 def halt(self):
390 def halt(self):
391 """Safely stop the thread."""
391 """Safely stop the thread."""
392 if not self.started:
392 if not self.started:
393 return
393 return
394
394
395 self.stop.set()
395 self.stop.set()
396 os.write(self.writefd, b'wake up') # Ensure we're not locked in a read()
396 os.write(self.writefd, b'wake up') # Ensure we're not locked in a read()
397 self.join()
397 self.join()
398
398
399 class SubprocessStreamCapturePlugin(Plugin):
399 class SubprocessStreamCapturePlugin(Plugin):
400 name='subprocstreams'
400 name='subprocstreams'
401 def __init__(self):
401 def __init__(self):
402 Plugin.__init__(self)
402 Plugin.__init__(self)
403 self.stream_capturer = StreamCapturer()
403 self.stream_capturer = StreamCapturer()
404 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
404 self.destination = os.environ.get('IPTEST_SUBPROC_STREAMS', 'capture')
405 # This is ugly, but distant parts of the test machinery need to be able
405 # This is ugly, but distant parts of the test machinery need to be able
406 # to redirect streams, so we make the object globally accessible.
406 # to redirect streams, so we make the object globally accessible.
407 nose.iptest_stdstreams_fileno = self.get_write_fileno
407 nose.iptest_stdstreams_fileno = self.get_write_fileno
408
408
409 def get_write_fileno(self):
409 def get_write_fileno(self):
410 if self.destination == 'capture':
410 if self.destination == 'capture':
411 self.stream_capturer.ensure_started()
411 self.stream_capturer.ensure_started()
412 return self.stream_capturer.writefd
412 return self.stream_capturer.writefd
413 elif self.destination == 'discard':
413 elif self.destination == 'discard':
414 return os.open(os.devnull, os.O_WRONLY)
414 return os.open(os.devnull, os.O_WRONLY)
415 else:
415 else:
416 return sys.__stdout__.fileno()
416 return sys.__stdout__.fileno()
417
417
418 def configure(self, options, config):
418 def configure(self, options, config):
419 Plugin.configure(self, options, config)
419 Plugin.configure(self, options, config)
420 # Override nose trying to disable plugin.
420 # Override nose trying to disable plugin.
421 if self.destination == 'capture':
421 if self.destination == 'capture':
422 self.enabled = True
422 self.enabled = True
423
423
424 def startTest(self, test):
424 def startTest(self, test):
425 # Reset log capture
425 # Reset log capture
426 self.stream_capturer.reset_buffer()
426 self.stream_capturer.reset_buffer()
427
427
428 def formatFailure(self, test, err):
428 def formatFailure(self, test, err):
429 # Show output
429 # Show output
430 ec, ev, tb = err
430 ec, ev, tb = err
431 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
431 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
432 if captured.strip():
432 if captured.strip():
433 ev = safe_str(ev)
433 ev = safe_str(ev)
434 out = [ev, '>> begin captured subprocess output <<',
434 out = [ev, '>> begin captured subprocess output <<',
435 captured,
435 captured,
436 '>> end captured subprocess output <<']
436 '>> end captured subprocess output <<']
437 return ec, '\n'.join(out), tb
437 return ec, '\n'.join(out), tb
438
438
439 return err
439 return err
440
440
441 formatError = formatFailure
441 formatError = formatFailure
442
442
443 def finalize(self, result):
443 def finalize(self, result):
444 self.stream_capturer.halt()
444 self.stream_capturer.halt()
445
445
446
446
447 def run_iptest():
447 def run_iptest():
448 """Run the IPython test suite using nose.
448 """Run the IPython test suite using nose.
449
449
450 This function is called when this script is **not** called with the form
450 This function is called when this script is **not** called with the form
451 `iptest all`. It simply calls nose with appropriate command line flags
451 `iptest all`. It simply calls nose with appropriate command line flags
452 and accepts all of the standard nose arguments.
452 and accepts all of the standard nose arguments.
453 """
453 """
454 # Apply our monkeypatch to Xunit
454 # Apply our monkeypatch to Xunit
455 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
455 if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'):
456 monkeypatch_xunit()
456 monkeypatch_xunit()
457
457
458 warnings.filterwarnings('ignore',
458 warnings.filterwarnings('ignore',
459 'This will be removed soon. Use IPython.testing.util instead')
459 'This will be removed soon. Use IPython.testing.util instead')
460
460
461 arg1 = sys.argv[1]
461 arg1 = sys.argv[1]
462 if arg1 in test_sections:
462 if arg1 in test_sections:
463 section = test_sections[arg1]
463 section = test_sections[arg1]
464 sys.argv[1:2] = section.includes
464 sys.argv[1:2] = section.includes
465 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
465 elif arg1.startswith('IPython.') and arg1[8:] in test_sections:
466 section = test_sections[arg1[8:]]
466 section = test_sections[arg1[8:]]
467 sys.argv[1:2] = section.includes
467 sys.argv[1:2] = section.includes
468 else:
468 else:
469 section = TestSection(arg1, includes=[arg1])
469 section = TestSection(arg1, includes=[arg1])
470
470
471
471
472 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
472 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
473
473
474 '--with-ipdoctest',
474 '--with-ipdoctest',
475 '--ipdoctest-tests','--ipdoctest-extension=txt',
475 '--ipdoctest-tests','--ipdoctest-extension=txt',
476
476
477 # We add --exe because of setuptools' imbecility (it
477 # We add --exe because of setuptools' imbecility (it
478 # blindly does chmod +x on ALL files). Nose does the
478 # blindly does chmod +x on ALL files). Nose does the
479 # right thing and it tries to avoid executables,
479 # right thing and it tries to avoid executables,
480 # setuptools unfortunately forces our hand here. This
480 # setuptools unfortunately forces our hand here. This
481 # has been discussed on the distutils list and the
481 # has been discussed on the distutils list and the
482 # setuptools devs refuse to fix this problem!
482 # setuptools devs refuse to fix this problem!
483 '--exe',
483 '--exe',
484 ]
484 ]
485 if '-a' not in argv and '-A' not in argv:
485 if '-a' not in argv and '-A' not in argv:
486 argv = argv + ['-a', '!crash']
486 argv = argv + ['-a', '!crash']
487
487
488 if nose.__version__ >= '0.11':
488 if nose.__version__ >= '0.11':
489 # I don't fully understand why we need this one, but depending on what
489 # I don't fully understand why we need this one, but depending on what
490 # directory the test suite is run from, if we don't give it, 0 tests
490 # directory the test suite is run from, if we don't give it, 0 tests
491 # get run. Specifically, if the test suite is run from the source dir
491 # get run. Specifically, if the test suite is run from the source dir
492 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
492 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
493 # even if the same call done in this directory works fine). It appears
493 # even if the same call done in this directory works fine). It appears
494 # that if the requested package is in the current dir, nose bails early
494 # that if the requested package is in the current dir, nose bails early
495 # by default. Since it's otherwise harmless, leave it in by default
495 # by default. Since it's otherwise harmless, leave it in by default
496 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
496 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
497 argv.append('--traverse-namespace')
497 argv.append('--traverse-namespace')
498
498
499 # use our plugin for doctesting. It will remove the standard doctest plugin
499 # use our plugin for doctesting. It will remove the standard doctest plugin
500 # if it finds it enabled
500 # if it finds it enabled
501 plugins = [ExclusionPlugin(section.excludes), IPythonDoctest(), KnownFailure(),
501 plugins = [ExclusionPlugin(section.excludes), IPythonDoctest(), KnownFailure(),
502 SubprocessStreamCapturePlugin() ]
502 SubprocessStreamCapturePlugin() ]
503
503
504 # Use working directory set by parent process (see iptestcontroller)
504 # Use working directory set by parent process (see iptestcontroller)
505 if 'IPTEST_WORKING_DIR' in os.environ:
505 if 'IPTEST_WORKING_DIR' in os.environ:
506 os.chdir(os.environ['IPTEST_WORKING_DIR'])
506 os.chdir(os.environ['IPTEST_WORKING_DIR'])
507
507
508 # We need a global ipython running in this process, but the special
508 # We need a global ipython running in this process, but the special
509 # in-process group spawns its own IPython kernels, so for *that* group we
509 # in-process group spawns its own IPython kernels, so for *that* group we
510 # must avoid also opening the global one (otherwise there's a conflict of
510 # must avoid also opening the global one (otherwise there's a conflict of
511 # singletons). Ultimately the solution to this problem is to refactor our
511 # singletons). Ultimately the solution to this problem is to refactor our
512 # assumptions about what needs to be a singleton and what doesn't (app
512 # assumptions about what needs to be a singleton and what doesn't (app
513 # objects should, individual shells shouldn't). But for now, this
513 # objects should, individual shells shouldn't). But for now, this
514 # workaround allows the test suite for the inprocess module to complete.
514 # workaround allows the test suite for the inprocess module to complete.
515 if 'kernel.inprocess' not in section.name:
515 if 'kernel.inprocess' not in section.name:
516 from IPython.testing import globalipapp
516 from IPython.testing import globalipapp
517 globalipapp.start_ipython()
517 globalipapp.start_ipython()
518
518
519 # Now nose can run
519 # Now nose can run
520 TestProgram(argv=argv, addplugins=plugins)
520 TestProgram(argv=argv, addplugins=plugins)
521
521
522 if __name__ == '__main__':
522 if __name__ == '__main__':
523 run_iptest()
523 run_iptest()
524
524
@@ -1,569 +1,592 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Process Controller
2 """IPython Test Process Controller
3
3
4 This module runs one or more subprocesses which will actually run the IPython
4 This module runs one or more subprocesses which will actually run the IPython
5 test suite.
5 test suite.
6
6
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2009-2011 The IPython Development Team
10 # Copyright (C) 2009-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 from __future__ import print_function
19 from __future__ import print_function
20
20
21 import argparse
21 import argparse
22 import json
22 import multiprocessing.pool
23 import multiprocessing.pool
23 from multiprocessing import Process, Queue
24 import os
24 import os
25 import shutil
25 import shutil
26 import signal
26 import signal
27 import sys
27 import sys
28 import subprocess
28 import subprocess
29 import time
29 import time
30
30
31 from .iptest import have, test_group_names as py_test_group_names, test_sections
31 from .iptest import have, test_group_names as py_test_group_names, test_sections, StreamCapturer
32 from IPython.utils.path import compress_user
32 from IPython.utils.path import compress_user
33 from IPython.utils.py3compat import bytes_to_str
33 from IPython.utils.py3compat import bytes_to_str
34 from IPython.utils.sysinfo import get_sys_info
34 from IPython.utils.sysinfo import get_sys_info
35 from IPython.utils.tempdir import TemporaryDirectory
35 from IPython.utils.tempdir import TemporaryDirectory
36
36
37
37
38 class TestController(object):
38 class TestController(object):
39 """Run tests in a subprocess
39 """Run tests in a subprocess
40 """
40 """
41 #: str, IPython test suite to be executed.
41 #: str, IPython test suite to be executed.
42 section = None
42 section = None
43 #: list, command line arguments to be executed
43 #: list, command line arguments to be executed
44 cmd = None
44 cmd = None
45 #: dict, extra environment variables to set for the subprocess
45 #: dict, extra environment variables to set for the subprocess
46 env = None
46 env = None
47 #: list, TemporaryDirectory instances to clear up when the process finishes
47 #: list, TemporaryDirectory instances to clear up when the process finishes
48 dirs = None
48 dirs = None
49 #: subprocess.Popen instance
49 #: subprocess.Popen instance
50 process = None
50 process = None
51 #: str, process stdout+stderr
51 #: str, process stdout+stderr
52 stdout = None
52 stdout = None
53
53
54 def __init__(self):
54 def __init__(self):
55 self.cmd = []
55 self.cmd = []
56 self.env = {}
56 self.env = {}
57 self.dirs = []
57 self.dirs = []
58
58
59 def setup(self):
59 def setup(self):
60 """Create temporary directories etc.
60 """Create temporary directories etc.
61
61
62 This is only called when we know the test group will be run. Things
62 This is only called when we know the test group will be run. Things
63 created here may be cleaned up by self.cleanup().
63 created here may be cleaned up by self.cleanup().
64 """
64 """
65 pass
65 pass
66
66
67 def launch(self, buffer_output=False):
67 def launch(self, buffer_output=False):
68 # print('*** ENV:', self.env) # dbg
68 # print('*** ENV:', self.env) # dbg
69 # print('*** CMD:', self.cmd) # dbg
69 # print('*** CMD:', self.cmd) # dbg
70 env = os.environ.copy()
70 env = os.environ.copy()
71 env.update(self.env)
71 env.update(self.env)
72 output = subprocess.PIPE if buffer_output else None
72 output = subprocess.PIPE if buffer_output else None
73 stdout = subprocess.STDOUT if buffer_output else None
73 stdout = subprocess.STDOUT if buffer_output else None
74 self.process = subprocess.Popen(self.cmd, stdout=output,
74 self.process = subprocess.Popen(self.cmd, stdout=output,
75 stderr=stdout, env=env)
75 stderr=stdout, env=env)
76
76
77 def wait(self):
77 def wait(self):
78 self.stdout, _ = self.process.communicate()
78 self.stdout, _ = self.process.communicate()
79 return self.process.returncode
79 return self.process.returncode
80
80
81 def print_extra_info(self):
81 def print_extra_info(self):
82 """Print extra information about this test run.
82 """Print extra information about this test run.
83
83
84 If we're running in parallel and showing the concise view, this is only
84 If we're running in parallel and showing the concise view, this is only
85 called if the test group fails. Otherwise, it's called before the test
85 called if the test group fails. Otherwise, it's called before the test
86 group is started.
86 group is started.
87
87
88 The base implementation does nothing, but it can be overridden by
88 The base implementation does nothing, but it can be overridden by
89 subclasses.
89 subclasses.
90 """
90 """
91 return
91 return
92
92
93 def cleanup_process(self):
93 def cleanup_process(self):
94 """Cleanup on exit by killing any leftover processes."""
94 """Cleanup on exit by killing any leftover processes."""
95 subp = self.process
95 subp = self.process
96 if subp is None or (subp.poll() is not None):
96 if subp is None or (subp.poll() is not None):
97 return # Process doesn't exist, or is already dead.
97 return # Process doesn't exist, or is already dead.
98
98
99 try:
99 try:
100 print('Cleaning up stale PID: %d' % subp.pid)
100 print('Cleaning up stale PID: %d' % subp.pid)
101 subp.kill()
101 subp.kill()
102 except: # (OSError, WindowsError) ?
102 except: # (OSError, WindowsError) ?
103 # This is just a best effort, if we fail or the process was
103 # This is just a best effort, if we fail or the process was
104 # really gone, ignore it.
104 # really gone, ignore it.
105 pass
105 pass
106 else:
106 else:
107 for i in range(10):
107 for i in range(10):
108 if subp.poll() is None:
108 if subp.poll() is None:
109 time.sleep(0.1)
109 time.sleep(0.1)
110 else:
110 else:
111 break
111 break
112
112
113 if subp.poll() is None:
113 if subp.poll() is None:
114 # The process did not die...
114 # The process did not die...
115 print('... failed. Manual cleanup may be required.')
115 print('... failed. Manual cleanup may be required.')
116
116
117 def cleanup(self):
117 def cleanup(self):
118 "Kill process if it's still alive, and clean up temporary directories"
118 "Kill process if it's still alive, and clean up temporary directories"
119 self.cleanup_process()
119 self.cleanup_process()
120 for td in self.dirs:
120 for td in self.dirs:
121 td.cleanup()
121 td.cleanup()
122
122
123 __del__ = cleanup
123 __del__ = cleanup
124
124
125 class PyTestController(TestController):
125 class PyTestController(TestController):
126 """Run Python tests using IPython.testing.iptest"""
126 """Run Python tests using IPython.testing.iptest"""
127 #: str, Python command to execute in subprocess
127 #: str, Python command to execute in subprocess
128 pycmd = None
128 pycmd = None
129
129
130 def __init__(self, section):
130 def __init__(self, section, options):
131 """Create new test runner."""
131 """Create new test runner."""
132 TestController.__init__(self)
132 TestController.__init__(self)
133 self.section = section
133 self.section = section
134 # pycmd is put into cmd[2] in PyTestController.launch()
134 # pycmd is put into cmd[2] in PyTestController.launch()
135 self.cmd = [sys.executable, '-c', None, section]
135 self.cmd = [sys.executable, '-c', None, section]
136 self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
136 self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
137 self.options = options
137
138
138 def setup(self):
139 def setup(self):
139 ipydir = TemporaryDirectory()
140 ipydir = TemporaryDirectory()
140 self.dirs.append(ipydir)
141 self.dirs.append(ipydir)
141 self.env['IPYTHONDIR'] = ipydir.name
142 self.env['IPYTHONDIR'] = ipydir.name
142 self.workingdir = workingdir = TemporaryDirectory()
143 self.workingdir = workingdir = TemporaryDirectory()
143 self.dirs.append(workingdir)
144 self.dirs.append(workingdir)
144 self.env['IPTEST_WORKING_DIR'] = workingdir.name
145 self.env['IPTEST_WORKING_DIR'] = workingdir.name
145 # This means we won't get odd effects from our own matplotlib config
146 # This means we won't get odd effects from our own matplotlib config
146 self.env['MPLCONFIGDIR'] = workingdir.name
147 self.env['MPLCONFIGDIR'] = workingdir.name
147
148
149 # From options:
150 if self.options.xunit:
151 self.add_xunit()
152 if self.options.coverage:
153 self.add_coverage()
154 self.env['IPTEST_SUBPROC_STREAMS'] = self.options.subproc_streams
155 self.cmd.extend(self.options.extra_args)
156
148 @property
157 @property
149 def will_run(self):
158 def will_run(self):
150 try:
159 try:
151 return test_sections[self.section].will_run
160 return test_sections[self.section].will_run
152 except KeyError:
161 except KeyError:
153 return True
162 return True
154
163
155 def add_xunit(self):
164 def add_xunit(self):
156 xunit_file = os.path.abspath(self.section + '.xunit.xml')
165 xunit_file = os.path.abspath(self.section + '.xunit.xml')
157 self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
166 self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
158
167
159 def add_coverage(self):
168 def add_coverage(self):
160 try:
169 try:
161 sources = test_sections[self.section].includes
170 sources = test_sections[self.section].includes
162 except KeyError:
171 except KeyError:
163 sources = ['IPython']
172 sources = ['IPython']
164
173
165 coverage_rc = ("[run]\n"
174 coverage_rc = ("[run]\n"
166 "data_file = {data_file}\n"
175 "data_file = {data_file}\n"
167 "source =\n"
176 "source =\n"
168 " {source}\n"
177 " {source}\n"
169 ).format(data_file=os.path.abspath('.coverage.'+self.section),
178 ).format(data_file=os.path.abspath('.coverage.'+self.section),
170 source="\n ".join(sources))
179 source="\n ".join(sources))
171 config_file = os.path.join(self.workingdir.name, '.coveragerc')
180 config_file = os.path.join(self.workingdir.name, '.coveragerc')
172 with open(config_file, 'w') as f:
181 with open(config_file, 'w') as f:
173 f.write(coverage_rc)
182 f.write(coverage_rc)
174
183
175 self.env['COVERAGE_PROCESS_START'] = config_file
184 self.env['COVERAGE_PROCESS_START'] = config_file
176 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
185 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
177
186
178 def launch(self, buffer_output=False):
187 def launch(self, buffer_output=False):
179 self.cmd[2] = self.pycmd
188 self.cmd[2] = self.pycmd
180 super(PyTestController, self).launch(buffer_output=buffer_output)
189 super(PyTestController, self).launch(buffer_output=buffer_output)
181
190
182 js_prefix = 'js/'
191 js_prefix = 'js/'
183
192
184 def get_js_test_dir():
193 def get_js_test_dir():
185 import IPython.html.tests as t
194 import IPython.html.tests as t
186 return os.path.join(os.path.dirname(t.__file__), '')
195 return os.path.join(os.path.dirname(t.__file__), '')
187
196
188 def all_js_groups():
197 def all_js_groups():
189 import glob
198 import glob
190 test_dir = get_js_test_dir()
199 test_dir = get_js_test_dir()
191 all_subdirs = glob.glob(test_dir + '*/')
200 all_subdirs = glob.glob(test_dir + '*/')
192 return [js_prefix+os.path.relpath(x, test_dir) for x in all_subdirs if os.path.relpath(x, test_dir) != '__pycache__']
201 return [js_prefix+os.path.relpath(x, test_dir) for x in all_subdirs if os.path.relpath(x, test_dir) != '__pycache__']
193
202
194 class JSController(TestController):
203 class JSController(TestController):
195 """Run CasperJS tests """
204 """Run CasperJS tests """
196 def __init__(self, section):
205 def __init__(self, section):
197 """Create new test runner."""
206 """Create new test runner."""
198 TestController.__init__(self)
207 TestController.__init__(self)
199 self.section = section
208 self.section = section
200 js_test_dir = get_js_test_dir()
209 js_test_dir = get_js_test_dir()
201 includes = '--includes=' + os.path.join(js_test_dir,'util.js')
210 includes = '--includes=' + os.path.join(js_test_dir,'util.js')
202 test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):])
211 test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):])
203 self.cmd = ['casperjs', 'test', includes, test_cases]
212 self.cmd = ['casperjs', 'test', includes, test_cases]
204
213
205 def setup(self):
214 def setup(self):
206 self.ipydir = TemporaryDirectory()
215 self.ipydir = TemporaryDirectory()
207 self.nbdir = TemporaryDirectory()
216 self.nbdir = TemporaryDirectory()
208 self.dirs.append(self.ipydir)
217 self.dirs.append(self.ipydir)
209 self.dirs.append(self.nbdir)
218 self.dirs.append(self.nbdir)
210 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir1', u'sub βˆ‚ir 1a')))
219 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir1', u'sub βˆ‚ir 1a')))
211 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir2', u'sub βˆ‚ir 1b')))
220 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub βˆ‚ir2', u'sub βˆ‚ir 1b')))
212
221
213 # start the ipython notebook, so we get the port number
222 # start the ipython notebook, so we get the port number
223 self.server_port = 0
214 self._init_server()
224 self._init_server()
215 self.cmd.append('--port=%s' % self.server_port)
225 if self.server_port:
216
226 self.cmd.append("--port=%i" % self.server_port)
227 else:
228 # don't launch tests if the server didn't start
229 self.cmd = [sys.executable, '-c', 'raise SystemExit(1)']
230
217 def print_extra_info(self):
231 def print_extra_info(self):
218 print("Running tests with notebook directory %r" % self.nbdir.name)
232 print("Running tests with notebook directory %r" % self.nbdir.name)
219
233
220 @property
234 @property
221 def will_run(self):
235 def will_run(self):
222 return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs'])
236 return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs', 'sqlite3'])
223
237
224 def _init_server(self):
238 def _init_server(self):
225 "Start the notebook server in a separate process"
239 "Start the notebook server in a separate process"
226 self.queue = q = Queue()
240 self.server_command = command = [sys.executable,
227 self.server = Process(target=run_webapp, args=(q, self.ipydir.name, self.nbdir.name))
241 '-m', 'IPython.html',
228 self.server.start()
242 '--no-browser',
229 self.server_port = q.get()
243 '--ipython-dir', self.ipydir.name,
244 '--notebook-dir', self.nbdir.name,
245 ]
246 # ipc doesn't work on Windows, and darwin has crazy-long temp paths,
247 # which run afoul of ipc's maximum path length.
248 if sys.platform.startswith('linux'):
249 command.append('--KernelManager.transport=ipc')
250 self.stream_capturer = c = StreamCapturer()
251 c.start()
252 self.server = subprocess.Popen(command, stdout=c.writefd, stderr=subprocess.STDOUT)
253 self.server_info_file = os.path.join(self.ipydir.name,
254 'profile_default', 'security', 'nbserver-%i.json' % self.server.pid
255 )
256 self._wait_for_server()
257
258 def _wait_for_server(self):
259 """Wait 30 seconds for the notebook server to start"""
260 for i in range(300):
261 if self.server.poll() is not None:
262 return self._failed_to_start()
263 if os.path.exists(self.server_info_file):
264 self._load_server_info()
265 return
266 time.sleep(0.1)
267 print("Notebook server-info file never arrived: %s" % self.server_info_file,
268 file=sys.stderr
269 )
270
271 def _failed_to_start(self):
272 """Notebook server exited prematurely"""
273 captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace')
274 print("Notebook failed to start: ", file=sys.stderr)
275 print(self.server_command)
276 print(captured, file=sys.stderr)
277
278 def _load_server_info(self):
279 """Notebook server started, load connection info from JSON"""
280 with open(self.server_info_file) as f:
281 info = json.load(f)
282 self.server_port = info['port']
230
283
231 def cleanup(self):
284 def cleanup(self):
232 self.server.terminate()
285 try:
233 self.server.join()
286 self.server.terminate()
287 except OSError:
288 # already dead
289 pass
290 self.server.wait()
291 self.stream_capturer.halt()
234 TestController.cleanup(self)
292 TestController.cleanup(self)
235
293
236 def run_webapp(q, ipydir, nbdir, loglevel=0):
237 """start the IPython Notebook, and pass port back to the queue"""
238 import os
239 import IPython.html.notebookapp as nbapp
240 import sys
241 sys.stderr = open(os.devnull, 'w')
242 server = nbapp.NotebookApp()
243 args = ['--no-browser']
244 args.extend(['--ipython-dir', ipydir,
245 '--notebook-dir', nbdir,
246 '--log-level', str(loglevel),
247 ])
248 # ipc doesn't work on Windows, and darwin has crazy-long temp paths,
249 # which run afoul of ipc's maximum path length.
250 if sys.platform.startswith('linux'):
251 args.append('--KernelManager.transport=ipc')
252 server.initialize(args)
253 # communicate the port number to the parent process
254 q.put(server.port)
255 server.start()
256
294
257 def prepare_controllers(options):
295 def prepare_controllers(options):
258 """Returns two lists of TestController instances, those to run, and those
296 """Returns two lists of TestController instances, those to run, and those
259 not to run."""
297 not to run."""
260 testgroups = options.testgroups
298 testgroups = options.testgroups
261
299
262 if testgroups:
300 if testgroups:
263 py_testgroups = [g for g in testgroups if (g in py_test_group_names) \
301 py_testgroups = [g for g in testgroups if (g in py_test_group_names) \
264 or g.startswith('IPython.')]
302 or g.startswith('IPython.')]
265 if 'js' in testgroups:
303 if 'js' in testgroups:
266 js_testgroups = all_js_groups()
304 js_testgroups = all_js_groups()
267 else:
305 else:
268 js_testgroups = [g for g in testgroups if g not in py_testgroups]
306 js_testgroups = [g for g in testgroups if g not in py_testgroups]
269 else:
307 else:
270 py_testgroups = py_test_group_names
308 py_testgroups = py_test_group_names
271 js_testgroups = all_js_groups()
309 js_testgroups = all_js_groups()
272 if not options.all:
310 if not options.all:
273 test_sections['parallel'].enabled = False
311 test_sections['parallel'].enabled = False
274
312
275 c_js = [JSController(name) for name in js_testgroups]
313 c_js = [JSController(name) for name in js_testgroups]
276 c_py = [PyTestController(name) for name in py_testgroups]
314 c_py = [PyTestController(name, options) for name in py_testgroups]
277
278 configure_py_controllers(c_py, xunit=options.xunit,
279 coverage=options.coverage, subproc_streams=options.subproc_streams,
280 extra_args=options.extra_args)
281
315
282 controllers = c_py + c_js
316 controllers = c_py + c_js
283 to_run = [c for c in controllers if c.will_run]
317 to_run = [c for c in controllers if c.will_run]
284 not_run = [c for c in controllers if not c.will_run]
318 not_run = [c for c in controllers if not c.will_run]
285 return to_run, not_run
319 return to_run, not_run
286
320
287 def configure_py_controllers(controllers, xunit=False, coverage=False,
288 subproc_streams='capture', extra_args=()):
289 """Apply options for a collection of TestController objects."""
290 for controller in controllers:
291 if xunit:
292 controller.add_xunit()
293 if coverage:
294 controller.add_coverage()
295 controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams
296 controller.cmd.extend(extra_args)
297
298 def do_run(controller, buffer_output=True):
321 def do_run(controller, buffer_output=True):
299 """Setup and run a test controller.
322 """Setup and run a test controller.
300
323
301 If buffer_output is True, no output is displayed, to avoid it appearing
324 If buffer_output is True, no output is displayed, to avoid it appearing
302 interleaved. In this case, the caller is responsible for displaying test
325 interleaved. In this case, the caller is responsible for displaying test
303 output on failure.
326 output on failure.
304
327
305 Returns
328 Returns
306 -------
329 -------
307 controller : TestController
330 controller : TestController
308 The same controller as passed in, as a convenience for using map() type
331 The same controller as passed in, as a convenience for using map() type
309 APIs.
332 APIs.
310 exitcode : int
333 exitcode : int
311 The exit code of the test subprocess. Non-zero indicates failure.
334 The exit code of the test subprocess. Non-zero indicates failure.
312 """
335 """
313 try:
336 try:
314 try:
337 try:
315 controller.setup()
338 controller.setup()
316 if not buffer_output:
339 if not buffer_output:
317 controller.print_extra_info()
340 controller.print_extra_info()
318 controller.launch(buffer_output=buffer_output)
341 controller.launch(buffer_output=buffer_output)
319 except Exception:
342 except Exception:
320 import traceback
343 import traceback
321 traceback.print_exc()
344 traceback.print_exc()
322 return controller, 1 # signal failure
345 return controller, 1 # signal failure
323
346
324 exitcode = controller.wait()
347 exitcode = controller.wait()
325 return controller, exitcode
348 return controller, exitcode
326
349
327 except KeyboardInterrupt:
350 except KeyboardInterrupt:
328 return controller, -signal.SIGINT
351 return controller, -signal.SIGINT
329 finally:
352 finally:
330 controller.cleanup()
353 controller.cleanup()
331
354
332 def report():
355 def report():
333 """Return a string with a summary report of test-related variables."""
356 """Return a string with a summary report of test-related variables."""
334 inf = get_sys_info()
357 inf = get_sys_info()
335 out = []
358 out = []
336 def _add(name, value):
359 def _add(name, value):
337 out.append((name, value))
360 out.append((name, value))
338
361
339 _add('IPython version', inf['ipython_version'])
362 _add('IPython version', inf['ipython_version'])
340 _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
363 _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
341 _add('IPython package', compress_user(inf['ipython_path']))
364 _add('IPython package', compress_user(inf['ipython_path']))
342 _add('Python version', inf['sys_version'].replace('\n',''))
365 _add('Python version', inf['sys_version'].replace('\n',''))
343 _add('sys.executable', compress_user(inf['sys_executable']))
366 _add('sys.executable', compress_user(inf['sys_executable']))
344 _add('Platform', inf['platform'])
367 _add('Platform', inf['platform'])
345
368
346 width = max(len(n) for (n,v) in out)
369 width = max(len(n) for (n,v) in out)
347 out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
370 out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
348
371
349 avail = []
372 avail = []
350 not_avail = []
373 not_avail = []
351
374
352 for k, is_avail in have.items():
375 for k, is_avail in have.items():
353 if is_avail:
376 if is_avail:
354 avail.append(k)
377 avail.append(k)
355 else:
378 else:
356 not_avail.append(k)
379 not_avail.append(k)
357
380
358 if avail:
381 if avail:
359 out.append('\nTools and libraries available at test time:\n')
382 out.append('\nTools and libraries available at test time:\n')
360 avail.sort()
383 avail.sort()
361 out.append(' ' + ' '.join(avail)+'\n')
384 out.append(' ' + ' '.join(avail)+'\n')
362
385
363 if not_avail:
386 if not_avail:
364 out.append('\nTools and libraries NOT available at test time:\n')
387 out.append('\nTools and libraries NOT available at test time:\n')
365 not_avail.sort()
388 not_avail.sort()
366 out.append(' ' + ' '.join(not_avail)+'\n')
389 out.append(' ' + ' '.join(not_avail)+'\n')
367
390
368 return ''.join(out)
391 return ''.join(out)
369
392
370 def run_iptestall(options):
393 def run_iptestall(options):
371 """Run the entire IPython test suite by calling nose and trial.
394 """Run the entire IPython test suite by calling nose and trial.
372
395
373 This function constructs :class:`IPTester` instances for all IPython
396 This function constructs :class:`IPTester` instances for all IPython
374 modules and package and then runs each of them. This causes the modules
397 modules and package and then runs each of them. This causes the modules
375 and packages of IPython to be tested each in their own subprocess using
398 and packages of IPython to be tested each in their own subprocess using
376 nose.
399 nose.
377
400
378 Parameters
401 Parameters
379 ----------
402 ----------
380
403
381 All parameters are passed as attributes of the options object.
404 All parameters are passed as attributes of the options object.
382
405
383 testgroups : list of str
406 testgroups : list of str
384 Run only these sections of the test suite. If empty, run all the available
407 Run only these sections of the test suite. If empty, run all the available
385 sections.
408 sections.
386
409
387 fast : int or None
410 fast : int or None
388 Run the test suite in parallel, using n simultaneous processes. If None
411 Run the test suite in parallel, using n simultaneous processes. If None
389 is passed, one process is used per CPU core. Default 1 (i.e. sequential)
412 is passed, one process is used per CPU core. Default 1 (i.e. sequential)
390
413
391 inc_slow : bool
414 inc_slow : bool
392 Include slow tests, like IPython.parallel. By default, these tests aren't
415 Include slow tests, like IPython.parallel. By default, these tests aren't
393 run.
416 run.
394
417
395 xunit : bool
418 xunit : bool
396 Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
419 Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
397
420
398 coverage : bool or str
421 coverage : bool or str
399 Measure code coverage from tests. True will store the raw coverage data,
422 Measure code coverage from tests. True will store the raw coverage data,
400 or pass 'html' or 'xml' to get reports.
423 or pass 'html' or 'xml' to get reports.
401
424
402 extra_args : list
425 extra_args : list
403 Extra arguments to pass to the test subprocesses, e.g. '-v'
426 Extra arguments to pass to the test subprocesses, e.g. '-v'
404 """
427 """
405 to_run, not_run = prepare_controllers(options)
428 to_run, not_run = prepare_controllers(options)
406
429
407 def justify(ltext, rtext, width=70, fill='-'):
430 def justify(ltext, rtext, width=70, fill='-'):
408 ltext += ' '
431 ltext += ' '
409 rtext = (' ' + rtext).rjust(width - len(ltext), fill)
432 rtext = (' ' + rtext).rjust(width - len(ltext), fill)
410 return ltext + rtext
433 return ltext + rtext
411
434
412 # Run all test runners, tracking execution time
435 # Run all test runners, tracking execution time
413 failed = []
436 failed = []
414 t_start = time.time()
437 t_start = time.time()
415
438
416 print()
439 print()
417 if options.fast == 1:
440 if options.fast == 1:
418 # This actually means sequential, i.e. with 1 job
441 # This actually means sequential, i.e. with 1 job
419 for controller in to_run:
442 for controller in to_run:
420 print('Test group:', controller.section)
443 print('Test group:', controller.section)
421 sys.stdout.flush() # Show in correct order when output is piped
444 sys.stdout.flush() # Show in correct order when output is piped
422 controller, res = do_run(controller, buffer_output=False)
445 controller, res = do_run(controller, buffer_output=False)
423 if res:
446 if res:
424 failed.append(controller)
447 failed.append(controller)
425 if res == -signal.SIGINT:
448 if res == -signal.SIGINT:
426 print("Interrupted")
449 print("Interrupted")
427 break
450 break
428 print()
451 print()
429
452
430 else:
453 else:
431 # Run tests concurrently
454 # Run tests concurrently
432 try:
455 try:
433 pool = multiprocessing.pool.ThreadPool(options.fast)
456 pool = multiprocessing.pool.ThreadPool(options.fast)
434 for (controller, res) in pool.imap_unordered(do_run, to_run):
457 for (controller, res) in pool.imap_unordered(do_run, to_run):
435 res_string = 'OK' if res == 0 else 'FAILED'
458 res_string = 'OK' if res == 0 else 'FAILED'
436 print(justify('Test group: ' + controller.section, res_string))
459 print(justify('Test group: ' + controller.section, res_string))
437 if res:
460 if res:
438 controller.print_extra_info()
461 controller.print_extra_info()
439 print(bytes_to_str(controller.stdout))
462 print(bytes_to_str(controller.stdout))
440 failed.append(controller)
463 failed.append(controller)
441 if res == -signal.SIGINT:
464 if res == -signal.SIGINT:
442 print("Interrupted")
465 print("Interrupted")
443 break
466 break
444 except KeyboardInterrupt:
467 except KeyboardInterrupt:
445 return
468 return
446
469
447 for controller in not_run:
470 for controller in not_run:
448 print(justify('Test group: ' + controller.section, 'NOT RUN'))
471 print(justify('Test group: ' + controller.section, 'NOT RUN'))
449
472
450 t_end = time.time()
473 t_end = time.time()
451 t_tests = t_end - t_start
474 t_tests = t_end - t_start
452 nrunners = len(to_run)
475 nrunners = len(to_run)
453 nfail = len(failed)
476 nfail = len(failed)
454 # summarize results
477 # summarize results
455 print('_'*70)
478 print('_'*70)
456 print('Test suite completed for system with the following information:')
479 print('Test suite completed for system with the following information:')
457 print(report())
480 print(report())
458 took = "Took %.3fs." % t_tests
481 took = "Took %.3fs." % t_tests
459 print('Status: ', end='')
482 print('Status: ', end='')
460 if not failed:
483 if not failed:
461 print('OK (%d test groups).' % nrunners, took)
484 print('OK (%d test groups).' % nrunners, took)
462 else:
485 else:
463 # If anything went wrong, point out what command to rerun manually to
486 # If anything went wrong, point out what command to rerun manually to
464 # see the actual errors and individual summary
487 # see the actual errors and individual summary
465 failed_sections = [c.section for c in failed]
488 failed_sections = [c.section for c in failed]
466 print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
489 print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
467 nrunners, ', '.join(failed_sections)), took)
490 nrunners, ', '.join(failed_sections)), took)
468 print()
491 print()
469 print('You may wish to rerun these, with:')
492 print('You may wish to rerun these, with:')
470 print(' iptest', *failed_sections)
493 print(' iptest', *failed_sections)
471 print()
494 print()
472
495
473 if options.coverage:
496 if options.coverage:
474 from coverage import coverage
497 from coverage import coverage
475 cov = coverage(data_file='.coverage')
498 cov = coverage(data_file='.coverage')
476 cov.combine()
499 cov.combine()
477 cov.save()
500 cov.save()
478
501
479 # Coverage HTML report
502 # Coverage HTML report
480 if options.coverage == 'html':
503 if options.coverage == 'html':
481 html_dir = 'ipy_htmlcov'
504 html_dir = 'ipy_htmlcov'
482 shutil.rmtree(html_dir, ignore_errors=True)
505 shutil.rmtree(html_dir, ignore_errors=True)
483 print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
506 print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
484 sys.stdout.flush()
507 sys.stdout.flush()
485
508
486 # Custom HTML reporter to clean up module names.
509 # Custom HTML reporter to clean up module names.
487 from coverage.html import HtmlReporter
510 from coverage.html import HtmlReporter
488 class CustomHtmlReporter(HtmlReporter):
511 class CustomHtmlReporter(HtmlReporter):
489 def find_code_units(self, morfs):
512 def find_code_units(self, morfs):
490 super(CustomHtmlReporter, self).find_code_units(morfs)
513 super(CustomHtmlReporter, self).find_code_units(morfs)
491 for cu in self.code_units:
514 for cu in self.code_units:
492 nameparts = cu.name.split(os.sep)
515 nameparts = cu.name.split(os.sep)
493 if 'IPython' not in nameparts:
516 if 'IPython' not in nameparts:
494 continue
517 continue
495 ix = nameparts.index('IPython')
518 ix = nameparts.index('IPython')
496 cu.name = '.'.join(nameparts[ix:])
519 cu.name = '.'.join(nameparts[ix:])
497
520
498 # Reimplement the html_report method with our custom reporter
521 # Reimplement the html_report method with our custom reporter
499 cov._harvest_data()
522 cov._harvest_data()
500 cov.config.from_args(omit='*{0}tests{0}*'.format(os.sep), html_dir=html_dir,
523 cov.config.from_args(omit='*{0}tests{0}*'.format(os.sep), html_dir=html_dir,
501 html_title='IPython test coverage',
524 html_title='IPython test coverage',
502 )
525 )
503 reporter = CustomHtmlReporter(cov, cov.config)
526 reporter = CustomHtmlReporter(cov, cov.config)
504 reporter.report(None)
527 reporter.report(None)
505 print('done.')
528 print('done.')
506
529
507 # Coverage XML report
530 # Coverage XML report
508 elif options.coverage == 'xml':
531 elif options.coverage == 'xml':
509 cov.xml_report(outfile='ipy_coverage.xml')
532 cov.xml_report(outfile='ipy_coverage.xml')
510
533
511 if failed:
534 if failed:
512 # Ensure that our exit code indicates failure
535 # Ensure that our exit code indicates failure
513 sys.exit(1)
536 sys.exit(1)
514
537
515 argparser = argparse.ArgumentParser(description='Run IPython test suite')
538 argparser = argparse.ArgumentParser(description='Run IPython test suite')
516 argparser.add_argument('testgroups', nargs='*',
539 argparser.add_argument('testgroups', nargs='*',
517 help='Run specified groups of tests. If omitted, run '
540 help='Run specified groups of tests. If omitted, run '
518 'all tests.')
541 'all tests.')
519 argparser.add_argument('--all', action='store_true',
542 argparser.add_argument('--all', action='store_true',
520 help='Include slow tests not run by default.')
543 help='Include slow tests not run by default.')
521 argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
544 argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
522 help='Run test sections in parallel. This starts as many '
545 help='Run test sections in parallel. This starts as many '
523 'processes as you have cores, or you can specify a number.')
546 'processes as you have cores, or you can specify a number.')
524 argparser.add_argument('--xunit', action='store_true',
547 argparser.add_argument('--xunit', action='store_true',
525 help='Produce Xunit XML results')
548 help='Produce Xunit XML results')
526 argparser.add_argument('--coverage', nargs='?', const=True, default=False,
549 argparser.add_argument('--coverage', nargs='?', const=True, default=False,
527 help="Measure test coverage. Specify 'html' or "
550 help="Measure test coverage. Specify 'html' or "
528 "'xml' to get reports.")
551 "'xml' to get reports.")
529 argparser.add_argument('--subproc-streams', default='capture',
552 argparser.add_argument('--subproc-streams', default='capture',
530 help="What to do with stdout/stderr from subprocesses. "
553 help="What to do with stdout/stderr from subprocesses. "
531 "'capture' (default), 'show' and 'discard' are the options.")
554 "'capture' (default), 'show' and 'discard' are the options.")
532
555
533 def default_options():
556 def default_options():
534 """Get an argparse Namespace object with the default arguments, to pass to
557 """Get an argparse Namespace object with the default arguments, to pass to
535 :func:`run_iptestall`.
558 :func:`run_iptestall`.
536 """
559 """
537 options = argparser.parse_args([])
560 options = argparser.parse_args([])
538 options.extra_args = []
561 options.extra_args = []
539 return options
562 return options
540
563
541 def main():
564 def main():
542 # iptest doesn't work correctly if the working directory is the
565 # iptest doesn't work correctly if the working directory is the
543 # root of the IPython source tree. Tell the user to avoid
566 # root of the IPython source tree. Tell the user to avoid
544 # frustration.
567 # frustration.
545 if os.path.exists(os.path.join(os.getcwd(),
568 if os.path.exists(os.path.join(os.getcwd(),
546 'IPython', 'testing', '__main__.py')):
569 'IPython', 'testing', '__main__.py')):
547 print("Don't run iptest from the IPython source directory",
570 print("Don't run iptest from the IPython source directory",
548 file=sys.stderr)
571 file=sys.stderr)
549 sys.exit(1)
572 sys.exit(1)
550 # Arguments after -- should be passed through to nose. Argparse treats
573 # Arguments after -- should be passed through to nose. Argparse treats
551 # everything after -- as regular positional arguments, so we separate them
574 # everything after -- as regular positional arguments, so we separate them
552 # first.
575 # first.
553 try:
576 try:
554 ix = sys.argv.index('--')
577 ix = sys.argv.index('--')
555 except ValueError:
578 except ValueError:
556 to_parse = sys.argv[1:]
579 to_parse = sys.argv[1:]
557 extra_args = []
580 extra_args = []
558 else:
581 else:
559 to_parse = sys.argv[1:ix]
582 to_parse = sys.argv[1:ix]
560 extra_args = sys.argv[ix+1:]
583 extra_args = sys.argv[ix+1:]
561
584
562 options = argparser.parse_args(to_parse)
585 options = argparser.parse_args(to_parse)
563 options.extra_args = extra_args
586 options.extra_args = extra_args
564
587
565 run_iptestall(options)
588 run_iptestall(options)
566
589
567
590
568 if __name__ == '__main__':
591 if __name__ == '__main__':
569 main()
592 main()
@@ -1,1163 +1,1093 b''
1 =================
1 =================
2 IPython reference
2 IPython reference
3 =================
3 =================
4
4
5 .. _command_line_options:
5 .. _command_line_options:
6
6
7 Command-line usage
7 Command-line usage
8 ==================
8 ==================
9
9
10 You start IPython with the command::
10 You start IPython with the command::
11
11
12 $ ipython [options] files
12 $ ipython [options] files
13
13
14 If invoked with no options, it executes all the files listed in sequence
14 If invoked with no options, it executes all the files listed in sequence
15 and drops you into the interpreter while still acknowledging any options
15 and drops you into the interpreter while still acknowledging any options
16 you may have set in your ipython_config.py. This behavior is different from
16 you may have set in your ipython_config.py. This behavior is different from
17 standard Python, which when called as python -i will only execute one
17 standard Python, which when called as python -i will only execute one
18 file and ignore your configuration setup.
18 file and ignore your configuration setup.
19
19
20 Please note that some of the configuration options are not available at
20 Please note that some of the configuration options are not available at
21 the command line, simply because they are not practical here. Look into
21 the command line, simply because they are not practical here. Look into
22 your configuration files for details on those. There are separate configuration
22 your configuration files for details on those. There are separate configuration
23 files for each profile, and the files look like :file:`ipython_config.py` or
23 files for each profile, and the files look like :file:`ipython_config.py` or
24 :file:`ipython_config_{frontendname}.py`. Profile directories look like
24 :file:`ipython_config_{frontendname}.py`. Profile directories look like
25 :file:`profile_{profilename}` and are typically installed in the :envvar:`IPYTHONDIR` directory,
25 :file:`profile_{profilename}` and are typically installed in the :envvar:`IPYTHONDIR` directory,
26 which defaults to :file:`$HOME/.ipython`. For Windows users, :envvar:`HOME`
26 which defaults to :file:`$HOME/.ipython`. For Windows users, :envvar:`HOME`
27 resolves to :file:`C:\\Users\\{YourUserName}` in most instances.
27 resolves to :file:`C:\\Users\\{YourUserName}` in most instances.
28
28
29
30 Eventloop integration
31 ---------------------
32
33 Previously IPython had command line options for controlling GUI event loop
34 integration (-gthread, -qthread, -q4thread, -wthread, -pylab). As of IPython
35 version 0.11, these have been removed. Please see the new ``%gui``
36 magic command or :ref:`this section <gui_support>` for details on the new
37 interface, or specify the gui at the commandline::
38
39 $ ipython --gui=qt
40
41
42 Command-line Options
29 Command-line Options
43 --------------------
30 --------------------
44
31
45 To see the options IPython accepts, use ``ipython --help`` (and you probably
32 To see the options IPython accepts, use ``ipython --help`` (and you probably
46 should run the output through a pager such as ``ipython --help | less`` for
33 should run the output through a pager such as ``ipython --help | less`` for
47 more convenient reading). This shows all the options that have a single-word
34 more convenient reading). This shows all the options that have a single-word
48 alias to control them, but IPython lets you configure all of its objects from
35 alias to control them, but IPython lets you configure all of its objects from
49 the command-line by passing the full class name and a corresponding value; type
36 the command-line by passing the full class name and a corresponding value; type
50 ``ipython --help-all`` to see this full list. For example::
37 ``ipython --help-all`` to see this full list. For example::
51
38
52 ipython --matplotlib qt
39 ipython --matplotlib qt
53
40
54 is equivalent to::
41 is equivalent to::
55
42
56 ipython --TerminalIPythonApp.matplotlib='qt'
43 ipython --TerminalIPythonApp.matplotlib='qt'
57
44
58 Note that in the second form, you *must* use the equal sign, as the expression
45 Note that in the second form, you *must* use the equal sign, as the expression
59 is evaluated as an actual Python assignment. While in the above example the
46 is evaluated as an actual Python assignment. While in the above example the
60 short form is more convenient, only the most common options have a short form,
47 short form is more convenient, only the most common options have a short form,
61 while any configurable variable in IPython can be set at the command-line by
48 while any configurable variable in IPython can be set at the command-line by
62 using the long form. This long form is the same syntax used in the
49 using the long form. This long form is the same syntax used in the
63 configuration files, if you want to set these options permanently.
50 configuration files, if you want to set these options permanently.
64
51
65
52
66 Interactive use
53 Interactive use
67 ===============
54 ===============
68
55
69 IPython is meant to work as a drop-in replacement for the standard interactive
56 IPython is meant to work as a drop-in replacement for the standard interactive
70 interpreter. As such, any code which is valid python should execute normally
57 interpreter. As such, any code which is valid python should execute normally
71 under IPython (cases where this is not true should be reported as bugs). It
58 under IPython (cases where this is not true should be reported as bugs). It
72 does, however, offer many features which are not available at a standard python
59 does, however, offer many features which are not available at a standard python
73 prompt. What follows is a list of these.
60 prompt. What follows is a list of these.
74
61
75
62
76 Caution for Windows users
63 Caution for Windows users
77 -------------------------
64 -------------------------
78
65
79 Windows, unfortunately, uses the '\\' character as a path separator. This is a
66 Windows, unfortunately, uses the '\\' character as a path separator. This is a
80 terrible choice, because '\\' also represents the escape character in most
67 terrible choice, because '\\' also represents the escape character in most
81 modern programming languages, including Python. For this reason, using '/'
68 modern programming languages, including Python. For this reason, using '/'
82 character is recommended if you have problems with ``\``. However, in Windows
69 character is recommended if you have problems with ``\``. However, in Windows
83 commands '/' flags options, so you can not use it for the root directory. This
70 commands '/' flags options, so you can not use it for the root directory. This
84 means that paths beginning at the root must be typed in a contrived manner
71 means that paths beginning at the root must be typed in a contrived manner
85 like: ``%copy \opt/foo/bar.txt \tmp``
72 like: ``%copy \opt/foo/bar.txt \tmp``
86
73
87 .. _magic:
74 .. _magic:
88
75
89 Magic command system
76 Magic command system
90 --------------------
77 --------------------
91
78
92 IPython will treat any line whose first character is a % as a special
79 IPython will treat any line whose first character is a % as a special
93 call to a 'magic' function. These allow you to control the behavior of
80 call to a 'magic' function. These allow you to control the behavior of
94 IPython itself, plus a lot of system-type features. They are all
81 IPython itself, plus a lot of system-type features. They are all
95 prefixed with a % character, but parameters are given without
82 prefixed with a % character, but parameters are given without
96 parentheses or quotes.
83 parentheses or quotes.
97
84
98 Lines that begin with ``%%`` signal a *cell magic*: they take as arguments not
85 Lines that begin with ``%%`` signal a *cell magic*: they take as arguments not
99 only the rest of the current line, but all lines below them as well, in the
86 only the rest of the current line, but all lines below them as well, in the
100 current execution block. Cell magics can in fact make arbitrary modifications
87 current execution block. Cell magics can in fact make arbitrary modifications
101 to the input they receive, which need not even be valid Python code at all.
88 to the input they receive, which need not even be valid Python code at all.
102 They receive the whole block as a single string.
89 They receive the whole block as a single string.
103
90
104 As a line magic example, the ``%cd`` magic works just like the OS command of
91 As a line magic example, the ``%cd`` magic works just like the OS command of
105 the same name::
92 the same name::
106
93
107 In [8]: %cd
94 In [8]: %cd
108 /home/fperez
95 /home/fperez
109
96
110 The following uses the builtin ``timeit`` in cell mode::
97 The following uses the builtin ``timeit`` in cell mode::
111
98
112 In [10]: %%timeit x = range(10000)
99 In [10]: %%timeit x = range(10000)
113 ...: min(x)
100 ...: min(x)
114 ...: max(x)
101 ...: max(x)
115 ...:
102 ...:
116 1000 loops, best of 3: 438 us per loop
103 1000 loops, best of 3: 438 us per loop
117
104
118 In this case, ``x = range(10000)`` is called as the line argument, and the
105 In this case, ``x = range(10000)`` is called as the line argument, and the
119 block with ``min(x)`` and ``max(x)`` is called as the cell body. The
106 block with ``min(x)`` and ``max(x)`` is called as the cell body. The
120 ``timeit`` magic receives both.
107 ``timeit`` magic receives both.
121
108
122 If you have 'automagic' enabled (as it by default), you don't need to type in
109 If you have 'automagic' enabled (as it by default), you don't need to type in
123 the single ``%`` explicitly for line magics; IPython will scan its internal
110 the single ``%`` explicitly for line magics; IPython will scan its internal
124 list of magic functions and call one if it exists. With automagic on you can
111 list of magic functions and call one if it exists. With automagic on you can
125 then just type ``cd mydir`` to go to directory 'mydir'::
112 then just type ``cd mydir`` to go to directory 'mydir'::
126
113
127 In [9]: cd mydir
114 In [9]: cd mydir
128 /home/fperez/mydir
115 /home/fperez/mydir
129
116
130 Note that cell magics *always* require an explicit ``%%`` prefix, automagic
117 Note that cell magics *always* require an explicit ``%%`` prefix, automagic
131 calling only works for line magics.
118 calling only works for line magics.
132
119
133 The automagic system has the lowest possible precedence in name searches, so
120 The automagic system has the lowest possible precedence in name searches, so
134 defining an identifier with the same name as an existing magic function will
121 you can freely use variables with the same names as magic commands. If a magic
135 shadow it for automagic use. You can still access the shadowed magic function
122 command is 'shadowed' by a variable, you will need the explicit ``%`` prefix to
136 by explicitly using the ``%`` character at the beginning of the line.
123 use it:
137
138 An example (with automagic on) should clarify all this:
139
124
140 .. sourcecode:: ipython
125 .. sourcecode:: ipython
141
126
142 In [1]: cd ipython # %cd is called by automagic
127 In [1]: cd ipython # %cd is called by automagic
143 /home/fperez/ipython
128 /home/fperez/ipython
144
129
145 In [2]: cd=1 # now cd is just a variable
130 In [2]: cd=1 # now cd is just a variable
146
131
147 In [3]: cd .. # and doesn't work as a function anymore
132 In [3]: cd .. # and doesn't work as a function anymore
148 File "<ipython-input-3-9fedb3aff56c>", line 1
133 File "<ipython-input-3-9fedb3aff56c>", line 1
149 cd ..
134 cd ..
150 ^
135 ^
151 SyntaxError: invalid syntax
136 SyntaxError: invalid syntax
152
137
153
138
154 In [4]: %cd .. # but %cd always works
139 In [4]: %cd .. # but %cd always works
155 /home/fperez
140 /home/fperez
156
141
157 In [5]: del cd # if you remove the cd variable, automagic works again
142 In [5]: del cd # if you remove the cd variable, automagic works again
158
143
159 In [6]: cd ipython
144 In [6]: cd ipython
160
145
161 /home/fperez/ipython
146 /home/fperez/ipython
162
147
163 .. _defining_magics:
148 .. _defining_magics:
164
149
165 Defining your own magics
150 Defining your own magics
166 ++++++++++++++++++++++++
151 ++++++++++++++++++++++++
167
152
168 There are two main ways to define your own magic functions: from standalone
153 There are two main ways to define your own magic functions: from standalone
169 functions and by inheriting from a base class provided by IPython:
154 functions and by inheriting from a base class provided by IPython:
170 :class:`IPython.core.magic.Magics`. Below we show code you can place in a file
155 :class:`IPython.core.magic.Magics`. Below we show code you can place in a file
171 that you load from your configuration, such as any file in the ``startup``
156 that you load from your configuration, such as any file in the ``startup``
172 subdirectory of your default IPython profile.
157 subdirectory of your default IPython profile.
173
158
174 First, let us see the simplest case. The following shows how to create a line
159 First, let us see the simplest case. The following shows how to create a line
175 magic, a cell one and one that works in both modes, using just plain functions:
160 magic, a cell one and one that works in both modes, using just plain functions:
176
161
177 .. sourcecode:: python
162 .. sourcecode:: python
178
163
179 from IPython.core.magic import (register_line_magic, register_cell_magic,
164 from IPython.core.magic import (register_line_magic, register_cell_magic,
180 register_line_cell_magic)
165 register_line_cell_magic)
181
166
182 @register_line_magic
167 @register_line_magic
183 def lmagic(line):
168 def lmagic(line):
184 "my line magic"
169 "my line magic"
185 return line
170 return line
186
171
187 @register_cell_magic
172 @register_cell_magic
188 def cmagic(line, cell):
173 def cmagic(line, cell):
189 "my cell magic"
174 "my cell magic"
190 return line, cell
175 return line, cell
191
176
192 @register_line_cell_magic
177 @register_line_cell_magic
193 def lcmagic(line, cell=None):
178 def lcmagic(line, cell=None):
194 "Magic that works both as %lcmagic and as %%lcmagic"
179 "Magic that works both as %lcmagic and as %%lcmagic"
195 if cell is None:
180 if cell is None:
196 print("Called as line magic")
181 print("Called as line magic")
197 return line
182 return line
198 else:
183 else:
199 print("Called as cell magic")
184 print("Called as cell magic")
200 return line, cell
185 return line, cell
201
186
202 # We delete these to avoid name conflicts for automagic to work
187 # We delete these to avoid name conflicts for automagic to work
203 del lmagic, lcmagic
188 del lmagic, lcmagic
204
189
205
190
206 You can also create magics of all three kinds by inheriting from the
191 You can also create magics of all three kinds by inheriting from the
207 :class:`IPython.core.magic.Magics` class. This lets you create magics that can
192 :class:`IPython.core.magic.Magics` class. This lets you create magics that can
208 potentially hold state in between calls, and that have full access to the main
193 potentially hold state in between calls, and that have full access to the main
209 IPython object:
194 IPython object:
210
195
211 .. sourcecode:: python
196 .. sourcecode:: python
212
197
213 # This code can be put in any Python module, it does not require IPython
198 # This code can be put in any Python module, it does not require IPython
214 # itself to be running already. It only creates the magics subclass but
199 # itself to be running already. It only creates the magics subclass but
215 # doesn't instantiate it yet.
200 # doesn't instantiate it yet.
216 from __future__ import print_function
201 from __future__ import print_function
217 from IPython.core.magic import (Magics, magics_class, line_magic,
202 from IPython.core.magic import (Magics, magics_class, line_magic,
218 cell_magic, line_cell_magic)
203 cell_magic, line_cell_magic)
219
204
220 # The class MUST call this class decorator at creation time
205 # The class MUST call this class decorator at creation time
221 @magics_class
206 @magics_class
222 class MyMagics(Magics):
207 class MyMagics(Magics):
223
208
224 @line_magic
209 @line_magic
225 def lmagic(self, line):
210 def lmagic(self, line):
226 "my line magic"
211 "my line magic"
227 print("Full access to the main IPython object:", self.shell)
212 print("Full access to the main IPython object:", self.shell)
228 print("Variables in the user namespace:", list(self.shell.user_ns.keys()))
213 print("Variables in the user namespace:", list(self.shell.user_ns.keys()))
229 return line
214 return line
230
215
231 @cell_magic
216 @cell_magic
232 def cmagic(self, line, cell):
217 def cmagic(self, line, cell):
233 "my cell magic"
218 "my cell magic"
234 return line, cell
219 return line, cell
235
220
236 @line_cell_magic
221 @line_cell_magic
237 def lcmagic(self, line, cell=None):
222 def lcmagic(self, line, cell=None):
238 "Magic that works both as %lcmagic and as %%lcmagic"
223 "Magic that works both as %lcmagic and as %%lcmagic"
239 if cell is None:
224 if cell is None:
240 print("Called as line magic")
225 print("Called as line magic")
241 return line
226 return line
242 else:
227 else:
243 print("Called as cell magic")
228 print("Called as cell magic")
244 return line, cell
229 return line, cell
245
230
246
231
247 # In order to actually use these magics, you must register them with a
232 # In order to actually use these magics, you must register them with a
248 # running IPython. This code must be placed in a file that is loaded once
233 # running IPython. This code must be placed in a file that is loaded once
249 # IPython is up and running:
234 # IPython is up and running:
250 ip = get_ipython()
235 ip = get_ipython()
251 # You can register the class itself without instantiating it. IPython will
236 # You can register the class itself without instantiating it. IPython will
252 # call the default constructor on it.
237 # call the default constructor on it.
253 ip.register_magics(MyMagics)
238 ip.register_magics(MyMagics)
254
239
255 If you want to create a class with a different constructor that holds
240 If you want to create a class with a different constructor that holds
256 additional state, then you should always call the parent constructor and
241 additional state, then you should always call the parent constructor and
257 instantiate the class yourself before registration:
242 instantiate the class yourself before registration:
258
243
259 .. sourcecode:: python
244 .. sourcecode:: python
260
245
261 @magics_class
246 @magics_class
262 class StatefulMagics(Magics):
247 class StatefulMagics(Magics):
263 "Magics that hold additional state"
248 "Magics that hold additional state"
264
249
265 def __init__(self, shell, data):
250 def __init__(self, shell, data):
266 # You must call the parent constructor
251 # You must call the parent constructor
267 super(StatefulMagics, self).__init__(shell)
252 super(StatefulMagics, self).__init__(shell)
268 self.data = data
253 self.data = data
269
254
270 # etc...
255 # etc...
271
256
272 # This class must then be registered with a manually created instance,
257 # This class must then be registered with a manually created instance,
273 # since its constructor has different arguments from the default:
258 # since its constructor has different arguments from the default:
274 ip = get_ipython()
259 ip = get_ipython()
275 magics = StatefulMagics(ip, some_data)
260 magics = StatefulMagics(ip, some_data)
276 ip.register_magics(magics)
261 ip.register_magics(magics)
277
262
278
263
279 In earlier versions, IPython had an API for the creation of line magics (cell
264 In earlier versions, IPython had an API for the creation of line magics (cell
280 magics did not exist at the time) that required you to create functions with a
265 magics did not exist at the time) that required you to create functions with a
281 method-looking signature and to manually pass both the function and the name.
266 method-looking signature and to manually pass both the function and the name.
282 While this API is no longer recommended, it remains indefinitely supported for
267 While this API is no longer recommended, it remains indefinitely supported for
283 backwards compatibility purposes. With the old API, you'd create a magic as
268 backwards compatibility purposes. With the old API, you'd create a magic as
284 follows:
269 follows:
285
270
286 .. sourcecode:: python
271 .. sourcecode:: python
287
272
288 def func(self, line):
273 def func(self, line):
289 print("Line magic called with line:", line)
274 print("Line magic called with line:", line)
290 print("IPython object:", self.shell)
275 print("IPython object:", self.shell)
291
276
292 ip = get_ipython()
277 ip = get_ipython()
293 # Declare this function as the magic %mycommand
278 # Declare this function as the magic %mycommand
294 ip.define_magic('mycommand', func)
279 ip.define_magic('mycommand', func)
295
280
296 Type ``%magic`` for more information, including a list of all available magic
281 Type ``%magic`` for more information, including a list of all available magic
297 functions at any time and their docstrings. You can also type
282 functions at any time and their docstrings. You can also type
298 ``%magic_function_name?`` (see :ref:`below <dynamic_object_info>` for
283 ``%magic_function_name?`` (see :ref:`below <dynamic_object_info>` for
299 information on the '?' system) to get information about any particular magic
284 information on the '?' system) to get information about any particular magic
300 function you are interested in.
285 function you are interested in.
301
286
302 The API documentation for the :mod:`IPython.core.magic` module contains the full
287 The API documentation for the :mod:`IPython.core.magic` module contains the full
303 docstrings of all currently available magic commands.
288 docstrings of all currently available magic commands.
304
289
305
290
306 Access to the standard Python help
291 Access to the standard Python help
307 ----------------------------------
292 ----------------------------------
308
293
309 Simply type ``help()`` to access Python's standard help system. You can
294 Simply type ``help()`` to access Python's standard help system. You can
310 also type ``help(object)`` for information about a given object, or
295 also type ``help(object)`` for information about a given object, or
311 ``help('keyword')`` for information on a keyword. You may need to configure your
296 ``help('keyword')`` for information on a keyword. You may need to configure your
312 PYTHONDOCS environment variable for this feature to work correctly.
297 PYTHONDOCS environment variable for this feature to work correctly.
313
298
314 .. _dynamic_object_info:
299 .. _dynamic_object_info:
315
300
316 Dynamic object information
301 Dynamic object information
317 --------------------------
302 --------------------------
318
303
319 Typing ``?word`` or ``word?`` prints detailed information about an object. If
304 Typing ``?word`` or ``word?`` prints detailed information about an object. If
320 certain strings in the object are too long (e.g. function signatures) they get
305 certain strings in the object are too long (e.g. function signatures) they get
321 snipped in the center for brevity. This system gives access variable types and
306 snipped in the center for brevity. This system gives access variable types and
322 values, docstrings, function prototypes and other useful information.
307 values, docstrings, function prototypes and other useful information.
323
308
324 If the information will not fit in the terminal, it is displayed in a pager
309 If the information will not fit in the terminal, it is displayed in a pager
325 (``less`` if available, otherwise a basic internal pager).
310 (``less`` if available, otherwise a basic internal pager).
326
311
327 Typing ``??word`` or ``word??`` gives access to the full information, including
312 Typing ``??word`` or ``word??`` gives access to the full information, including
328 the source code where possible. Long strings are not snipped.
313 the source code where possible. Long strings are not snipped.
329
314
330 The following magic functions are particularly useful for gathering
315 The following magic functions are particularly useful for gathering
331 information about your working environment. You can get more details by
316 information about your working environment. You can get more details by
332 typing ``%magic`` or querying them individually (``%function_name?``);
317 typing ``%magic`` or querying them individually (``%function_name?``);
333 this is just a summary:
318 this is just a summary:
334
319
335 * **%pdoc <object>**: Print (or run through a pager if too long) the
320 * **%pdoc <object>**: Print (or run through a pager if too long) the
336 docstring for an object. If the given object is a class, it will
321 docstring for an object. If the given object is a class, it will
337 print both the class and the constructor docstrings.
322 print both the class and the constructor docstrings.
338 * **%pdef <object>**: Print the call signature for any callable
323 * **%pdef <object>**: Print the call signature for any callable
339 object. If the object is a class, print the constructor information.
324 object. If the object is a class, print the constructor information.
340 * **%psource <object>**: Print (or run through a pager if too long)
325 * **%psource <object>**: Print (or run through a pager if too long)
341 the source code for an object.
326 the source code for an object.
342 * **%pfile <object>**: Show the entire source file where an object was
327 * **%pfile <object>**: Show the entire source file where an object was
343 defined via a pager, opening it at the line where the object
328 defined via a pager, opening it at the line where the object
344 definition begins.
329 definition begins.
345 * **%who/%whos**: These functions give information about identifiers
330 * **%who/%whos**: These functions give information about identifiers
346 you have defined interactively (not things you loaded or defined
331 you have defined interactively (not things you loaded or defined
347 in your configuration files). %who just prints a list of
332 in your configuration files). %who just prints a list of
348 identifiers and %whos prints a table with some basic details about
333 identifiers and %whos prints a table with some basic details about
349 each identifier.
334 each identifier.
350
335
351 Note that the dynamic object information functions (?/??, ``%pdoc``,
336 Note that the dynamic object information functions (?/??, ``%pdoc``,
352 ``%pfile``, ``%pdef``, ``%psource``) work on object attributes, as well as
337 ``%pfile``, ``%pdef``, ``%psource``) work on object attributes, as well as
353 directly on variables. For example, after doing ``import os``, you can use
338 directly on variables. For example, after doing ``import os``, you can use
354 ``os.path.abspath??``.
339 ``os.path.abspath??``.
355
340
356 .. _readline:
341 .. _readline:
357
342
358 Readline-based features
343 Readline-based features
359 -----------------------
344 -----------------------
360
345
361 These features require the GNU readline library, so they won't work if your
346 These features require the GNU readline library, so they won't work if your
362 Python installation lacks readline support. We will first describe the default
347 Python installation lacks readline support. We will first describe the default
363 behavior IPython uses, and then how to change it to suit your preferences.
348 behavior IPython uses, and then how to change it to suit your preferences.
364
349
365
350
366 Command line completion
351 Command line completion
367 +++++++++++++++++++++++
352 +++++++++++++++++++++++
368
353
369 At any time, hitting TAB will complete any available python commands or
354 At any time, hitting TAB will complete any available python commands or
370 variable names, and show you a list of the possible completions if
355 variable names, and show you a list of the possible completions if
371 there's no unambiguous one. It will also complete filenames in the
356 there's no unambiguous one. It will also complete filenames in the
372 current directory if no python names match what you've typed so far.
357 current directory if no python names match what you've typed so far.
373
358
374
359
375 Search command history
360 Search command history
376 ++++++++++++++++++++++
361 ++++++++++++++++++++++
377
362
378 IPython provides two ways for searching through previous input and thus
363 IPython provides two ways for searching through previous input and thus
379 reduce the need for repetitive typing:
364 reduce the need for repetitive typing:
380
365
381 1. Start typing, and then use Ctrl-p (previous,up) and Ctrl-n
366 1. Start typing, and then use the up and down arrow keys (or :kbd:`Ctrl-p`
382 (next,down) to search through only the history items that match
367 and :kbd:`Ctrl-n`) to search through only the history items that match
383 what you've typed so far. If you use Ctrl-p/Ctrl-n at a blank
368 what you've typed so far.
384 prompt, they just behave like normal arrow keys.
369 2. Hit :kbd:`Ctrl-r`: to open a search prompt. Begin typing and the system
385 2. Hit Ctrl-r: opens a search prompt. Begin typing and the system
386 searches your history for lines that contain what you've typed so
370 searches your history for lines that contain what you've typed so
387 far, completing as much as it can.
371 far, completing as much as it can.
388
372
389
390 Persistent command history across sessions
391 ++++++++++++++++++++++++++++++++++++++++++
392
393 IPython will save your input history when it leaves and reload it next
373 IPython will save your input history when it leaves and reload it next
394 time you restart it. By default, the history file is named
374 time you restart it. By default, the history file is named
395 $IPYTHONDIR/profile_<name>/history.sqlite. This allows you to keep
375 :file:`.ipython/profile_{name}/history.sqlite`.
396 separate histories related to various tasks: commands related to
397 numerical work will not be clobbered by a system shell history, for
398 example.
399
400
376
401 Autoindent
377 Autoindent
402 ++++++++++
378 ++++++++++
403
379
404 IPython can recognize lines ending in ':' and indent the next line,
380 IPython can recognize lines ending in ':' and indent the next line,
405 while also un-indenting automatically after 'raise' or 'return'.
381 while also un-indenting automatically after 'raise' or 'return'.
406
382
407 This feature uses the readline library, so it will honor your
383 This feature uses the readline library, so it will honor your
408 :file:`~/.inputrc` configuration (or whatever file your INPUTRC variable points
384 :file:`~/.inputrc` configuration (or whatever file your :envvar:`INPUTRC` environment variable points
409 to). Adding the following lines to your :file:`.inputrc` file can make
385 to). Adding the following lines to your :file:`.inputrc` file can make
410 indenting/unindenting more convenient (M-i indents, M-u unindents)::
386 indenting/unindenting more convenient (M-i indents, M-u unindents)::
411
387
412 # if you don't already have a ~/.inputrc file, you need this include:
388 # if you don't already have a ~/.inputrc file, you need this include:
413 $include /etc/inputrc
389 $include /etc/inputrc
414
390
415 $if Python
391 $if Python
416 "\M-i": " "
392 "\M-i": " "
417 "\M-u": "\d\d\d\d"
393 "\M-u": "\d\d\d\d"
418 $endif
394 $endif
419
395
420 Note that there are 4 spaces between the quote marks after "M-i" above.
396 Note that there are 4 spaces between the quote marks after "M-i" above.
421
397
422 .. warning::
398 .. warning::
423
399
424 Setting the above indents will cause problems with unicode text entry in
400 Setting the above indents will cause problems with unicode text entry in
425 the terminal.
401 the terminal.
426
402
427 .. warning::
403 .. warning::
428
404
429 Autoindent is ON by default, but it can cause problems with the pasting of
405 Autoindent is ON by default, but it can cause problems with the pasting of
430 multi-line indented code (the pasted code gets re-indented on each line). A
406 multi-line indented code (the pasted code gets re-indented on each line). A
431 magic function %autoindent allows you to toggle it on/off at runtime. You
407 magic function %autoindent allows you to toggle it on/off at runtime. You
432 can also disable it permanently on in your :file:`ipython_config.py` file
408 can also disable it permanently on in your :file:`ipython_config.py` file
433 (set TerminalInteractiveShell.autoindent=False).
409 (set TerminalInteractiveShell.autoindent=False).
434
410
435 If you want to paste multiple lines in the terminal, it is recommended that
411 If you want to paste multiple lines in the terminal, it is recommended that
436 you use ``%paste``.
412 you use ``%paste``.
437
413
438
414
439 Customizing readline behavior
415 Customizing readline behavior
440 +++++++++++++++++++++++++++++
416 +++++++++++++++++++++++++++++
441
417
442 All these features are based on the GNU readline library, which has an
418 All these features are based on the GNU readline library, which has an
443 extremely customizable interface. Normally, readline is configured via a
419 extremely customizable interface. Normally, readline is configured via a
444 file which defines the behavior of the library; the details of the
420 :file:`.inputrc` file. IPython respects this, and you can also customise readline
445 syntax for this can be found in the readline documentation available
421 by setting the following :doc:`configuration </config/intro>` options:
446 with your system or on the Internet. IPython doesn't read this file (if
422
447 it exists) directly, but it does support passing to readline valid
423 * ``InteractiveShell.readline_parse_and_bind``: this holds a list of strings to be executed
448 options via a simple interface. In brief, you can customize readline by
449 setting the following options in your configuration file (note
450 that these options can not be specified at the command line):
451
452 * **readline_parse_and_bind**: this holds a list of strings to be executed
453 via a readline.parse_and_bind() command. The syntax for valid commands
424 via a readline.parse_and_bind() command. The syntax for valid commands
454 of this kind can be found by reading the documentation for the GNU
425 of this kind can be found by reading the documentation for the GNU
455 readline library, as these commands are of the kind which readline
426 readline library, as these commands are of the kind which readline
456 accepts in its configuration file.
427 accepts in its configuration file.
457 * **readline_remove_delims**: a string of characters to be removed
428 * ``InteractiveShell.readline_remove_delims``: a string of characters to be removed
458 from the default word-delimiters list used by readline, so that
429 from the default word-delimiters list used by readline, so that
459 completions may be performed on strings which contain them. Do not
430 completions may be performed on strings which contain them. Do not
460 change the default value unless you know what you're doing.
431 change the default value unless you know what you're doing.
461
432
462 You will find the default values in your configuration file.
433 You will find the default values in your configuration file.
463
434
464
435
465 Session logging and restoring
436 Session logging and restoring
466 -----------------------------
437 -----------------------------
467
438
468 You can log all input from a session either by starting IPython with the
439 You can log all input from a session either by starting IPython with the
469 command line switch ``--logfile=foo.py`` (see :ref:`here <command_line_options>`)
440 command line switch ``--logfile=foo.py`` (see :ref:`here <command_line_options>`)
470 or by activating the logging at any moment with the magic function %logstart.
441 or by activating the logging at any moment with the magic function %logstart.
471
442
472 Log files can later be reloaded by running them as scripts and IPython
443 Log files can later be reloaded by running them as scripts and IPython
473 will attempt to 'replay' the log by executing all the lines in it, thus
444 will attempt to 'replay' the log by executing all the lines in it, thus
474 restoring the state of a previous session. This feature is not quite
445 restoring the state of a previous session. This feature is not quite
475 perfect, but can still be useful in many cases.
446 perfect, but can still be useful in many cases.
476
447
477 The log files can also be used as a way to have a permanent record of
448 The log files can also be used as a way to have a permanent record of
478 any code you wrote while experimenting. Log files are regular text files
449 any code you wrote while experimenting. Log files are regular text files
479 which you can later open in your favorite text editor to extract code or
450 which you can later open in your favorite text editor to extract code or
480 to 'clean them up' before using them to replay a session.
451 to 'clean them up' before using them to replay a session.
481
452
482 The `%logstart` function for activating logging in mid-session is used as
453 The `%logstart` function for activating logging in mid-session is used as
483 follows::
454 follows::
484
455
485 %logstart [log_name [log_mode]]
456 %logstart [log_name [log_mode]]
486
457
487 If no name is given, it defaults to a file named 'ipython_log.py' in your
458 If no name is given, it defaults to a file named 'ipython_log.py' in your
488 current working directory, in 'rotate' mode (see below).
459 current working directory, in 'rotate' mode (see below).
489
460
490 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
461 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
491 history up to that point and then continues logging.
462 history up to that point and then continues logging.
492
463
493 %logstart takes a second optional parameter: logging mode. This can be
464 %logstart takes a second optional parameter: logging mode. This can be
494 one of (note that the modes are given unquoted):
465 one of (note that the modes are given unquoted):
495
466
496 * [over:] overwrite existing log_name.
467 * [over:] overwrite existing log_name.
497 * [backup:] rename (if exists) to log_name~ and start log_name.
468 * [backup:] rename (if exists) to log_name~ and start log_name.
498 * [append:] well, that says it.
469 * [append:] well, that says it.
499 * [rotate:] create rotating logs log_name.1~, log_name.2~, etc.
470 * [rotate:] create rotating logs log_name.1~, log_name.2~, etc.
500
471
501 The %logoff and %logon functions allow you to temporarily stop and
472 The %logoff and %logon functions allow you to temporarily stop and
502 resume logging to a file which had previously been started with
473 resume logging to a file which had previously been started with
503 %logstart. They will fail (with an explanation) if you try to use them
474 %logstart. They will fail (with an explanation) if you try to use them
504 before logging has been started.
475 before logging has been started.
505
476
506 .. _system_shell_access:
477 .. _system_shell_access:
507
478
508 System shell access
479 System shell access
509 -------------------
480 -------------------
510
481
511 Any input line beginning with a ! character is passed verbatim (minus
482 Any input line beginning with a ! character is passed verbatim (minus
512 the !, of course) to the underlying operating system. For example,
483 the !, of course) to the underlying operating system. For example,
513 typing ``!ls`` will run 'ls' in the current directory.
484 typing ``!ls`` will run 'ls' in the current directory.
514
485
515 Manual capture of command output
486 Manual capture of command output
516 --------------------------------
487 --------------------------------
517
488
518 You can assign the result of a system command to a Python variable with the
489 You can assign the result of a system command to a Python variable with the
519 syntax ``myfiles = !ls``. This gets machine readable output from stdout
490 syntax ``myfiles = !ls``. This gets machine readable output from stdout
520 (e.g. without colours), and splits on newlines. To explicitly get this sort of
491 (e.g. without colours), and splits on newlines. To explicitly get this sort of
521 output without assigning to a variable, use two exclamation marks (``!!ls``) or
492 output without assigning to a variable, use two exclamation marks (``!!ls``) or
522 the ``%sx`` magic command.
493 the ``%sx`` magic command.
523
494
524 The captured list has some convenience features. ``myfiles.n`` or ``myfiles.s``
495 The captured list has some convenience features. ``myfiles.n`` or ``myfiles.s``
525 returns a string delimited by newlines or spaces, respectively. ``myfiles.p``
496 returns a string delimited by newlines or spaces, respectively. ``myfiles.p``
526 produces `path objects <http://pypi.python.org/pypi/path.py>`_ from the list items.
497 produces `path objects <http://pypi.python.org/pypi/path.py>`_ from the list items.
527 See :ref:`string_lists` for details.
498 See :ref:`string_lists` for details.
528
499
529 IPython also allows you to expand the value of python variables when
500 IPython also allows you to expand the value of python variables when
530 making system calls. Wrap variables or expressions in {braces}::
501 making system calls. Wrap variables or expressions in {braces}::
531
502
532 In [1]: pyvar = 'Hello world'
503 In [1]: pyvar = 'Hello world'
533 In [2]: !echo "A python variable: {pyvar}"
504 In [2]: !echo "A python variable: {pyvar}"
534 A python variable: Hello world
505 A python variable: Hello world
535 In [3]: import math
506 In [3]: import math
536 In [4]: x = 8
507 In [4]: x = 8
537 In [5]: !echo {math.factorial(x)}
508 In [5]: !echo {math.factorial(x)}
538 40320
509 40320
539
510
540 For simple cases, you can alternatively prepend $ to a variable name::
511 For simple cases, you can alternatively prepend $ to a variable name::
541
512
542 In [6]: !echo $sys.argv
513 In [6]: !echo $sys.argv
543 [/home/fperez/usr/bin/ipython]
514 [/home/fperez/usr/bin/ipython]
544 In [7]: !echo "A system variable: $$HOME" # Use $$ for literal $
515 In [7]: !echo "A system variable: $$HOME" # Use $$ for literal $
545 A system variable: /home/fperez
516 A system variable: /home/fperez
546
517
547 System command aliases
518 System command aliases
548 ----------------------
519 ----------------------
549
520
550 The %alias magic function allows you to define magic functions which are in fact
521 The %alias magic function allows you to define magic functions which are in fact
551 system shell commands. These aliases can have parameters.
522 system shell commands. These aliases can have parameters.
552
523
553 ``%alias alias_name cmd`` defines 'alias_name' as an alias for 'cmd'
524 ``%alias alias_name cmd`` defines 'alias_name' as an alias for 'cmd'
554
525
555 Then, typing ``alias_name params`` will execute the system command 'cmd
526 Then, typing ``alias_name params`` will execute the system command 'cmd
556 params' (from your underlying operating system).
527 params' (from your underlying operating system).
557
528
558 You can also define aliases with parameters using %s specifiers (one per
529 You can also define aliases with parameters using %s specifiers (one per
559 parameter). The following example defines the parts function as an
530 parameter). The following example defines the parts function as an
560 alias to the command 'echo first %s second %s' where each %s will be
531 alias to the command 'echo first %s second %s' where each %s will be
561 replaced by a positional parameter to the call to %parts::
532 replaced by a positional parameter to the call to %parts::
562
533
563 In [1]: %alias parts echo first %s second %s
534 In [1]: %alias parts echo first %s second %s
564 In [2]: parts A B
535 In [2]: parts A B
565 first A second B
536 first A second B
566 In [3]: parts A
537 In [3]: parts A
567 ERROR: Alias <parts> requires 2 arguments, 1 given.
538 ERROR: Alias <parts> requires 2 arguments, 1 given.
568
539
569 If called with no parameters, %alias prints the table of currently
540 If called with no parameters, %alias prints the table of currently
570 defined aliases.
541 defined aliases.
571
542
572 The %rehashx magic allows you to load your entire $PATH as
543 The %rehashx magic allows you to load your entire $PATH as
573 ipython aliases. See its docstring for further details.
544 ipython aliases. See its docstring for further details.
574
545
575
546
576 .. _dreload:
547 .. _dreload:
577
548
578 Recursive reload
549 Recursive reload
579 ----------------
550 ----------------
580
551
581 The :mod:`IPython.lib.deepreload` module allows you to recursively reload a
552 The :mod:`IPython.lib.deepreload` module allows you to recursively reload a
582 module: changes made to any of its dependencies will be reloaded without
553 module: changes made to any of its dependencies will be reloaded without
583 having to exit. To start using it, do::
554 having to exit. To start using it, do::
584
555
585 from IPython.lib.deepreload import reload as dreload
556 from IPython.lib.deepreload import reload as dreload
586
557
587
558
588 Verbose and colored exception traceback printouts
559 Verbose and colored exception traceback printouts
589 -------------------------------------------------
560 -------------------------------------------------
590
561
591 IPython provides the option to see very detailed exception tracebacks,
562 IPython provides the option to see very detailed exception tracebacks,
592 which can be especially useful when debugging large programs. You can
563 which can be especially useful when debugging large programs. You can
593 run any Python file with the %run function to benefit from these
564 run any Python file with the %run function to benefit from these
594 detailed tracebacks. Furthermore, both normal and verbose tracebacks can
565 detailed tracebacks. Furthermore, both normal and verbose tracebacks can
595 be colored (if your terminal supports it) which makes them much easier
566 be colored (if your terminal supports it) which makes them much easier
596 to parse visually.
567 to parse visually.
597
568
598 See the magic xmode and colors functions for details (just type %magic).
569 See the magic xmode and colors functions for details.
599
570
600 These features are basically a terminal version of Ka-Ping Yee's cgitb
571 These features are basically a terminal version of Ka-Ping Yee's cgitb
601 module, now part of the standard Python library.
572 module, now part of the standard Python library.
602
573
603
574
604 .. _input_caching:
575 .. _input_caching:
605
576
606 Input caching system
577 Input caching system
607 --------------------
578 --------------------
608
579
609 IPython offers numbered prompts (In/Out) with input and output caching
580 IPython offers numbered prompts (In/Out) with input and output caching
610 (also referred to as 'input history'). All input is saved and can be
581 (also referred to as 'input history'). All input is saved and can be
611 retrieved as variables (besides the usual arrow key recall), in
582 retrieved as variables (besides the usual arrow key recall), in
612 addition to the %rep magic command that brings a history entry
583 addition to the %rep magic command that brings a history entry
613 up for editing on the next command line.
584 up for editing on the next command line.
614
585
615 The following GLOBAL variables always exist (so don't overwrite them!):
586 The following variables always exist:
616
587
617 * _i, _ii, _iii: store previous, next previous and next-next previous inputs.
588 * _i, _ii, _iii: store previous, next previous and next-next previous inputs.
618 * In, _ih : a list of all inputs; _ih[n] is the input from line n. If you
589 * In, _ih : a list of all inputs; _ih[n] is the input from line n. If you
619 overwrite In with a variable of your own, you can remake the assignment to the
590 overwrite In with a variable of your own, you can remake the assignment to the
620 internal list with a simple ``In=_ih``.
591 internal list with a simple ``In=_ih``.
621
592
622 Additionally, global variables named _i<n> are dynamically created (<n>
593 Additionally, global variables named _i<n> are dynamically created (<n>
623 being the prompt counter), so ``_i<n> == _ih[<n>] == In[<n>]``.
594 being the prompt counter), so ``_i<n> == _ih[<n>] == In[<n>]``.
624
595
625 For example, what you typed at prompt 14 is available as _i14, _ih[14]
596 For example, what you typed at prompt 14 is available as ``_i14``, ``_ih[14]``
626 and In[14].
597 and ``In[14]``.
627
598
628 This allows you to easily cut and paste multi line interactive prompts
599 This allows you to easily cut and paste multi line interactive prompts
629 by printing them out: they print like a clean string, without prompt
600 by printing them out: they print like a clean string, without prompt
630 characters. You can also manipulate them like regular variables (they
601 characters. You can also manipulate them like regular variables (they
631 are strings), modify or exec them (typing ``exec _i9`` will re-execute the
602 are strings), modify or exec them.
632 contents of input prompt 9.
633
603
634 You can also re-execute multiple lines of input easily by using the
604 You can also re-execute multiple lines of input easily by using the
635 magic %rerun or %macro functions. The macro system also allows you to re-execute
605 magic %rerun or %macro functions. The macro system also allows you to re-execute
636 previous lines which include magic function calls (which require special
606 previous lines which include magic function calls (which require special
637 processing). Type %macro? for more details on the macro system.
607 processing). Type %macro? for more details on the macro system.
638
608
639 A history function %hist allows you to see any part of your input
609 A history function %hist allows you to see any part of your input
640 history by printing a range of the _i variables.
610 history by printing a range of the _i variables.
641
611
642 You can also search ('grep') through your history by typing
612 You can also search ('grep') through your history by typing
643 ``%hist -g somestring``. This is handy for searching for URLs, IP addresses,
613 ``%hist -g somestring``. This is handy for searching for URLs, IP addresses,
644 etc. You can bring history entries listed by '%hist -g' up for editing
614 etc. You can bring history entries listed by '%hist -g' up for editing
645 with the %recall command, or run them immediately with %rerun.
615 with the %recall command, or run them immediately with %rerun.
646
616
647 .. _output_caching:
617 .. _output_caching:
648
618
649 Output caching system
619 Output caching system
650 ---------------------
620 ---------------------
651
621
652 For output that is returned from actions, a system similar to the input
622 For output that is returned from actions, a system similar to the input
653 cache exists but using _ instead of _i. Only actions that produce a
623 cache exists but using _ instead of _i. Only actions that produce a
654 result (NOT assignments, for example) are cached. If you are familiar
624 result (NOT assignments, for example) are cached. If you are familiar
655 with Mathematica, IPython's _ variables behave exactly like
625 with Mathematica, IPython's _ variables behave exactly like
656 Mathematica's % variables.
626 Mathematica's % variables.
657
627
658 The following GLOBAL variables always exist (so don't overwrite them!):
628 The following variables always exist:
659
629
660 * [_] (a single underscore) : stores previous output, like Python's
630 * [_] (a single underscore): stores previous output, like Python's
661 default interpreter.
631 default interpreter.
662 * [__] (two underscores): next previous.
632 * [__] (two underscores): next previous.
663 * [___] (three underscores): next-next previous.
633 * [___] (three underscores): next-next previous.
664
634
665 Additionally, global variables named _<n> are dynamically created (<n>
635 Additionally, global variables named _<n> are dynamically created (<n>
666 being the prompt counter), such that the result of output <n> is always
636 being the prompt counter), such that the result of output <n> is always
667 available as _<n> (don't use the angle brackets, just the number, e.g.
637 available as _<n> (don't use the angle brackets, just the number, e.g.
668 _21).
638 ``_21``).
669
639
670 These variables are also stored in a global dictionary (not a
640 These variables are also stored in a global dictionary (not a
671 list, since it only has entries for lines which returned a result)
641 list, since it only has entries for lines which returned a result)
672 available under the names _oh and Out (similar to _ih and In). So the
642 available under the names _oh and Out (similar to _ih and In). So the
673 output from line 12 can be obtained as _12, Out[12] or _oh[12]. If you
643 output from line 12 can be obtained as ``_12``, ``Out[12]`` or ``_oh[12]``. If you
674 accidentally overwrite the Out variable you can recover it by typing
644 accidentally overwrite the Out variable you can recover it by typing
675 'Out=_oh' at the prompt.
645 ``Out=_oh`` at the prompt.
676
646
677 This system obviously can potentially put heavy memory demands on your
647 This system obviously can potentially put heavy memory demands on your
678 system, since it prevents Python's garbage collector from removing any
648 system, since it prevents Python's garbage collector from removing any
679 previously computed results. You can control how many results are kept
649 previously computed results. You can control how many results are kept
680 in memory with the option (at the command line or in your configuration
650 in memory with the configuration option ``InteractiveShell.cache_size``.
681 file) cache_size. If you set it to 0, the whole system is completely
651 If you set it to 0, output caching is disabled. You can also use the ``%reset``
682 disabled and the prompts revert to the classic '>>>' of normal Python.
652 and ``%xdel`` magics to clear large items from memory.
683
684
653
685 Directory history
654 Directory history
686 -----------------
655 -----------------
687
656
688 Your history of visited directories is kept in the global list _dh, and
657 Your history of visited directories is kept in the global list _dh, and
689 the magic %cd command can be used to go to any entry in that list. The
658 the magic %cd command can be used to go to any entry in that list. The
690 %dhist command allows you to view this history. Do ``cd -<TAB>`` to
659 %dhist command allows you to view this history. Do ``cd -<TAB>`` to
691 conveniently view the directory history.
660 conveniently view the directory history.
692
661
693
662
694 Automatic parentheses and quotes
663 Automatic parentheses and quotes
695 --------------------------------
664 --------------------------------
696
665
697 These features were adapted from Nathan Gray's LazyPython. They are
666 These features were adapted from Nathan Gray's LazyPython. They are
698 meant to allow less typing for common situations.
667 meant to allow less typing for common situations.
699
668
700
701 Automatic parentheses
702 +++++++++++++++++++++
703
704 Callable objects (i.e. functions, methods, etc) can be invoked like this
669 Callable objects (i.e. functions, methods, etc) can be invoked like this
705 (notice the commas between the arguments)::
670 (notice the commas between the arguments)::
706
671
707 In [1]: callable_ob arg1, arg2, arg3
672 In [1]: callable_ob arg1, arg2, arg3
708 ------> callable_ob(arg1, arg2, arg3)
673 ------> callable_ob(arg1, arg2, arg3)
709
674
675 .. note::
676 This feature is disabled by default. To enable it, use the ``%autocall``
677 magic command. The commands below with special prefixes will always work,
678 however.
679
710 You can force automatic parentheses by using '/' as the first character
680 You can force automatic parentheses by using '/' as the first character
711 of a line. For example::
681 of a line. For example::
712
682
713 In [2]: /globals # becomes 'globals()'
683 In [2]: /globals # becomes 'globals()'
714
684
715 Note that the '/' MUST be the first character on the line! This won't work::
685 Note that the '/' MUST be the first character on the line! This won't work::
716
686
717 In [3]: print /globals # syntax error
687 In [3]: print /globals # syntax error
718
688
719 In most cases the automatic algorithm should work, so you should rarely
689 In most cases the automatic algorithm should work, so you should rarely
720 need to explicitly invoke /. One notable exception is if you are trying
690 need to explicitly invoke /. One notable exception is if you are trying
721 to call a function with a list of tuples as arguments (the parenthesis
691 to call a function with a list of tuples as arguments (the parenthesis
722 will confuse IPython)::
692 will confuse IPython)::
723
693
724 In [4]: zip (1,2,3),(4,5,6) # won't work
694 In [4]: zip (1,2,3),(4,5,6) # won't work
725
695
726 but this will work::
696 but this will work::
727
697
728 In [5]: /zip (1,2,3),(4,5,6)
698 In [5]: /zip (1,2,3),(4,5,6)
729 ------> zip ((1,2,3),(4,5,6))
699 ------> zip ((1,2,3),(4,5,6))
730 Out[5]: [(1, 4), (2, 5), (3, 6)]
700 Out[5]: [(1, 4), (2, 5), (3, 6)]
731
701
732 IPython tells you that it has altered your command line by displaying
702 IPython tells you that it has altered your command line by displaying
733 the new command line preceded by ->. e.g.::
703 the new command line preceded by ``--->``.
734
735 In [6]: callable list
736 ------> callable(list)
737
704
738
705 You can force automatic quoting of a function's arguments by using ``,``
739 Automatic quoting
706 or ``;`` as the first character of a line. For example::
740 +++++++++++++++++
741
742 You can force automatic quoting of a function's arguments by using ','
743 or ';' as the first character of a line. For example::
744
707
745 In [1]: ,my_function /home/me # becomes my_function("/home/me")
708 In [1]: ,my_function /home/me # becomes my_function("/home/me")
746
709
747 If you use ';' the whole argument is quoted as a single string, while ',' splits
710 If you use ';' the whole argument is quoted as a single string, while ',' splits
748 on whitespace::
711 on whitespace::
749
712
750 In [2]: ,my_function a b c # becomes my_function("a","b","c")
713 In [2]: ,my_function a b c # becomes my_function("a","b","c")
751
714
752 In [3]: ;my_function a b c # becomes my_function("a b c")
715 In [3]: ;my_function a b c # becomes my_function("a b c")
753
716
754 Note that the ',' or ';' MUST be the first character on the line! This
717 Note that the ',' or ';' MUST be the first character on the line! This
755 won't work::
718 won't work::
756
719
757 In [4]: x = ,my_function /home/me # syntax error
720 In [4]: x = ,my_function /home/me # syntax error
758
721
759 IPython as your default Python environment
722 IPython as your default Python environment
760 ==========================================
723 ==========================================
761
724
762 Python honors the environment variable :envvar:`PYTHONSTARTUP` and will
725 Python honors the environment variable :envvar:`PYTHONSTARTUP` and will
763 execute at startup the file referenced by this variable. If you put the
726 execute at startup the file referenced by this variable. If you put the
764 following code at the end of that file, then IPython will be your working
727 following code at the end of that file, then IPython will be your working
765 environment anytime you start Python::
728 environment anytime you start Python::
766
729
767 import os, IPython
730 import os, IPython
768 os.environ['PYTHONSTARTUP'] = '' # Prevent running this again
731 os.environ['PYTHONSTARTUP'] = '' # Prevent running this again
769 IPython.start_ipython()
732 IPython.start_ipython()
770 raise SystemExit
733 raise SystemExit
771
734
772 The ``raise SystemExit`` is needed to exit Python when
735 The ``raise SystemExit`` is needed to exit Python when
773 it finishes, otherwise you'll be back at the normal Python '>>>'
736 it finishes, otherwise you'll be back at the normal Python ``>>>``
774 prompt.
737 prompt.
775
738
776 This is probably useful to developers who manage multiple Python
739 This is probably useful to developers who manage multiple Python
777 versions and don't want to have correspondingly multiple IPython
740 versions and don't want to have correspondingly multiple IPython
778 versions. Note that in this mode, there is no way to pass IPython any
741 versions. Note that in this mode, there is no way to pass IPython any
779 command-line options, as those are trapped first by Python itself.
742 command-line options, as those are trapped first by Python itself.
780
743
781 .. _Embedding:
744 .. _Embedding:
782
745
783 Embedding IPython
746 Embedding IPython
784 =================
747 =================
785
748
786 You can start a regular IPython session with
749 You can start a regular IPython session with
787
750
788 .. sourcecode:: python
751 .. sourcecode:: python
789
752
790 import IPython
753 import IPython
791 IPython.start_ipython()
754 IPython.start_ipython(argv=[])
792
755
793 at any point in your program. This will load IPython configuration,
756 at any point in your program. This will load IPython configuration,
794 startup files, and everything, just as if it were a normal IPython session.
757 startup files, and everything, just as if it were a normal IPython session.
795 In addition to this,
758
796 it is possible to embed an IPython instance inside your own Python programs.
759 It is also possible to embed an IPython shell in a namespace in your Python code.
797 This allows you to evaluate dynamically the state of your code,
760 This allows you to evaluate dynamically the state of your code,
798 operate with your variables, analyze them, etc. Note however that
761 operate with your variables, analyze them, etc. Note however that
799 any changes you make to values while in the shell do not propagate back
762 any changes you make to values while in the shell do not propagate back
800 to the running code, so it is safe to modify your values because you
763 to the running code, so it is safe to modify your values because you
801 won't break your code in bizarre ways by doing so.
764 won't break your code in bizarre ways by doing so.
802
765
803 .. note::
766 .. note::
804
767
805 At present, embedding IPython cannot be done from inside IPython.
768 At present, embedding IPython cannot be done from inside IPython.
806 Run the code samples below outside IPython.
769 Run the code samples below outside IPython.
807
770
808 This feature allows you to easily have a fully functional python
771 This feature allows you to easily have a fully functional python
809 environment for doing object introspection anywhere in your code with a
772 environment for doing object introspection anywhere in your code with a
810 simple function call. In some cases a simple print statement is enough,
773 simple function call. In some cases a simple print statement is enough,
811 but if you need to do more detailed analysis of a code fragment this
774 but if you need to do more detailed analysis of a code fragment this
812 feature can be very valuable.
775 feature can be very valuable.
813
776
814 It can also be useful in scientific computing situations where it is
777 It can also be useful in scientific computing situations where it is
815 common to need to do some automatic, computationally intensive part and
778 common to need to do some automatic, computationally intensive part and
816 then stop to look at data, plots, etc.
779 then stop to look at data, plots, etc.
817 Opening an IPython instance will give you full access to your data and
780 Opening an IPython instance will give you full access to your data and
818 functions, and you can resume program execution once you are done with
781 functions, and you can resume program execution once you are done with
819 the interactive part (perhaps to stop again later, as many times as
782 the interactive part (perhaps to stop again later, as many times as
820 needed).
783 needed).
821
784
822 The following code snippet is the bare minimum you need to include in
785 The following code snippet is the bare minimum you need to include in
823 your Python programs for this to work (detailed examples follow later)::
786 your Python programs for this to work (detailed examples follow later)::
824
787
825 from IPython import embed
788 from IPython import embed
826
789
827 embed() # this call anywhere in your program will start IPython
790 embed() # this call anywhere in your program will start IPython
828
791
829 .. note::
792 You can also embed an IPython *kernel*, for use with qtconsole, etc. via
830
793 ``IPython.embed_kernel()``. This should function work the same way, but you can
831 As of 0.13, you can embed an IPython *kernel*, for use with qtconsole,
794 connect an external frontend (``ipython qtconsole`` or ``ipython console``),
832 etc. via ``IPython.embed_kernel()`` instead of ``IPython.embed()``.
795 rather than interacting with it in the terminal.
833 It should function just the same as regular embed, but you connect
834 an external frontend rather than IPython starting up in the local
835 terminal.
836
796
837 You can run embedded instances even in code which is itself being run at
797 You can run embedded instances even in code which is itself being run at
838 the IPython interactive prompt with '%run <filename>'. Since it's easy
798 the IPython interactive prompt with '%run <filename>'. Since it's easy
839 to get lost as to where you are (in your top-level IPython or in your
799 to get lost as to where you are (in your top-level IPython or in your
840 embedded one), it's a good idea in such cases to set the in/out prompts
800 embedded one), it's a good idea in such cases to set the in/out prompts
841 to something different for the embedded instances. The code examples
801 to something different for the embedded instances. The code examples
842 below illustrate this.
802 below illustrate this.
843
803
844 You can also have multiple IPython instances in your program and open
804 You can also have multiple IPython instances in your program and open
845 them separately, for example with different options for data
805 them separately, for example with different options for data
846 presentation. If you close and open the same instance multiple times,
806 presentation. If you close and open the same instance multiple times,
847 its prompt counters simply continue from each execution to the next.
807 its prompt counters simply continue from each execution to the next.
848
808
849 Please look at the docstrings in the :mod:`~IPython.frontend.terminal.embed`
809 Please look at the docstrings in the :mod:`~IPython.frontend.terminal.embed`
850 module for more details on the use of this system.
810 module for more details on the use of this system.
851
811
852 The following sample file illustrating how to use the embedding
812 The following sample file illustrating how to use the embedding
853 functionality is provided in the examples directory as example-embed.py.
813 functionality is provided in the examples directory as example-embed.py.
854 It should be fairly self-explanatory:
814 It should be fairly self-explanatory:
855
815
856 .. literalinclude:: ../../../examples/core/example-embed.py
816 .. literalinclude:: ../../../examples/core/example-embed.py
857 :language: python
817 :language: python
858
818
859 Once you understand how the system functions, you can use the following
819 Once you understand how the system functions, you can use the following
860 code fragments in your programs which are ready for cut and paste:
820 code fragments in your programs which are ready for cut and paste:
861
821
862 .. literalinclude:: ../../../examples/core/example-embed-short.py
822 .. literalinclude:: ../../../examples/core/example-embed-short.py
863 :language: python
823 :language: python
864
824
865 Using the Python debugger (pdb)
825 Using the Python debugger (pdb)
866 ===============================
826 ===============================
867
827
868 Running entire programs via pdb
828 Running entire programs via pdb
869 -------------------------------
829 -------------------------------
870
830
871 pdb, the Python debugger, is a powerful interactive debugger which
831 pdb, the Python debugger, is a powerful interactive debugger which
872 allows you to step through code, set breakpoints, watch variables,
832 allows you to step through code, set breakpoints, watch variables,
873 etc. IPython makes it very easy to start any script under the control
833 etc. IPython makes it very easy to start any script under the control
874 of pdb, regardless of whether you have wrapped it into a 'main()'
834 of pdb, regardless of whether you have wrapped it into a 'main()'
875 function or not. For this, simply type '%run -d myscript' at an
835 function or not. For this, simply type ``%run -d myscript`` at an
876 IPython prompt. See the %run command's documentation (via '%run?' or
836 IPython prompt. See the %run command's documentation for more details, including
877 in Sec. magic_ for more details, including how to control where pdb
837 how to control where pdb will stop execution first.
878 will stop execution first.
879
880 For more information on the use of the pdb debugger, read the included
881 pdb.doc file (part of the standard Python distribution). On a stock
882 Linux system it is located at /usr/lib/python2.3/pdb.doc, but the
883 easiest way to read it is by using the help() function of the pdb module
884 as follows (in an IPython prompt)::
885
838
886 In [1]: import pdb
839 For more information on the use of the pdb debugger, see :ref:`debugger-commands`
887 In [2]: pdb.help()
840 in the Python documentation.
888
841
889 This will load the pdb.doc document in a file viewer for you automatically.
890
842
843 Post-mortem debugging
844 ---------------------
891
845
892 Automatic invocation of pdb on exceptions
846 Going into a debugger when an exception occurs can be
893 -----------------------------------------
894
895 IPython, if started with the ``--pdb`` option (or if the option is set in
896 your config file) can call the Python pdb debugger every time your code
897 triggers an uncaught exception. This feature
898 can also be toggled at any time with the %pdb magic command. This can be
899 extremely useful in order to find the origin of subtle bugs, because pdb
847 extremely useful in order to find the origin of subtle bugs, because pdb
900 opens up at the point in your code which triggered the exception, and
848 opens up at the point in your code which triggered the exception, and
901 while your program is at this point 'dead', all the data is still
849 while your program is at this point 'dead', all the data is still
902 available and you can walk up and down the stack frame and understand
850 available and you can walk up and down the stack frame and understand
903 the origin of the problem.
851 the origin of the problem.
904
852
905 Furthermore, you can use these debugging facilities both with the
853 You can use the ``%debug`` magic after an exception has occurred to start
906 embedded IPython mode and without IPython at all. For an embedded shell
854 post-mortem debugging. IPython can also call debugger every time your code
907 (see sec. Embedding_), simply call the constructor with
855 triggers an uncaught exception. This feature can be toggled with the %pdb magic
908 ``--pdb`` in the argument string and pdb will automatically be called if an
856 command, or you can start IPython with the ``--pdb`` option.
909 uncaught exception is triggered by your code.
910
857
911 For stand-alone use of the feature in your programs which do not use
858 For a post-mortem debugger in your programs outside IPython,
912 IPython at all, put the following lines toward the top of your 'main'
859 put the following lines toward the top of your 'main' routine::
913 routine::
914
860
915 import sys
861 import sys
916 from IPython.core import ultratb
862 from IPython.core import ultratb
917 sys.excepthook = ultratb.FormattedTB(mode='Verbose',
863 sys.excepthook = ultratb.FormattedTB(mode='Verbose',
918 color_scheme='Linux', call_pdb=1)
864 color_scheme='Linux', call_pdb=1)
919
865
920 The mode keyword can be either 'Verbose' or 'Plain', giving either very
866 The mode keyword can be either 'Verbose' or 'Plain', giving either very
921 detailed or normal tracebacks respectively. The color_scheme keyword can
867 detailed or normal tracebacks respectively. The color_scheme keyword can
922 be one of 'NoColor', 'Linux' (default) or 'LightBG'. These are the same
868 be one of 'NoColor', 'Linux' (default) or 'LightBG'. These are the same
923 options which can be set in IPython with ``--colors`` and ``--xmode``.
869 options which can be set in IPython with ``--colors`` and ``--xmode``.
924
870
925 This will give any of your programs detailed, colored tracebacks with
871 This will give any of your programs detailed, colored tracebacks with
926 automatic invocation of pdb.
872 automatic invocation of pdb.
927
873
928
929 Extensions for syntax processing
930 ================================
931
932 This isn't for the faint of heart, because the potential for breaking
933 things is quite high. But it can be a very powerful and useful feature.
934 In a nutshell, you can redefine the way IPython processes the user input
935 line to accept new, special extensions to the syntax without needing to
936 change any of IPython's own code.
937
938 In the IPython/extensions directory you will find some examples
939 supplied, which we will briefly describe now. These can be used 'as is'
940 (and both provide very useful functionality), or you can use them as a
941 starting point for writing your own extensions.
942
943 .. _pasting_with_prompts:
874 .. _pasting_with_prompts:
944
875
945 Pasting of code starting with Python or IPython prompts
876 Pasting of code starting with Python or IPython prompts
946 -------------------------------------------------------
877 =======================================================
947
878
948 IPython is smart enough to filter out input prompts, be they plain Python ones
879 IPython is smart enough to filter out input prompts, be they plain Python ones
949 (``>>>`` and ``...``) or IPython ones (``In [N]:`` and ``...:``). You can
880 (``>>>`` and ``...``) or IPython ones (``In [N]:`` and ``...:``). You can
950 therefore copy and paste from existing interactive sessions without worry.
881 therefore copy and paste from existing interactive sessions without worry.
951
882
952 The following is a 'screenshot' of how things work, copying an example from the
883 The following is a 'screenshot' of how things work, copying an example from the
953 standard Python tutorial::
884 standard Python tutorial::
954
885
955 In [1]: >>> # Fibonacci series:
886 In [1]: >>> # Fibonacci series:
956
887
957 In [2]: ... # the sum of two elements defines the next
888 In [2]: ... # the sum of two elements defines the next
958
889
959 In [3]: ... a, b = 0, 1
890 In [3]: ... a, b = 0, 1
960
891
961 In [4]: >>> while b < 10:
892 In [4]: >>> while b < 10:
962 ...: ... print(b)
893 ...: ... print(b)
963 ...: ... a, b = b, a+b
894 ...: ... a, b = b, a+b
964 ...:
895 ...:
965 1
896 1
966 1
897 1
967 2
898 2
968 3
899 3
969 5
900 5
970 8
901 8
971
902
972 And pasting from IPython sessions works equally well::
903 And pasting from IPython sessions works equally well::
973
904
974 In [1]: In [5]: def f(x):
905 In [1]: In [5]: def f(x):
975 ...: ...: "A simple function"
906 ...: ...: "A simple function"
976 ...: ...: return x**2
907 ...: ...: return x**2
977 ...: ...:
908 ...: ...:
978
909
979 In [2]: f(3)
910 In [2]: f(3)
980 Out[2]: 9
911 Out[2]: 9
981
912
982 .. _gui_support:
913 .. _gui_support:
983
914
984 GUI event loop support
915 GUI event loop support
985 ======================
916 ======================
986
917
987 .. versionadded:: 0.11
918 .. versionadded:: 0.11
988 The ``%gui`` magic and :mod:`IPython.lib.inputhook`.
919 The ``%gui`` magic and :mod:`IPython.lib.inputhook`.
989
920
990 IPython has excellent support for working interactively with Graphical User
921 IPython has excellent support for working interactively with Graphical User
991 Interface (GUI) toolkits, such as wxPython, PyQt4/PySide, PyGTK and Tk. This is
922 Interface (GUI) toolkits, such as wxPython, PyQt4/PySide, PyGTK and Tk. This is
992 implemented using Python's builtin ``PyOSInputHook`` hook. This implementation
923 implemented using Python's builtin ``PyOSInputHook`` hook. This implementation
993 is extremely robust compared to our previous thread-based version. The
924 is extremely robust compared to our previous thread-based version. The
994 advantages of this are:
925 advantages of this are:
995
926
996 * GUIs can be enabled and disabled dynamically at runtime.
927 * GUIs can be enabled and disabled dynamically at runtime.
997 * The active GUI can be switched dynamically at runtime.
928 * The active GUI can be switched dynamically at runtime.
998 * In some cases, multiple GUIs can run simultaneously with no problems.
929 * In some cases, multiple GUIs can run simultaneously with no problems.
999 * There is a developer API in :mod:`IPython.lib.inputhook` for customizing
930 * There is a developer API in :mod:`IPython.lib.inputhook` for customizing
1000 all of these things.
931 all of these things.
1001
932
1002 For users, enabling GUI event loop integration is simple. You simple use the
933 For users, enabling GUI event loop integration is simple. You simple use the
1003 ``%gui`` magic as follows::
934 ``%gui`` magic as follows::
1004
935
1005 %gui [GUINAME]
936 %gui [GUINAME]
1006
937
1007 With no arguments, ``%gui`` removes all GUI support. Valid ``GUINAME``
938 With no arguments, ``%gui`` removes all GUI support. Valid ``GUINAME``
1008 arguments are ``wx``, ``qt``, ``gtk`` and ``tk``.
939 arguments are ``wx``, ``qt``, ``gtk`` and ``tk``.
1009
940
1010 Thus, to use wxPython interactively and create a running :class:`wx.App`
941 Thus, to use wxPython interactively and create a running :class:`wx.App`
1011 object, do::
942 object, do::
1012
943
1013 %gui wx
944 %gui wx
1014
945
946 You can also start IPython with an event loop set up using the :option:`--gui`
947 flag::
948
949 $ ipython --gui=qt
950
1015 For information on IPython's matplotlib_ integration (and the ``matplotlib``
951 For information on IPython's matplotlib_ integration (and the ``matplotlib``
1016 mode) see :ref:`this section <matplotlib_support>`.
952 mode) see :ref:`this section <matplotlib_support>`.
1017
953
1018 For developers that want to use IPython's GUI event loop integration in the
954 For developers that want to use IPython's GUI event loop integration in the
1019 form of a library, these capabilities are exposed in library form in the
955 form of a library, these capabilities are exposed in library form in the
1020 :mod:`IPython.lib.inputhook` and :mod:`IPython.lib.guisupport` modules.
956 :mod:`IPython.lib.inputhook` and :mod:`IPython.lib.guisupport` modules.
1021 Interested developers should see the module docstrings for more information,
957 Interested developers should see the module docstrings for more information,
1022 but there are a few points that should be mentioned here.
958 but there are a few points that should be mentioned here.
1023
959
1024 First, the ``PyOSInputHook`` approach only works in command line settings
960 First, the ``PyOSInputHook`` approach only works in command line settings
1025 where readline is activated. The integration with various eventloops
961 where readline is activated. The integration with various eventloops
1026 is handled somewhat differently (and more simply) when using the standalone
962 is handled somewhat differently (and more simply) when using the standalone
1027 kernel, as in the qtconsole and notebook.
963 kernel, as in the qtconsole and notebook.
1028
964
1029 Second, when using the ``PyOSInputHook`` approach, a GUI application should
965 Second, when using the ``PyOSInputHook`` approach, a GUI application should
1030 *not* start its event loop. Instead all of this is handled by the
966 *not* start its event loop. Instead all of this is handled by the
1031 ``PyOSInputHook``. This means that applications that are meant to be used both
967 ``PyOSInputHook``. This means that applications that are meant to be used both
1032 in IPython and as standalone apps need to have special code to detects how the
968 in IPython and as standalone apps need to have special code to detects how the
1033 application is being run. We highly recommend using IPython's support for this.
969 application is being run. We highly recommend using IPython's support for this.
1034 Since the details vary slightly between toolkits, we point you to the various
970 Since the details vary slightly between toolkits, we point you to the various
1035 examples in our source directory :file:`examples/lib` that demonstrate
971 examples in our source directory :file:`examples/lib` that demonstrate
1036 these capabilities.
972 these capabilities.
1037
973
1038 Third, unlike previous versions of IPython, we no longer "hijack" (replace
974 Third, unlike previous versions of IPython, we no longer "hijack" (replace
1039 them with no-ops) the event loops. This is done to allow applications that
975 them with no-ops) the event loops. This is done to allow applications that
1040 actually need to run the real event loops to do so. This is often needed to
976 actually need to run the real event loops to do so. This is often needed to
1041 process pending events at critical points.
977 process pending events at critical points.
1042
978
1043 Finally, we also have a number of examples in our source directory
979 Finally, we also have a number of examples in our source directory
1044 :file:`examples/lib` that demonstrate these capabilities.
980 :file:`examples/lib` that demonstrate these capabilities.
1045
981
1046 PyQt and PySide
982 PyQt and PySide
1047 ---------------
983 ---------------
1048
984
1049 .. attempt at explanation of the complete mess that is Qt support
985 .. attempt at explanation of the complete mess that is Qt support
1050
986
1051 When you use ``--gui=qt`` or ``--matplotlib=qt``, IPython can work with either
987 When you use ``--gui=qt`` or ``--matplotlib=qt``, IPython can work with either
1052 PyQt4 or PySide. There are three options for configuration here, because
988 PyQt4 or PySide. There are three options for configuration here, because
1053 PyQt4 has two APIs for QString and QVariant - v1, which is the default on
989 PyQt4 has two APIs for QString and QVariant - v1, which is the default on
1054 Python 2, and the more natural v2, which is the only API supported by PySide.
990 Python 2, and the more natural v2, which is the only API supported by PySide.
1055 v2 is also the default for PyQt4 on Python 3. IPython's code for the QtConsole
991 v2 is also the default for PyQt4 on Python 3. IPython's code for the QtConsole
1056 uses v2, but you can still use any interface in your code, since the
992 uses v2, but you can still use any interface in your code, since the
1057 Qt frontend is in a different process.
993 Qt frontend is in a different process.
1058
994
1059 The default will be to import PyQt4 without configuration of the APIs, thus
995 The default will be to import PyQt4 without configuration of the APIs, thus
1060 matching what most applications would expect. It will fall back of PySide if
996 matching what most applications would expect. It will fall back of PySide if
1061 PyQt4 is unavailable.
997 PyQt4 is unavailable.
1062
998
1063 If specified, IPython will respect the environment variable ``QT_API`` used
999 If specified, IPython will respect the environment variable ``QT_API`` used
1064 by ETS. ETS 4.0 also works with both PyQt4 and PySide, but it requires
1000 by ETS. ETS 4.0 also works with both PyQt4 and PySide, but it requires
1065 PyQt4 to use its v2 API. So if ``QT_API=pyside`` PySide will be used,
1001 PyQt4 to use its v2 API. So if ``QT_API=pyside`` PySide will be used,
1066 and if ``QT_API=pyqt`` then PyQt4 will be used *with the v2 API* for
1002 and if ``QT_API=pyqt`` then PyQt4 will be used *with the v2 API* for
1067 QString and QVariant, so ETS codes like MayaVi will also work with IPython.
1003 QString and QVariant, so ETS codes like MayaVi will also work with IPython.
1068
1004
1069 If you launch IPython in matplotlib mode with ``ipython --matplotlib=qt``,
1005 If you launch IPython in matplotlib mode with ``ipython --matplotlib=qt``,
1070 then IPython will ask matplotlib which Qt library to use (only if QT_API is
1006 then IPython will ask matplotlib which Qt library to use (only if QT_API is
1071 *not set*), via the 'backend.qt4' rcParam. If matplotlib is version 1.0.1 or
1007 *not set*), via the 'backend.qt4' rcParam. If matplotlib is version 1.0.1 or
1072 older, then IPython will always use PyQt4 without setting the v2 APIs, since
1008 older, then IPython will always use PyQt4 without setting the v2 APIs, since
1073 neither v2 PyQt nor PySide work.
1009 neither v2 PyQt nor PySide work.
1074
1010
1075 .. warning::
1011 .. warning::
1076
1012
1077 Note that this means for ETS 4 to work with PyQt4, ``QT_API`` *must* be set
1013 Note that this means for ETS 4 to work with PyQt4, ``QT_API`` *must* be set
1078 to work with IPython's qt integration, because otherwise PyQt4 will be
1014 to work with IPython's qt integration, because otherwise PyQt4 will be
1079 loaded in an incompatible mode.
1015 loaded in an incompatible mode.
1080
1016
1081 It also means that you must *not* have ``QT_API`` set if you want to
1017 It also means that you must *not* have ``QT_API`` set if you want to
1082 use ``--gui=qt`` with code that requires PyQt4 API v1.
1018 use ``--gui=qt`` with code that requires PyQt4 API v1.
1083
1019
1084
1020
1085 .. _matplotlib_support:
1021 .. _matplotlib_support:
1086
1022
1087 Plotting with matplotlib
1023 Plotting with matplotlib
1088 ========================
1024 ========================
1089
1025
1090 matplotlib_ provides high quality 2D and 3D plotting for Python. matplotlib_
1026 matplotlib_ provides high quality 2D and 3D plotting for Python. matplotlib_
1091 can produce plots on screen using a variety of GUI toolkits, including Tk,
1027 can produce plots on screen using a variety of GUI toolkits, including Tk,
1092 PyGTK, PyQt4 and wxPython. It also provides a number of commands useful for
1028 PyGTK, PyQt4 and wxPython. It also provides a number of commands useful for
1093 scientific computing, all with a syntax compatible with that of the popular
1029 scientific computing, all with a syntax compatible with that of the popular
1094 Matlab program.
1030 Matlab program.
1095
1031
1096 To start IPython with matplotlib support, use the ``--matplotlib`` switch. If
1032 To start IPython with matplotlib support, use the ``--matplotlib`` switch. If
1097 IPython is already running, you can run the ``%matplotlib`` magic. If no
1033 IPython is already running, you can run the ``%matplotlib`` magic. If no
1098 arguments are given, IPython will automatically detect your choice of
1034 arguments are given, IPython will automatically detect your choice of
1099 matplotlib backend. You can also request a specific backend with
1035 matplotlib backend. You can also request a specific backend with
1100 ``%matplotlib backend``, where ``backend`` must be one of: 'tk', 'qt', 'wx',
1036 ``%matplotlib backend``, where ``backend`` must be one of: 'tk', 'qt', 'wx',
1101 'gtk', 'osx'. In the web notebook and Qt console, 'inline' is also a valid
1037 'gtk', 'osx'. In the web notebook and Qt console, 'inline' is also a valid
1102 backend value, which produces static figures inlined inside the application
1038 backend value, which produces static figures inlined inside the application
1103 window instead of matplotlib's interactive figures that live in separate
1039 window instead of matplotlib's interactive figures that live in separate
1104 windows.
1040 windows.
1105
1041
1106 .. _interactive_demos:
1042 .. _interactive_demos:
1107
1043
1108 Interactive demos with IPython
1044 Interactive demos with IPython
1109 ==============================
1045 ==============================
1110
1046
1111 IPython ships with a basic system for running scripts interactively in
1047 IPython ships with a basic system for running scripts interactively in
1112 sections, useful when presenting code to audiences. A few tags embedded
1048 sections, useful when presenting code to audiences. A few tags embedded
1113 in comments (so that the script remains valid Python code) divide a file
1049 in comments (so that the script remains valid Python code) divide a file
1114 into separate blocks, and the demo can be run one block at a time, with
1050 into separate blocks, and the demo can be run one block at a time, with
1115 IPython printing (with syntax highlighting) the block before executing
1051 IPython printing (with syntax highlighting) the block before executing
1116 it, and returning to the interactive prompt after each block. The
1052 it, and returning to the interactive prompt after each block. The
1117 interactive namespace is updated after each block is run with the
1053 interactive namespace is updated after each block is run with the
1118 contents of the demo's namespace.
1054 contents of the demo's namespace.
1119
1055
1120 This allows you to show a piece of code, run it and then execute
1056 This allows you to show a piece of code, run it and then execute
1121 interactively commands based on the variables just created. Once you
1057 interactively commands based on the variables just created. Once you
1122 want to continue, you simply execute the next block of the demo. The
1058 want to continue, you simply execute the next block of the demo. The
1123 following listing shows the markup necessary for dividing a script into
1059 following listing shows the markup necessary for dividing a script into
1124 sections for execution as a demo:
1060 sections for execution as a demo:
1125
1061
1126 .. literalinclude:: ../../../examples/lib/example-demo.py
1062 .. literalinclude:: ../../../examples/lib/example-demo.py
1127 :language: python
1063 :language: python
1128
1064
1129 In order to run a file as a demo, you must first make a Demo object out
1065 In order to run a file as a demo, you must first make a Demo object out
1130 of it. If the file is named myscript.py, the following code will make a
1066 of it. If the file is named myscript.py, the following code will make a
1131 demo::
1067 demo::
1132
1068
1133 from IPython.lib.demo import Demo
1069 from IPython.lib.demo import Demo
1134
1070
1135 mydemo = Demo('myscript.py')
1071 mydemo = Demo('myscript.py')
1136
1072
1137 This creates the mydemo object, whose blocks you run one at a time by
1073 This creates the mydemo object, whose blocks you run one at a time by
1138 simply calling the object with no arguments. If you have autocall active
1074 simply calling the object with no arguments. Then call it to run each step
1139 in IPython (the default), all you need to do is type::
1075 of the demo::
1140
1076
1141 mydemo
1077 mydemo()
1142
1078
1143 and IPython will call it, executing each block. Demo objects can be
1079 Demo objects can be
1144 restarted, you can move forward or back skipping blocks, re-execute the
1080 restarted, you can move forward or back skipping blocks, re-execute the
1145 last block, etc. Simply use the Tab key on a demo object to see its
1081 last block, etc. See the :mod:`IPython.lib.demo` module and the
1146 methods, and call '?' on them to see their docstrings for more usage
1082 :class:`~IPython.lib.demo.Demo` class for details.
1147 details. In addition, the demo module itself contains a comprehensive
1148 docstring, which you can access via::
1149
1150 from IPython.lib import demo
1151
1152 demo?
1153
1083
1154 Limitations: It is important to note that these demos are limited to
1084 Limitations: These demos are limited to
1155 fairly simple uses. In particular, you cannot break up sections within
1085 fairly simple uses. In particular, you cannot break up sections within
1156 indented code (loops, if statements, function definitions, etc.)
1086 indented code (loops, if statements, function definitions, etc.)
1157 Supporting something like this would basically require tracking the
1087 Supporting something like this would basically require tracking the
1158 internal execution state of the Python interpreter, so only top-level
1088 internal execution state of the Python interpreter, so only top-level
1159 divisions are allowed. If you want to be able to open an IPython
1089 divisions are allowed. If you want to be able to open an IPython
1160 instance at an arbitrary point in a program, you can use IPython's
1090 instance at an arbitrary point in a program, you can use IPython's
1161 embedding facilities, see :func:`IPython.embed` for details.
1091 :ref:`embedding facilities <Embedding>`.
1162
1092
1163 .. include:: ../links.txt
1093 .. include:: ../links.txt
@@ -1,138 +1,137 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
3 """An example of how to embed an IPython shell into a running program.
2 """An example of how to embed an IPython shell into a running program.
4
3
5 Please see the documentation in the IPython.Shell module for more details.
4 Please see the documentation in the IPython.Shell module for more details.
6
5
7 The accompanying file example-embed-short.py has quick code fragments for
6 The accompanying file example-embed-short.py has quick code fragments for
8 embedding which you can cut and paste in your code once you understand how
7 embedding which you can cut and paste in your code once you understand how
9 things work.
8 things work.
10
9
11 The code in this file is deliberately extra-verbose, meant for learning."""
10 The code in this file is deliberately extra-verbose, meant for learning."""
12 from __future__ import print_function
11 from __future__ import print_function
13
12
14 # The basics to get you going:
13 # The basics to get you going:
15
14
16 # IPython sets the __IPYTHON__ variable so you can know if you have nested
15 # IPython injects get_ipython into builtins, so you can know if you have nested
17 # copies running.
16 # copies running.
18
17
19 # Try running this code both at the command line and from inside IPython (with
18 # Try running this code both at the command line and from inside IPython (with
20 # %run example-embed.py)
19 # %run example-embed.py)
21 from IPython.config.loader import Config
20 from IPython.config.loader import Config
22 try:
21 try:
23 get_ipython
22 get_ipython
24 except NameError:
23 except NameError:
25 nested = 0
24 nested = 0
26 cfg = Config()
25 cfg = Config()
27 prompt_config = cfg.PromptManager
26 prompt_config = cfg.PromptManager
28 prompt_config.in_template = 'In <\\#>: '
27 prompt_config.in_template = 'In <\\#>: '
29 prompt_config.in2_template = ' .\\D.: '
28 prompt_config.in2_template = ' .\\D.: '
30 prompt_config.out_template = 'Out<\\#>: '
29 prompt_config.out_template = 'Out<\\#>: '
31 else:
30 else:
32 print("Running nested copies of IPython.")
31 print("Running nested copies of IPython.")
33 print("The prompts for the nested copy have been modified")
32 print("The prompts for the nested copy have been modified")
34 cfg = Config()
33 cfg = Config()
35 nested = 1
34 nested = 1
36
35
37 # First import the embeddable shell class
36 # First import the embeddable shell class
38 from IPython.terminal.embed import InteractiveShellEmbed
37 from IPython.terminal.embed import InteractiveShellEmbed
39
38
40 # Now create an instance of the embeddable shell. The first argument is a
39 # Now create an instance of the embeddable shell. The first argument is a
41 # string with options exactly as you would type them if you were starting
40 # string with options exactly as you would type them if you were starting
42 # IPython at the system command line. Any parameters you want to define for
41 # IPython at the system command line. Any parameters you want to define for
43 # configuration can thus be specified here.
42 # configuration can thus be specified here.
44 ipshell = InteractiveShellEmbed(config=cfg,
43 ipshell = InteractiveShellEmbed(config=cfg,
45 banner1 = 'Dropping into IPython',
44 banner1 = 'Dropping into IPython',
46 exit_msg = 'Leaving Interpreter, back to program.')
45 exit_msg = 'Leaving Interpreter, back to program.')
47
46
48 # Make a second instance, you can have as many as you want.
47 # Make a second instance, you can have as many as you want.
49 cfg2 = cfg.copy()
48 cfg2 = cfg.copy()
50 prompt_config = cfg2.PromptManager
49 prompt_config = cfg2.PromptManager
51 prompt_config.in_template = 'In2<\\#>: '
50 prompt_config.in_template = 'In2<\\#>: '
52 if not nested:
51 if not nested:
53 prompt_config.in_template = 'In2<\\#>: '
52 prompt_config.in_template = 'In2<\\#>: '
54 prompt_config.in2_template = ' .\\D.: '
53 prompt_config.in2_template = ' .\\D.: '
55 prompt_config.out_template = 'Out<\\#>: '
54 prompt_config.out_template = 'Out<\\#>: '
56 ipshell2 = InteractiveShellEmbed(config=cfg,
55 ipshell2 = InteractiveShellEmbed(config=cfg,
57 banner1 = 'Second IPython instance.')
56 banner1 = 'Second IPython instance.')
58
57
59 print('\nHello. This is printed from the main controller program.\n')
58 print('\nHello. This is printed from the main controller program.\n')
60
59
61 # You can then call ipshell() anywhere you need it (with an optional
60 # You can then call ipshell() anywhere you need it (with an optional
62 # message):
61 # message):
63 ipshell('***Called from top level. '
62 ipshell('***Called from top level. '
64 'Hit Ctrl-D to exit interpreter and continue program.\n'
63 'Hit Ctrl-D to exit interpreter and continue program.\n'
65 'Note that if you use %kill_embedded, you can fully deactivate\n'
64 'Note that if you use %kill_embedded, you can fully deactivate\n'
66 'This embedded instance so it will never turn on again')
65 'This embedded instance so it will never turn on again')
67
66
68 print('\nBack in caller program, moving along...\n')
67 print('\nBack in caller program, moving along...\n')
69
68
70 #---------------------------------------------------------------------------
69 #---------------------------------------------------------------------------
71 # More details:
70 # More details:
72
71
73 # InteractiveShellEmbed instances don't print the standard system banner and
72 # InteractiveShellEmbed instances don't print the standard system banner and
74 # messages. The IPython banner (which actually may contain initialization
73 # messages. The IPython banner (which actually may contain initialization
75 # messages) is available as get_ipython().banner in case you want it.
74 # messages) is available as get_ipython().banner in case you want it.
76
75
77 # InteractiveShellEmbed instances print the following information everytime they
76 # InteractiveShellEmbed instances print the following information everytime they
78 # start:
77 # start:
79
78
80 # - A global startup banner.
79 # - A global startup banner.
81
80
82 # - A call-specific header string, which you can use to indicate where in the
81 # - A call-specific header string, which you can use to indicate where in the
83 # execution flow the shell is starting.
82 # execution flow the shell is starting.
84
83
85 # They also print an exit message every time they exit.
84 # They also print an exit message every time they exit.
86
85
87 # Both the startup banner and the exit message default to None, and can be set
86 # Both the startup banner and the exit message default to None, and can be set
88 # either at the instance constructor or at any other time with the
87 # either at the instance constructor or at any other time with the
89 # by setting the banner and exit_msg attributes.
88 # by setting the banner and exit_msg attributes.
90
89
91 # The shell instance can be also put in 'dummy' mode globally or on a per-call
90 # The shell instance can be also put in 'dummy' mode globally or on a per-call
92 # basis. This gives you fine control for debugging without having to change
91 # basis. This gives you fine control for debugging without having to change
93 # code all over the place.
92 # code all over the place.
94
93
95 # The code below illustrates all this.
94 # The code below illustrates all this.
96
95
97
96
98 # This is how the global banner and exit_msg can be reset at any point
97 # This is how the global banner and exit_msg can be reset at any point
99 ipshell.banner = 'Entering interpreter - New Banner'
98 ipshell.banner = 'Entering interpreter - New Banner'
100 ipshell.exit_msg = 'Leaving interpreter - New exit_msg'
99 ipshell.exit_msg = 'Leaving interpreter - New exit_msg'
101
100
102 def foo(m):
101 def foo(m):
103 s = 'spam'
102 s = 'spam'
104 ipshell('***In foo(). Try %whos, or print s or m:')
103 ipshell('***In foo(). Try %whos, or print s or m:')
105 print('foo says m = ',m)
104 print('foo says m = ',m)
106
105
107 def bar(n):
106 def bar(n):
108 s = 'eggs'
107 s = 'eggs'
109 ipshell('***In bar(). Try %whos, or print s or n:')
108 ipshell('***In bar(). Try %whos, or print s or n:')
110 print('bar says n = ',n)
109 print('bar says n = ',n)
111
110
112 # Some calls to the above functions which will trigger IPython:
111 # Some calls to the above functions which will trigger IPython:
113 print('Main program calling foo("eggs")\n')
112 print('Main program calling foo("eggs")\n')
114 foo('eggs')
113 foo('eggs')
115
114
116 # The shell can be put in 'dummy' mode where calls to it silently return. This
115 # The shell can be put in 'dummy' mode where calls to it silently return. This
117 # allows you, for example, to globally turn off debugging for a program with a
116 # allows you, for example, to globally turn off debugging for a program with a
118 # single call.
117 # single call.
119 ipshell.dummy_mode = True
118 ipshell.dummy_mode = True
120 print('\nTrying to call IPython which is now "dummy":')
119 print('\nTrying to call IPython which is now "dummy":')
121 ipshell()
120 ipshell()
122 print('Nothing happened...')
121 print('Nothing happened...')
123 # The global 'dummy' mode can still be overridden for a single call
122 # The global 'dummy' mode can still be overridden for a single call
124 print('\nOverriding dummy mode manually:')
123 print('\nOverriding dummy mode manually:')
125 ipshell(dummy=False)
124 ipshell(dummy=False)
126
125
127 # Reactivate the IPython shell
126 # Reactivate the IPython shell
128 ipshell.dummy_mode = False
127 ipshell.dummy_mode = False
129
128
130 print('You can even have multiple embedded instances:')
129 print('You can even have multiple embedded instances:')
131 ipshell2()
130 ipshell2()
132
131
133 print('\nMain program calling bar("spam")\n')
132 print('\nMain program calling bar("spam")\n')
134 bar('spam')
133 bar('spam')
135
134
136 print('Main program finished. Bye!')
135 print('Main program finished. Bye!')
137
136
138 #********************** End of file <example-embed.py> ***********************
137 #********************** End of file <example-embed.py> ***********************
@@ -1,44 +1,43 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """A simple interactive demo to illustrate the use of IPython's Demo class.
2 """A simple interactive demo to illustrate the use of IPython's Demo class.
3
3
4 Any python script can be run as a demo, but that does little more than showing
4 Any python script can be run as a demo, but that does little more than showing
5 it on-screen, syntax-highlighted in one shot. If you add a little simple
5 it on-screen, syntax-highlighted in one shot. If you add a little simple
6 markup, you can stop at specified intervals and return to the ipython prompt,
6 markup, you can stop at specified intervals and return to the ipython prompt,
7 resuming execution later.
7 resuming execution later.
8
8
9 This is a unicode test, Γ₯Àâ
9 This is a unicode test, Γ₯Àâ
10 """
10 """
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 print('Hello, welcome to an interactive IPython demo.')
13 print('Hello, welcome to an interactive IPython demo.')
14 print('Executing this block should require confirmation before proceeding,')
14 print('Executing this block should require confirmation before proceeding,')
15 print('unless auto_all has been set to true in the demo object')
15 print('unless auto_all has been set to true in the demo object')
16
16
17 # The mark below defines a block boundary, which is a point where IPython will
17 # The mark below defines a block boundary, which is a point where IPython will
18 # stop execution and return to the interactive prompt.
18 # stop execution and return to the interactive prompt.
19 # Note that in actual interactive execution,
20 # <demo> --- stop ---
19 # <demo> --- stop ---
21
20
22 x = 1
21 x = 1
23 y = 2
22 y = 2
24
23
25 # <demo> --- stop ---
24 # <demo> --- stop ---
26
25
27 # the mark below makes this block as silent
26 # the mark below makes this block as silent
28 # <demo> silent
27 # <demo> silent
29
28
30 print('This is a silent block, which gets executed but not printed.')
29 print('This is a silent block, which gets executed but not printed.')
31
30
32 # <demo> --- stop ---
31 # <demo> --- stop ---
33 # <demo> auto
32 # <demo> auto
34 print('This is an automatic block.')
33 print('This is an automatic block.')
35 print('It is executed without asking for confirmation, but printed.')
34 print('It is executed without asking for confirmation, but printed.')
36 z = x+y
35 z = x+y
37
36
38 print('z=',x)
37 print('z=',x)
39
38
40 # <demo> --- stop ---
39 # <demo> --- stop ---
41 # This is just another normal block.
40 # This is just another normal block.
42 print('z is now:', z)
41 print('z is now:', z)
43
42
44 print('bye!')
43 print('bye!')
General Comments 0
You need to be logged in to leave comments. Login now