##// END OF EJS Templates
Merge pull request #3089 from minrk/stdin...
Brian E. Granger -
r10380:c3a90443 merge
parent child Browse files
Show More
@@ -1,927 +1,924 b''
1 """Tornado handlers for the notebook.
1 """Tornado handlers for the notebook.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import Cookie
19 import Cookie
20 import datetime
20 import datetime
21 import email.utils
21 import email.utils
22 import hashlib
22 import hashlib
23 import logging
23 import logging
24 import mimetypes
24 import mimetypes
25 import os
25 import os
26 import stat
26 import stat
27 import threading
27 import threading
28 import time
28 import time
29 import uuid
29 import uuid
30
30
31 from tornado.escape import url_escape
31 from tornado.escape import url_escape
32 from tornado import web
32 from tornado import web
33 from tornado import websocket
33 from tornado import websocket
34
34
35 try:
35 try:
36 from tornado.log import app_log
36 from tornado.log import app_log
37 except ImportError:
37 except ImportError:
38 app_log = logging.getLogger()
38 app_log = logging.getLogger()
39
39
40 from zmq.eventloop import ioloop
40 from zmq.eventloop import ioloop
41 from zmq.utils import jsonapi
41 from zmq.utils import jsonapi
42
42
43 from IPython.config import Application
43 from IPython.config import Application
44 from IPython.external.decorator import decorator
44 from IPython.external.decorator import decorator
45 from IPython.kernel.zmq.session import Session
45 from IPython.kernel.zmq.session import Session
46 from IPython.lib.security import passwd_check
46 from IPython.lib.security import passwd_check
47 from IPython.utils.jsonutil import date_default
47 from IPython.utils.jsonutil import date_default
48 from IPython.utils.path import filefind
48 from IPython.utils.path import filefind
49 from IPython.utils.py3compat import PY3
49 from IPython.utils.py3compat import PY3
50
50
51 try:
51 try:
52 from docutils.core import publish_string
52 from docutils.core import publish_string
53 except ImportError:
53 except ImportError:
54 publish_string = None
54 publish_string = None
55
55
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57 # Monkeypatch for Tornado <= 2.1.1 - Remove when no longer necessary!
57 # Monkeypatch for Tornado <= 2.1.1 - Remove when no longer necessary!
58 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
59
59
60 # Google Chrome, as of release 16, changed its websocket protocol number. The
60 # Google Chrome, as of release 16, changed its websocket protocol number. The
61 # parts tornado cares about haven't really changed, so it's OK to continue
61 # parts tornado cares about haven't really changed, so it's OK to continue
62 # accepting Chrome connections, but as of Tornado 2.1.1 (the currently released
62 # accepting Chrome connections, but as of Tornado 2.1.1 (the currently released
63 # version as of Oct 30/2011) the version check fails, see the issue report:
63 # version as of Oct 30/2011) the version check fails, see the issue report:
64
64
65 # https://github.com/facebook/tornado/issues/385
65 # https://github.com/facebook/tornado/issues/385
66
66
67 # This issue has been fixed in Tornado post 2.1.1:
67 # This issue has been fixed in Tornado post 2.1.1:
68
68
69 # https://github.com/facebook/tornado/commit/84d7b458f956727c3b0d6710
69 # https://github.com/facebook/tornado/commit/84d7b458f956727c3b0d6710
70
70
71 # Here we manually apply the same patch as above so that users of IPython can
71 # Here we manually apply the same patch as above so that users of IPython can
72 # continue to work with an officially released Tornado. We make the
72 # continue to work with an officially released Tornado. We make the
73 # monkeypatch version check as narrow as possible to limit its effects; once
73 # monkeypatch version check as narrow as possible to limit its effects; once
74 # Tornado 2.1.1 is no longer found in the wild we'll delete this code.
74 # Tornado 2.1.1 is no longer found in the wild we'll delete this code.
75
75
76 import tornado
76 import tornado
77
77
78 if tornado.version_info <= (2,1,1):
78 if tornado.version_info <= (2,1,1):
79
79
80 def _execute(self, transforms, *args, **kwargs):
80 def _execute(self, transforms, *args, **kwargs):
81 from tornado.websocket import WebSocketProtocol8, WebSocketProtocol76
81 from tornado.websocket import WebSocketProtocol8, WebSocketProtocol76
82
82
83 self.open_args = args
83 self.open_args = args
84 self.open_kwargs = kwargs
84 self.open_kwargs = kwargs
85
85
86 # The difference between version 8 and 13 is that in 8 the
86 # The difference between version 8 and 13 is that in 8 the
87 # client sends a "Sec-Websocket-Origin" header and in 13 it's
87 # client sends a "Sec-Websocket-Origin" header and in 13 it's
88 # simply "Origin".
88 # simply "Origin".
89 if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8", "13"):
89 if self.request.headers.get("Sec-WebSocket-Version") in ("7", "8", "13"):
90 self.ws_connection = WebSocketProtocol8(self)
90 self.ws_connection = WebSocketProtocol8(self)
91 self.ws_connection.accept_connection()
91 self.ws_connection.accept_connection()
92
92
93 elif self.request.headers.get("Sec-WebSocket-Version"):
93 elif self.request.headers.get("Sec-WebSocket-Version"):
94 self.stream.write(tornado.escape.utf8(
94 self.stream.write(tornado.escape.utf8(
95 "HTTP/1.1 426 Upgrade Required\r\n"
95 "HTTP/1.1 426 Upgrade Required\r\n"
96 "Sec-WebSocket-Version: 8\r\n\r\n"))
96 "Sec-WebSocket-Version: 8\r\n\r\n"))
97 self.stream.close()
97 self.stream.close()
98
98
99 else:
99 else:
100 self.ws_connection = WebSocketProtocol76(self)
100 self.ws_connection = WebSocketProtocol76(self)
101 self.ws_connection.accept_connection()
101 self.ws_connection.accept_connection()
102
102
103 websocket.WebSocketHandler._execute = _execute
103 websocket.WebSocketHandler._execute = _execute
104 del _execute
104 del _execute
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # Decorator for disabling read-only handlers
107 # Decorator for disabling read-only handlers
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 @decorator
110 @decorator
111 def not_if_readonly(f, self, *args, **kwargs):
111 def not_if_readonly(f, self, *args, **kwargs):
112 if self.settings.get('read_only', False):
112 if self.settings.get('read_only', False):
113 raise web.HTTPError(403, "Notebook server is read-only")
113 raise web.HTTPError(403, "Notebook server is read-only")
114 else:
114 else:
115 return f(self, *args, **kwargs)
115 return f(self, *args, **kwargs)
116
116
117 @decorator
117 @decorator
118 def authenticate_unless_readonly(f, self, *args, **kwargs):
118 def authenticate_unless_readonly(f, self, *args, **kwargs):
119 """authenticate this page *unless* readonly view is active.
119 """authenticate this page *unless* readonly view is active.
120
120
121 In read-only mode, the notebook list and print view should
121 In read-only mode, the notebook list and print view should
122 be accessible without authentication.
122 be accessible without authentication.
123 """
123 """
124
124
125 @web.authenticated
125 @web.authenticated
126 def auth_f(self, *args, **kwargs):
126 def auth_f(self, *args, **kwargs):
127 return f(self, *args, **kwargs)
127 return f(self, *args, **kwargs)
128
128
129 if self.settings.get('read_only', False):
129 if self.settings.get('read_only', False):
130 return f(self, *args, **kwargs)
130 return f(self, *args, **kwargs)
131 else:
131 else:
132 return auth_f(self, *args, **kwargs)
132 return auth_f(self, *args, **kwargs)
133
133
134 def urljoin(*pieces):
134 def urljoin(*pieces):
135 """Join components of url into a relative url
135 """Join components of url into a relative url
136
136
137 Use to prevent double slash when joining subpath
137 Use to prevent double slash when joining subpath
138 """
138 """
139 striped = [s.strip('/') for s in pieces]
139 striped = [s.strip('/') for s in pieces]
140 return '/'.join(s for s in striped if s)
140 return '/'.join(s for s in striped if s)
141
141
142 #-----------------------------------------------------------------------------
142 #-----------------------------------------------------------------------------
143 # Top-level handlers
143 # Top-level handlers
144 #-----------------------------------------------------------------------------
144 #-----------------------------------------------------------------------------
145
145
146 class RequestHandler(web.RequestHandler):
146 class RequestHandler(web.RequestHandler):
147 """RequestHandler with default variable setting."""
147 """RequestHandler with default variable setting."""
148
148
149 def render(*args, **kwargs):
149 def render(*args, **kwargs):
150 kwargs.setdefault('message', '')
150 kwargs.setdefault('message', '')
151 return web.RequestHandler.render(*args, **kwargs)
151 return web.RequestHandler.render(*args, **kwargs)
152
152
153 class AuthenticatedHandler(RequestHandler):
153 class AuthenticatedHandler(RequestHandler):
154 """A RequestHandler with an authenticated user."""
154 """A RequestHandler with an authenticated user."""
155
155
156 def clear_login_cookie(self):
156 def clear_login_cookie(self):
157 self.clear_cookie(self.cookie_name)
157 self.clear_cookie(self.cookie_name)
158
158
159 def get_current_user(self):
159 def get_current_user(self):
160 user_id = self.get_secure_cookie(self.cookie_name)
160 user_id = self.get_secure_cookie(self.cookie_name)
161 # For now the user_id should not return empty, but it could eventually
161 # For now the user_id should not return empty, but it could eventually
162 if user_id == '':
162 if user_id == '':
163 user_id = 'anonymous'
163 user_id = 'anonymous'
164 if user_id is None:
164 if user_id is None:
165 # prevent extra Invalid cookie sig warnings:
165 # prevent extra Invalid cookie sig warnings:
166 self.clear_login_cookie()
166 self.clear_login_cookie()
167 if not self.read_only and not self.login_available:
167 if not self.read_only and not self.login_available:
168 user_id = 'anonymous'
168 user_id = 'anonymous'
169 return user_id
169 return user_id
170
170
171 @property
171 @property
172 def cookie_name(self):
172 def cookie_name(self):
173 return self.settings.get('cookie_name', '')
173 return self.settings.get('cookie_name', '')
174
174
175 @property
175 @property
176 def password(self):
176 def password(self):
177 """our password"""
177 """our password"""
178 return self.settings.get('password', '')
178 return self.settings.get('password', '')
179
179
180 @property
180 @property
181 def logged_in(self):
181 def logged_in(self):
182 """Is a user currently logged in?
182 """Is a user currently logged in?
183
183
184 """
184 """
185 user = self.get_current_user()
185 user = self.get_current_user()
186 return (user and not user == 'anonymous')
186 return (user and not user == 'anonymous')
187
187
188 @property
188 @property
189 def login_available(self):
189 def login_available(self):
190 """May a user proceed to log in?
190 """May a user proceed to log in?
191
191
192 This returns True if login capability is available, irrespective of
192 This returns True if login capability is available, irrespective of
193 whether the user is already logged in or not.
193 whether the user is already logged in or not.
194
194
195 """
195 """
196 return bool(self.settings.get('password', ''))
196 return bool(self.settings.get('password', ''))
197
197
198 @property
198 @property
199 def read_only(self):
199 def read_only(self):
200 """Is the notebook read-only?
200 """Is the notebook read-only?
201
201
202 """
202 """
203 return self.settings.get('read_only', False)
203 return self.settings.get('read_only', False)
204
204
205
205
206 class IPythonHandler(AuthenticatedHandler):
206 class IPythonHandler(AuthenticatedHandler):
207 """IPython-specific extensions to authenticated handling
207 """IPython-specific extensions to authenticated handling
208
208
209 Mostly property shortcuts to IPython-specific settings.
209 Mostly property shortcuts to IPython-specific settings.
210 """
210 """
211
211
212 @property
212 @property
213 def config(self):
213 def config(self):
214 return self.settings.get('config', None)
214 return self.settings.get('config', None)
215
215
216 @property
216 @property
217 def log(self):
217 def log(self):
218 """use the IPython log by default, falling back on tornado's logger"""
218 """use the IPython log by default, falling back on tornado's logger"""
219 if Application.initialized():
219 if Application.initialized():
220 return Application.instance().log
220 return Application.instance().log
221 else:
221 else:
222 return app_log
222 return app_log
223
223
224 @property
224 @property
225 def use_less(self):
225 def use_less(self):
226 """Use less instead of css in templates"""
226 """Use less instead of css in templates"""
227 return self.settings.get('use_less', False)
227 return self.settings.get('use_less', False)
228
228
229 #---------------------------------------------------------------
229 #---------------------------------------------------------------
230 # URLs
230 # URLs
231 #---------------------------------------------------------------
231 #---------------------------------------------------------------
232
232
233 @property
233 @property
234 def ws_url(self):
234 def ws_url(self):
235 """websocket url matching the current request
235 """websocket url matching the current request
236
236
237 turns http[s]://host[:port] into
237 turns http[s]://host[:port] into
238 ws[s]://host[:port]
238 ws[s]://host[:port]
239 """
239 """
240 proto = self.request.protocol.replace('http', 'ws')
240 proto = self.request.protocol.replace('http', 'ws')
241 host = self.settings.get('websocket_host', '')
241 host = self.settings.get('websocket_host', '')
242 # default to config value
242 # default to config value
243 if host == '':
243 if host == '':
244 host = self.request.host # get from request
244 host = self.request.host # get from request
245 return "%s://%s" % (proto, host)
245 return "%s://%s" % (proto, host)
246
246
247 @property
247 @property
248 def mathjax_url(self):
248 def mathjax_url(self):
249 return self.settings.get('mathjax_url', '')
249 return self.settings.get('mathjax_url', '')
250
250
251 @property
251 @property
252 def base_project_url(self):
252 def base_project_url(self):
253 return self.settings.get('base_project_url', '/')
253 return self.settings.get('base_project_url', '/')
254
254
255 @property
255 @property
256 def base_kernel_url(self):
256 def base_kernel_url(self):
257 return self.settings.get('base_kernel_url', '/')
257 return self.settings.get('base_kernel_url', '/')
258
258
259 #---------------------------------------------------------------
259 #---------------------------------------------------------------
260 # Manager objects
260 # Manager objects
261 #---------------------------------------------------------------
261 #---------------------------------------------------------------
262
262
263 @property
263 @property
264 def kernel_manager(self):
264 def kernel_manager(self):
265 return self.settings['kernel_manager']
265 return self.settings['kernel_manager']
266
266
267 @property
267 @property
268 def notebook_manager(self):
268 def notebook_manager(self):
269 return self.settings['notebook_manager']
269 return self.settings['notebook_manager']
270
270
271 @property
271 @property
272 def cluster_manager(self):
272 def cluster_manager(self):
273 return self.settings['cluster_manager']
273 return self.settings['cluster_manager']
274
274
275 @property
275 @property
276 def project(self):
276 def project(self):
277 return self.notebook_manager.notebook_dir
277 return self.notebook_manager.notebook_dir
278
278
279 #---------------------------------------------------------------
279 #---------------------------------------------------------------
280 # template rendering
280 # template rendering
281 #---------------------------------------------------------------
281 #---------------------------------------------------------------
282
282
283 def get_template(self, name):
283 def get_template(self, name):
284 """Return the jinja template object for a given name"""
284 """Return the jinja template object for a given name"""
285 return self.settings['jinja2_env'].get_template(name)
285 return self.settings['jinja2_env'].get_template(name)
286
286
287 def render_template(self, name, **ns):
287 def render_template(self, name, **ns):
288 ns.update(self.template_namespace)
288 ns.update(self.template_namespace)
289 template = self.get_template(name)
289 template = self.get_template(name)
290 return template.render(**ns)
290 return template.render(**ns)
291
291
292 @property
292 @property
293 def template_namespace(self):
293 def template_namespace(self):
294 return dict(
294 return dict(
295 base_project_url=self.base_project_url,
295 base_project_url=self.base_project_url,
296 base_kernel_url=self.base_kernel_url,
296 base_kernel_url=self.base_kernel_url,
297 read_only=self.read_only,
297 read_only=self.read_only,
298 logged_in=self.logged_in,
298 logged_in=self.logged_in,
299 login_available=self.login_available,
299 login_available=self.login_available,
300 use_less=self.use_less,
300 use_less=self.use_less,
301 )
301 )
302
302
303 class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):
303 class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):
304 """static files should only be accessible when logged in"""
304 """static files should only be accessible when logged in"""
305
305
306 @authenticate_unless_readonly
306 @authenticate_unless_readonly
307 def get(self, path):
307 def get(self, path):
308 return web.StaticFileHandler.get(self, path)
308 return web.StaticFileHandler.get(self, path)
309
309
310
310
311 class ProjectDashboardHandler(IPythonHandler):
311 class ProjectDashboardHandler(IPythonHandler):
312
312
313 @authenticate_unless_readonly
313 @authenticate_unless_readonly
314 def get(self):
314 def get(self):
315 self.write(self.render_template('projectdashboard.html',
315 self.write(self.render_template('projectdashboard.html',
316 project=self.project,
316 project=self.project,
317 project_component=self.project.split('/'),
317 project_component=self.project.split('/'),
318 ))
318 ))
319
319
320
320
321 class LoginHandler(IPythonHandler):
321 class LoginHandler(IPythonHandler):
322
322
323 def _render(self, message=None):
323 def _render(self, message=None):
324 self.write(self.render_template('login.html',
324 self.write(self.render_template('login.html',
325 next=url_escape(self.get_argument('next', default=self.base_project_url)),
325 next=url_escape(self.get_argument('next', default=self.base_project_url)),
326 message=message,
326 message=message,
327 ))
327 ))
328
328
329 def get(self):
329 def get(self):
330 if self.current_user:
330 if self.current_user:
331 self.redirect(self.get_argument('next', default=self.base_project_url))
331 self.redirect(self.get_argument('next', default=self.base_project_url))
332 else:
332 else:
333 self._render()
333 self._render()
334
334
335 def post(self):
335 def post(self):
336 pwd = self.get_argument('password', default=u'')
336 pwd = self.get_argument('password', default=u'')
337 if self.login_available:
337 if self.login_available:
338 if passwd_check(self.password, pwd):
338 if passwd_check(self.password, pwd):
339 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()))
339 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()))
340 else:
340 else:
341 self._render(message={'error': 'Invalid password'})
341 self._render(message={'error': 'Invalid password'})
342 return
342 return
343
343
344 self.redirect(self.get_argument('next', default=self.base_project_url))
344 self.redirect(self.get_argument('next', default=self.base_project_url))
345
345
346
346
347 class LogoutHandler(IPythonHandler):
347 class LogoutHandler(IPythonHandler):
348
348
349 def get(self):
349 def get(self):
350 self.clear_login_cookie()
350 self.clear_login_cookie()
351 if self.login_available:
351 if self.login_available:
352 message = {'info': 'Successfully logged out.'}
352 message = {'info': 'Successfully logged out.'}
353 else:
353 else:
354 message = {'warning': 'Cannot log out. Notebook authentication '
354 message = {'warning': 'Cannot log out. Notebook authentication '
355 'is disabled.'}
355 'is disabled.'}
356 self.write(self.render_template('logout.html',
356 self.write(self.render_template('logout.html',
357 message=message))
357 message=message))
358
358
359
359
360 class NewHandler(IPythonHandler):
360 class NewHandler(IPythonHandler):
361
361
362 @web.authenticated
362 @web.authenticated
363 def get(self):
363 def get(self):
364 notebook_id = self.notebook_manager.new_notebook()
364 notebook_id = self.notebook_manager.new_notebook()
365 self.redirect('/' + urljoin(self.base_project_url, notebook_id))
365 self.redirect('/' + urljoin(self.base_project_url, notebook_id))
366
366
367 class NamedNotebookHandler(IPythonHandler):
367 class NamedNotebookHandler(IPythonHandler):
368
368
369 @authenticate_unless_readonly
369 @authenticate_unless_readonly
370 def get(self, notebook_id):
370 def get(self, notebook_id):
371 nbm = self.notebook_manager
371 nbm = self.notebook_manager
372 if not nbm.notebook_exists(notebook_id):
372 if not nbm.notebook_exists(notebook_id):
373 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
373 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
374 self.write(self.render_template('notebook.html',
374 self.write(self.render_template('notebook.html',
375 project=self.project,
375 project=self.project,
376 notebook_id=notebook_id,
376 notebook_id=notebook_id,
377 kill_kernel=False,
377 kill_kernel=False,
378 mathjax_url=self.mathjax_url,
378 mathjax_url=self.mathjax_url,
379 )
379 )
380 )
380 )
381
381
382
382
383 class PrintNotebookHandler(IPythonHandler):
383 class PrintNotebookHandler(IPythonHandler):
384
384
385 @authenticate_unless_readonly
385 @authenticate_unless_readonly
386 def get(self, notebook_id):
386 def get(self, notebook_id):
387 if not self.notebook_manager.notebook_exists(notebook_id):
387 if not self.notebook_manager.notebook_exists(notebook_id):
388 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
388 raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id)
389 self.write( self.render_template('printnotebook.html',
389 self.write( self.render_template('printnotebook.html',
390 project=self.project,
390 project=self.project,
391 notebook_id=notebook_id,
391 notebook_id=notebook_id,
392 kill_kernel=False,
392 kill_kernel=False,
393 mathjax_url=self.mathjax_url,
393 mathjax_url=self.mathjax_url,
394 ))
394 ))
395
395
396 #-----------------------------------------------------------------------------
396 #-----------------------------------------------------------------------------
397 # Kernel handlers
397 # Kernel handlers
398 #-----------------------------------------------------------------------------
398 #-----------------------------------------------------------------------------
399
399
400
400
401 class MainKernelHandler(IPythonHandler):
401 class MainKernelHandler(IPythonHandler):
402
402
403 @web.authenticated
403 @web.authenticated
404 def get(self):
404 def get(self):
405 km = self.kernel_manager
405 km = self.kernel_manager
406 self.finish(jsonapi.dumps(km.list_kernel_ids()))
406 self.finish(jsonapi.dumps(km.list_kernel_ids()))
407
407
408 @web.authenticated
408 @web.authenticated
409 def post(self):
409 def post(self):
410 km = self.kernel_manager
410 km = self.kernel_manager
411 nbm = self.notebook_manager
411 nbm = self.notebook_manager
412 notebook_id = self.get_argument('notebook', default=None)
412 notebook_id = self.get_argument('notebook', default=None)
413 kernel_id = km.start_kernel(notebook_id, cwd=nbm.notebook_dir)
413 kernel_id = km.start_kernel(notebook_id, cwd=nbm.notebook_dir)
414 data = {'ws_url':self.ws_url,'kernel_id':kernel_id}
414 data = {'ws_url':self.ws_url,'kernel_id':kernel_id}
415 self.set_header('Location', '/'+kernel_id)
415 self.set_header('Location', '/'+kernel_id)
416 self.finish(jsonapi.dumps(data))
416 self.finish(jsonapi.dumps(data))
417
417
418
418
419 class KernelHandler(IPythonHandler):
419 class KernelHandler(IPythonHandler):
420
420
421 SUPPORTED_METHODS = ('DELETE')
421 SUPPORTED_METHODS = ('DELETE')
422
422
423 @web.authenticated
423 @web.authenticated
424 def delete(self, kernel_id):
424 def delete(self, kernel_id):
425 km = self.kernel_manager
425 km = self.kernel_manager
426 km.shutdown_kernel(kernel_id)
426 km.shutdown_kernel(kernel_id)
427 self.set_status(204)
427 self.set_status(204)
428 self.finish()
428 self.finish()
429
429
430
430
431 class KernelActionHandler(IPythonHandler):
431 class KernelActionHandler(IPythonHandler):
432
432
433 @web.authenticated
433 @web.authenticated
434 def post(self, kernel_id, action):
434 def post(self, kernel_id, action):
435 km = self.kernel_manager
435 km = self.kernel_manager
436 if action == 'interrupt':
436 if action == 'interrupt':
437 km.interrupt_kernel(kernel_id)
437 km.interrupt_kernel(kernel_id)
438 self.set_status(204)
438 self.set_status(204)
439 if action == 'restart':
439 if action == 'restart':
440 km.restart_kernel(kernel_id)
440 km.restart_kernel(kernel_id)
441 data = {'ws_url':self.ws_url, 'kernel_id':kernel_id}
441 data = {'ws_url':self.ws_url, 'kernel_id':kernel_id}
442 self.set_header('Location', '/'+kernel_id)
442 self.set_header('Location', '/'+kernel_id)
443 self.write(jsonapi.dumps(data))
443 self.write(jsonapi.dumps(data))
444 self.finish()
444 self.finish()
445
445
446
446
447 class ZMQStreamHandler(websocket.WebSocketHandler):
447 class ZMQStreamHandler(websocket.WebSocketHandler):
448
448
449 def clear_cookie(self, *args, **kwargs):
449 def clear_cookie(self, *args, **kwargs):
450 """meaningless for websockets"""
450 """meaningless for websockets"""
451 pass
451 pass
452
452
453 def _reserialize_reply(self, msg_list):
453 def _reserialize_reply(self, msg_list):
454 """Reserialize a reply message using JSON.
454 """Reserialize a reply message using JSON.
455
455
456 This takes the msg list from the ZMQ socket, unserializes it using
456 This takes the msg list from the ZMQ socket, unserializes it using
457 self.session and then serializes the result using JSON. This method
457 self.session and then serializes the result using JSON. This method
458 should be used by self._on_zmq_reply to build messages that can
458 should be used by self._on_zmq_reply to build messages that can
459 be sent back to the browser.
459 be sent back to the browser.
460 """
460 """
461 idents, msg_list = self.session.feed_identities(msg_list)
461 idents, msg_list = self.session.feed_identities(msg_list)
462 msg = self.session.unserialize(msg_list)
462 msg = self.session.unserialize(msg_list)
463 try:
463 try:
464 msg['header'].pop('date')
464 msg['header'].pop('date')
465 except KeyError:
465 except KeyError:
466 pass
466 pass
467 try:
467 try:
468 msg['parent_header'].pop('date')
468 msg['parent_header'].pop('date')
469 except KeyError:
469 except KeyError:
470 pass
470 pass
471 msg.pop('buffers')
471 msg.pop('buffers')
472 return jsonapi.dumps(msg, default=date_default)
472 return jsonapi.dumps(msg, default=date_default)
473
473
474 def _on_zmq_reply(self, msg_list):
474 def _on_zmq_reply(self, msg_list):
475 # Sometimes this gets triggered when the on_close method is scheduled in the
475 # Sometimes this gets triggered when the on_close method is scheduled in the
476 # eventloop but hasn't been called.
476 # eventloop but hasn't been called.
477 if self.stream.closed(): return
477 if self.stream.closed(): return
478 try:
478 try:
479 msg = self._reserialize_reply(msg_list)
479 msg = self._reserialize_reply(msg_list)
480 except Exception:
480 except Exception:
481 self.log.critical("Malformed message: %r" % msg_list, exc_info=True)
481 self.log.critical("Malformed message: %r" % msg_list, exc_info=True)
482 else:
482 else:
483 self.write_message(msg)
483 self.write_message(msg)
484
484
485 def allow_draft76(self):
485 def allow_draft76(self):
486 """Allow draft 76, until browsers such as Safari update to RFC 6455.
486 """Allow draft 76, until browsers such as Safari update to RFC 6455.
487
487
488 This has been disabled by default in tornado in release 2.2.0, and
488 This has been disabled by default in tornado in release 2.2.0, and
489 support will be removed in later versions.
489 support will be removed in later versions.
490 """
490 """
491 return True
491 return True
492
492
493
493
494 class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
494 class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler):
495
495
496 def open(self, kernel_id):
496 def open(self, kernel_id):
497 self.kernel_id = kernel_id.decode('ascii')
497 self.kernel_id = kernel_id.decode('ascii')
498 self.session = Session(config=self.config)
498 self.session = Session(config=self.config)
499 self.save_on_message = self.on_message
499 self.save_on_message = self.on_message
500 self.on_message = self.on_first_message
500 self.on_message = self.on_first_message
501
501
502 def _inject_cookie_message(self, msg):
502 def _inject_cookie_message(self, msg):
503 """Inject the first message, which is the document cookie,
503 """Inject the first message, which is the document cookie,
504 for authentication."""
504 for authentication."""
505 if not PY3 and isinstance(msg, unicode):
505 if not PY3 and isinstance(msg, unicode):
506 # Cookie constructor doesn't accept unicode strings
506 # Cookie constructor doesn't accept unicode strings
507 # under Python 2.x for some reason
507 # under Python 2.x for some reason
508 msg = msg.encode('utf8', 'replace')
508 msg = msg.encode('utf8', 'replace')
509 try:
509 try:
510 identity, msg = msg.split(':', 1)
511 self.session.session = identity.decode('ascii')
512 except Exception:
513 logging.error("First ws message didn't have the form 'identity:[cookie]' - %r", msg)
514
515 try:
510 self.request._cookies = Cookie.SimpleCookie(msg)
516 self.request._cookies = Cookie.SimpleCookie(msg)
511 except:
517 except:
512 self.log.warn("couldn't parse cookie string: %s",msg, exc_info=True)
518 self.log.warn("couldn't parse cookie string: %s",msg, exc_info=True)
513
519
514 def on_first_message(self, msg):
520 def on_first_message(self, msg):
515 self._inject_cookie_message(msg)
521 self._inject_cookie_message(msg)
516 if self.get_current_user() is None:
522 if self.get_current_user() is None:
517 self.log.warn("Couldn't authenticate WebSocket connection")
523 self.log.warn("Couldn't authenticate WebSocket connection")
518 raise web.HTTPError(403)
524 raise web.HTTPError(403)
519 self.on_message = self.save_on_message
525 self.on_message = self.save_on_message
520
526
521
527
522 class IOPubHandler(AuthenticatedZMQStreamHandler):
528 class ZMQChannelHandler(AuthenticatedZMQStreamHandler):
529
530 @property
531 def max_msg_size(self):
532 return self.settings.get('max_msg_size', 65535)
533
534 def create_stream(self):
535 km = self.kernel_manager
536 meth = getattr(km, 'connect_%s' % self.channel)
537 self.zmq_stream = meth(self.kernel_id, identity=self.session.bsession)
523
538
524 def initialize(self, *args, **kwargs):
539 def initialize(self, *args, **kwargs):
525 self.iopub_stream = None
540 self.zmq_stream = None
526
541
527 def on_first_message(self, msg):
542 def on_first_message(self, msg):
528 try:
543 try:
529 super(IOPubHandler, self).on_first_message(msg)
544 super(ZMQChannelHandler, self).on_first_message(msg)
530 except web.HTTPError:
545 except web.HTTPError:
531 self.close()
546 self.close()
532 return
547 return
533 km = self.kernel_manager
534 kernel_id = self.kernel_id
535 km.add_restart_callback(kernel_id, self.on_kernel_restarted)
536 km.add_restart_callback(kernel_id, self.on_restart_failed, 'dead')
537 try:
548 try:
538 self.iopub_stream = km.connect_iopub(kernel_id)
549 self.create_stream()
539 except web.HTTPError:
550 except web.HTTPError:
540 # WebSockets don't response to traditional error codes so we
551 # WebSockets don't response to traditional error codes so we
541 # close the connection.
552 # close the connection.
542 if not self.stream.closed():
553 if not self.stream.closed():
543 self.stream.close()
554 self.stream.close()
544 self.close()
555 self.close()
545 else:
556 else:
546 self.iopub_stream.on_recv(self._on_zmq_reply)
557 self.zmq_stream.on_recv(self._on_zmq_reply)
547
558
548 def on_message(self, msg):
559 def on_message(self, msg):
549 pass
560 if len(msg) < self.max_msg_size:
550
561 msg = jsonapi.loads(msg)
551 def _send_status_message(self, status):
562 self.session.send(self.zmq_stream, msg)
552 msg = self.session.msg("status",
553 {'execution_state': status}
554 )
555 self.write_message(jsonapi.dumps(msg, default=date_default))
556
557 def on_kernel_restarted(self):
558 self.log.warn("kernel %s restarted", self.kernel_id)
559 self._send_status_message('restarting')
560
561 def on_restart_failed(self):
562 self.log.error("kernel %s restarted failed!", self.kernel_id)
563 self._send_status_message('dead')
564
563
565 def on_close(self):
564 def on_close(self):
566 # This method can be called twice, once by self.kernel_died and once
565 # This method can be called twice, once by self.kernel_died and once
567 # from the WebSocket close event. If the WebSocket connection is
566 # from the WebSocket close event. If the WebSocket connection is
568 # closed before the ZMQ streams are setup, they could be None.
567 # closed before the ZMQ streams are setup, they could be None.
568 if self.zmq_stream is not None and not self.zmq_stream.closed():
569 self.zmq_stream.on_recv(None)
570 self.zmq_stream.close()
571
572
573 class IOPubHandler(ZMQChannelHandler):
574 channel = 'iopub'
575
576 def create_stream(self):
577 super(IOPubHandler, self).create_stream()
578 km = self.kernel_manager
579 km.add_restart_callback(self.kernel_id, self.on_kernel_restarted)
580 km.add_restart_callback(self.kernel_id, self.on_restart_failed, 'dead')
581
582 def on_close(self):
569 km = self.kernel_manager
583 km = self.kernel_manager
570 if self.kernel_id in km:
584 if self.kernel_id in km:
571 km.remove_restart_callback(
585 km.remove_restart_callback(
572 self.kernel_id, self.on_kernel_restarted,
586 self.kernel_id, self.on_kernel_restarted,
573 )
587 )
574 km.remove_restart_callback(
588 km.remove_restart_callback(
575 self.kernel_id, self.on_restart_failed, 'dead',
589 self.kernel_id, self.on_restart_failed, 'dead',
576 )
590 )
577 if self.iopub_stream is not None and not self.iopub_stream.closed():
591 super(IOPubHandler, self).on_close()
578 self.iopub_stream.on_recv(None)
579 self.iopub_stream.close()
580
581
582 class ShellHandler(AuthenticatedZMQStreamHandler):
583
592
584 @property
593 def _send_status_message(self, status):
585 def max_msg_size(self):
594 msg = self.session.msg("status",
586 return self.settings.get('max_msg_size', 65535)
595 {'execution_state': status}
596 )
597 self.write_message(jsonapi.dumps(msg, default=date_default))
587
598
588 def initialize(self, *args, **kwargs):
599 def on_kernel_restarted(self):
589 self.shell_stream = None
600 logging.warn("kernel %s restarted", self.kernel_id)
601 self._send_status_message('restarting')
590
602
591 def on_first_message(self, msg):
603 def on_restart_failed(self):
592 try:
604 logging.error("kernel %s restarted failed!", self.kernel_id)
593 super(ShellHandler, self).on_first_message(msg)
605 self._send_status_message('dead')
594 except web.HTTPError:
595 self.close()
596 return
597 km = self.kernel_manager
598 kernel_id = self.kernel_id
599 try:
600 self.shell_stream = km.connect_shell(kernel_id)
601 except web.HTTPError:
602 # WebSockets don't response to traditional error codes so we
603 # close the connection.
604 if not self.stream.closed():
605 self.stream.close()
606 self.close()
607 else:
608 self.shell_stream.on_recv(self._on_zmq_reply)
609
606
610 def on_message(self, msg):
607 def on_message(self, msg):
611 if len(msg) < self.max_msg_size:
608 """IOPub messages make no sense"""
612 msg = jsonapi.loads(msg)
609 pass
613 self.session.send(self.shell_stream, msg)
614
610
615 def on_close(self):
611 class ShellHandler(ZMQChannelHandler):
616 # Make sure the stream exists and is not already closed.
612 channel = 'shell'
617 if self.shell_stream is not None and not self.shell_stream.closed():
613
618 self.shell_stream.close()
614 class StdinHandler(ZMQChannelHandler):
615 channel = 'stdin'
619
616
620
617
621 #-----------------------------------------------------------------------------
618 #-----------------------------------------------------------------------------
622 # Notebook web service handlers
619 # Notebook web service handlers
623 #-----------------------------------------------------------------------------
620 #-----------------------------------------------------------------------------
624
621
625 class NotebookRedirectHandler(IPythonHandler):
622 class NotebookRedirectHandler(IPythonHandler):
626
623
627 @authenticate_unless_readonly
624 @authenticate_unless_readonly
628 def get(self, notebook_name):
625 def get(self, notebook_name):
629 # strip trailing .ipynb:
626 # strip trailing .ipynb:
630 notebook_name = os.path.splitext(notebook_name)[0]
627 notebook_name = os.path.splitext(notebook_name)[0]
631 notebook_id = self.notebook_manager.rev_mapping.get(notebook_name, '')
628 notebook_id = self.notebook_manager.rev_mapping.get(notebook_name, '')
632 if notebook_id:
629 if notebook_id:
633 url = self.settings.get('base_project_url', '/') + notebook_id
630 url = self.settings.get('base_project_url', '/') + notebook_id
634 return self.redirect(url)
631 return self.redirect(url)
635 else:
632 else:
636 raise HTTPError(404)
633 raise HTTPError(404)
637
634
638
635
639 class NotebookRootHandler(IPythonHandler):
636 class NotebookRootHandler(IPythonHandler):
640
637
641 @authenticate_unless_readonly
638 @authenticate_unless_readonly
642 def get(self):
639 def get(self):
643 nbm = self.notebook_manager
640 nbm = self.notebook_manager
644 km = self.kernel_manager
641 km = self.kernel_manager
645 files = nbm.list_notebooks()
642 files = nbm.list_notebooks()
646 for f in files :
643 for f in files :
647 f['kernel_id'] = km.kernel_for_notebook(f['notebook_id'])
644 f['kernel_id'] = km.kernel_for_notebook(f['notebook_id'])
648 self.finish(jsonapi.dumps(files))
645 self.finish(jsonapi.dumps(files))
649
646
650 @web.authenticated
647 @web.authenticated
651 def post(self):
648 def post(self):
652 nbm = self.notebook_manager
649 nbm = self.notebook_manager
653 body = self.request.body.strip()
650 body = self.request.body.strip()
654 format = self.get_argument('format', default='json')
651 format = self.get_argument('format', default='json')
655 name = self.get_argument('name', default=None)
652 name = self.get_argument('name', default=None)
656 if body:
653 if body:
657 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
654 notebook_id = nbm.save_new_notebook(body, name=name, format=format)
658 else:
655 else:
659 notebook_id = nbm.new_notebook()
656 notebook_id = nbm.new_notebook()
660 self.set_header('Location', '/'+notebook_id)
657 self.set_header('Location', '/'+notebook_id)
661 self.finish(jsonapi.dumps(notebook_id))
658 self.finish(jsonapi.dumps(notebook_id))
662
659
663
660
664 class NotebookHandler(IPythonHandler):
661 class NotebookHandler(IPythonHandler):
665
662
666 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
663 SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE')
667
664
668 @authenticate_unless_readonly
665 @authenticate_unless_readonly
669 def get(self, notebook_id):
666 def get(self, notebook_id):
670 nbm = self.notebook_manager
667 nbm = self.notebook_manager
671 format = self.get_argument('format', default='json')
668 format = self.get_argument('format', default='json')
672 last_mod, name, data = nbm.get_notebook(notebook_id, format)
669 last_mod, name, data = nbm.get_notebook(notebook_id, format)
673
670
674 if format == u'json':
671 if format == u'json':
675 self.set_header('Content-Type', 'application/json')
672 self.set_header('Content-Type', 'application/json')
676 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
673 self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name)
677 elif format == u'py':
674 elif format == u'py':
678 self.set_header('Content-Type', 'application/x-python')
675 self.set_header('Content-Type', 'application/x-python')
679 self.set_header('Content-Disposition','attachment; filename="%s.py"' % name)
676 self.set_header('Content-Disposition','attachment; filename="%s.py"' % name)
680 self.set_header('Last-Modified', last_mod)
677 self.set_header('Last-Modified', last_mod)
681 self.finish(data)
678 self.finish(data)
682
679
683 @web.authenticated
680 @web.authenticated
684 def put(self, notebook_id):
681 def put(self, notebook_id):
685 nbm = self.notebook_manager
682 nbm = self.notebook_manager
686 format = self.get_argument('format', default='json')
683 format = self.get_argument('format', default='json')
687 name = self.get_argument('name', default=None)
684 name = self.get_argument('name', default=None)
688 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
685 nbm.save_notebook(notebook_id, self.request.body, name=name, format=format)
689 self.set_status(204)
686 self.set_status(204)
690 self.finish()
687 self.finish()
691
688
692 @web.authenticated
689 @web.authenticated
693 def delete(self, notebook_id):
690 def delete(self, notebook_id):
694 self.notebook_manager.delete_notebook(notebook_id)
691 self.notebook_manager.delete_notebook(notebook_id)
695 self.set_status(204)
692 self.set_status(204)
696 self.finish()
693 self.finish()
697
694
698
695
699 class NotebookCopyHandler(IPythonHandler):
696 class NotebookCopyHandler(IPythonHandler):
700
697
701 @web.authenticated
698 @web.authenticated
702 def get(self, notebook_id):
699 def get(self, notebook_id):
703 notebook_id = self.notebook_manager.copy_notebook(notebook_id)
700 notebook_id = self.notebook_manager.copy_notebook(notebook_id)
704 self.redirect('/'+urljoin(self.base_project_url, notebook_id))
701 self.redirect('/'+urljoin(self.base_project_url, notebook_id))
705
702
706
703
707 #-----------------------------------------------------------------------------
704 #-----------------------------------------------------------------------------
708 # Cluster handlers
705 # Cluster handlers
709 #-----------------------------------------------------------------------------
706 #-----------------------------------------------------------------------------
710
707
711
708
712 class MainClusterHandler(IPythonHandler):
709 class MainClusterHandler(IPythonHandler):
713
710
714 @web.authenticated
711 @web.authenticated
715 def get(self):
712 def get(self):
716 self.finish(jsonapi.dumps(self.cluster_manager.list_profiles()))
713 self.finish(jsonapi.dumps(self.cluster_manager.list_profiles()))
717
714
718
715
719 class ClusterProfileHandler(IPythonHandler):
716 class ClusterProfileHandler(IPythonHandler):
720
717
721 @web.authenticated
718 @web.authenticated
722 def get(self, profile):
719 def get(self, profile):
723 self.finish(jsonapi.dumps(self.cluster_manager.profile_info(profile)))
720 self.finish(jsonapi.dumps(self.cluster_manager.profile_info(profile)))
724
721
725
722
726 class ClusterActionHandler(IPythonHandler):
723 class ClusterActionHandler(IPythonHandler):
727
724
728 @web.authenticated
725 @web.authenticated
729 def post(self, profile, action):
726 def post(self, profile, action):
730 cm = self.cluster_manager
727 cm = self.cluster_manager
731 if action == 'start':
728 if action == 'start':
732 n = self.get_argument('n',default=None)
729 n = self.get_argument('n',default=None)
733 if n is None:
730 if n is None:
734 data = cm.start_cluster(profile)
731 data = cm.start_cluster(profile)
735 else:
732 else:
736 data = cm.start_cluster(profile, int(n))
733 data = cm.start_cluster(profile, int(n))
737 if action == 'stop':
734 if action == 'stop':
738 data = cm.stop_cluster(profile)
735 data = cm.stop_cluster(profile)
739 self.finish(jsonapi.dumps(data))
736 self.finish(jsonapi.dumps(data))
740
737
741
738
742 #-----------------------------------------------------------------------------
739 #-----------------------------------------------------------------------------
743 # RST web service handlers
740 # RST web service handlers
744 #-----------------------------------------------------------------------------
741 #-----------------------------------------------------------------------------
745
742
746
743
747 class RSTHandler(IPythonHandler):
744 class RSTHandler(IPythonHandler):
748
745
749 @web.authenticated
746 @web.authenticated
750 def post(self):
747 def post(self):
751 if publish_string is None:
748 if publish_string is None:
752 raise web.HTTPError(503, u'docutils not available')
749 raise web.HTTPError(503, u'docutils not available')
753 body = self.request.body.strip()
750 body = self.request.body.strip()
754 source = body
751 source = body
755 # template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
752 # template_path=os.path.join(os.path.dirname(__file__), u'templates', u'rst_template.html')
756 defaults = {'file_insertion_enabled': 0,
753 defaults = {'file_insertion_enabled': 0,
757 'raw_enabled': 0,
754 'raw_enabled': 0,
758 '_disable_config': 1,
755 '_disable_config': 1,
759 'stylesheet_path': 0
756 'stylesheet_path': 0
760 # 'template': template_path
757 # 'template': template_path
761 }
758 }
762 try:
759 try:
763 html = publish_string(source, writer_name='html',
760 html = publish_string(source, writer_name='html',
764 settings_overrides=defaults
761 settings_overrides=defaults
765 )
762 )
766 except:
763 except:
767 raise web.HTTPError(400, u'Invalid RST')
764 raise web.HTTPError(400, u'Invalid RST')
768 print html
765 print html
769 self.set_header('Content-Type', 'text/html')
766 self.set_header('Content-Type', 'text/html')
770 self.finish(html)
767 self.finish(html)
771
768
772 # to minimize subclass changes:
769 # to minimize subclass changes:
773 HTTPError = web.HTTPError
770 HTTPError = web.HTTPError
774
771
775 class FileFindHandler(web.StaticFileHandler):
772 class FileFindHandler(web.StaticFileHandler):
776 """subclass of StaticFileHandler for serving files from a search path"""
773 """subclass of StaticFileHandler for serving files from a search path"""
777
774
778 _static_paths = {}
775 _static_paths = {}
779 # _lock is needed for tornado < 2.2.0 compat
776 # _lock is needed for tornado < 2.2.0 compat
780 _lock = threading.Lock() # protects _static_hashes
777 _lock = threading.Lock() # protects _static_hashes
781
778
782 def initialize(self, path, default_filename=None):
779 def initialize(self, path, default_filename=None):
783 if isinstance(path, basestring):
780 if isinstance(path, basestring):
784 path = [path]
781 path = [path]
785 self.roots = tuple(
782 self.roots = tuple(
786 os.path.abspath(os.path.expanduser(p)) + os.path.sep for p in path
783 os.path.abspath(os.path.expanduser(p)) + os.path.sep for p in path
787 )
784 )
788 self.default_filename = default_filename
785 self.default_filename = default_filename
789
786
790 @classmethod
787 @classmethod
791 def locate_file(cls, path, roots):
788 def locate_file(cls, path, roots):
792 """locate a file to serve on our static file search path"""
789 """locate a file to serve on our static file search path"""
793 with cls._lock:
790 with cls._lock:
794 if path in cls._static_paths:
791 if path in cls._static_paths:
795 return cls._static_paths[path]
792 return cls._static_paths[path]
796 try:
793 try:
797 abspath = os.path.abspath(filefind(path, roots))
794 abspath = os.path.abspath(filefind(path, roots))
798 except IOError:
795 except IOError:
799 # empty string should always give exists=False
796 # empty string should always give exists=False
800 return ''
797 return ''
801
798
802 # os.path.abspath strips a trailing /
799 # os.path.abspath strips a trailing /
803 # it needs to be temporarily added back for requests to root/
800 # it needs to be temporarily added back for requests to root/
804 if not (abspath + os.path.sep).startswith(roots):
801 if not (abspath + os.path.sep).startswith(roots):
805 raise HTTPError(403, "%s is not in root static directory", path)
802 raise HTTPError(403, "%s is not in root static directory", path)
806
803
807 cls._static_paths[path] = abspath
804 cls._static_paths[path] = abspath
808 return abspath
805 return abspath
809
806
810 def get(self, path, include_body=True):
807 def get(self, path, include_body=True):
811 path = self.parse_url_path(path)
808 path = self.parse_url_path(path)
812
809
813 # begin subclass override
810 # begin subclass override
814 abspath = self.locate_file(path, self.roots)
811 abspath = self.locate_file(path, self.roots)
815 # end subclass override
812 # end subclass override
816
813
817 if os.path.isdir(abspath) and self.default_filename is not None:
814 if os.path.isdir(abspath) and self.default_filename is not None:
818 # need to look at the request.path here for when path is empty
815 # need to look at the request.path here for when path is empty
819 # but there is some prefix to the path that was already
816 # but there is some prefix to the path that was already
820 # trimmed by the routing
817 # trimmed by the routing
821 if not self.request.path.endswith("/"):
818 if not self.request.path.endswith("/"):
822 self.redirect(self.request.path + "/")
819 self.redirect(self.request.path + "/")
823 return
820 return
824 abspath = os.path.join(abspath, self.default_filename)
821 abspath = os.path.join(abspath, self.default_filename)
825 if not os.path.exists(abspath):
822 if not os.path.exists(abspath):
826 raise HTTPError(404)
823 raise HTTPError(404)
827 if not os.path.isfile(abspath):
824 if not os.path.isfile(abspath):
828 raise HTTPError(403, "%s is not a file", path)
825 raise HTTPError(403, "%s is not a file", path)
829
826
830 stat_result = os.stat(abspath)
827 stat_result = os.stat(abspath)
831 modified = datetime.datetime.utcfromtimestamp(stat_result[stat.ST_MTIME])
828 modified = datetime.datetime.utcfromtimestamp(stat_result[stat.ST_MTIME])
832
829
833 self.set_header("Last-Modified", modified)
830 self.set_header("Last-Modified", modified)
834
831
835 mime_type, encoding = mimetypes.guess_type(abspath)
832 mime_type, encoding = mimetypes.guess_type(abspath)
836 if mime_type:
833 if mime_type:
837 self.set_header("Content-Type", mime_type)
834 self.set_header("Content-Type", mime_type)
838
835
839 cache_time = self.get_cache_time(path, modified, mime_type)
836 cache_time = self.get_cache_time(path, modified, mime_type)
840
837
841 if cache_time > 0:
838 if cache_time > 0:
842 self.set_header("Expires", datetime.datetime.utcnow() + \
839 self.set_header("Expires", datetime.datetime.utcnow() + \
843 datetime.timedelta(seconds=cache_time))
840 datetime.timedelta(seconds=cache_time))
844 self.set_header("Cache-Control", "max-age=" + str(cache_time))
841 self.set_header("Cache-Control", "max-age=" + str(cache_time))
845 else:
842 else:
846 self.set_header("Cache-Control", "public")
843 self.set_header("Cache-Control", "public")
847
844
848 self.set_extra_headers(path)
845 self.set_extra_headers(path)
849
846
850 # Check the If-Modified-Since, and don't send the result if the
847 # Check the If-Modified-Since, and don't send the result if the
851 # content has not been modified
848 # content has not been modified
852 ims_value = self.request.headers.get("If-Modified-Since")
849 ims_value = self.request.headers.get("If-Modified-Since")
853 if ims_value is not None:
850 if ims_value is not None:
854 date_tuple = email.utils.parsedate(ims_value)
851 date_tuple = email.utils.parsedate(ims_value)
855 if_since = datetime.datetime(*date_tuple[:6])
852 if_since = datetime.datetime(*date_tuple[:6])
856 if if_since >= modified:
853 if if_since >= modified:
857 self.set_status(304)
854 self.set_status(304)
858 return
855 return
859
856
860 with open(abspath, "rb") as file:
857 with open(abspath, "rb") as file:
861 data = file.read()
858 data = file.read()
862 hasher = hashlib.sha1()
859 hasher = hashlib.sha1()
863 hasher.update(data)
860 hasher.update(data)
864 self.set_header("Etag", '"%s"' % hasher.hexdigest())
861 self.set_header("Etag", '"%s"' % hasher.hexdigest())
865 if include_body:
862 if include_body:
866 self.write(data)
863 self.write(data)
867 else:
864 else:
868 assert self.request.method == "HEAD"
865 assert self.request.method == "HEAD"
869 self.set_header("Content-Length", len(data))
866 self.set_header("Content-Length", len(data))
870
867
871 @classmethod
868 @classmethod
872 def get_version(cls, settings, path):
869 def get_version(cls, settings, path):
873 """Generate the version string to be used in static URLs.
870 """Generate the version string to be used in static URLs.
874
871
875 This method may be overridden in subclasses (but note that it
872 This method may be overridden in subclasses (but note that it
876 is a class method rather than a static method). The default
873 is a class method rather than a static method). The default
877 implementation uses a hash of the file's contents.
874 implementation uses a hash of the file's contents.
878
875
879 ``settings`` is the `Application.settings` dictionary and ``path``
876 ``settings`` is the `Application.settings` dictionary and ``path``
880 is the relative location of the requested asset on the filesystem.
877 is the relative location of the requested asset on the filesystem.
881 The returned value should be a string, or ``None`` if no version
878 The returned value should be a string, or ``None`` if no version
882 could be determined.
879 could be determined.
883 """
880 """
884 # begin subclass override:
881 # begin subclass override:
885 static_paths = settings['static_path']
882 static_paths = settings['static_path']
886 if isinstance(static_paths, basestring):
883 if isinstance(static_paths, basestring):
887 static_paths = [static_paths]
884 static_paths = [static_paths]
888 roots = tuple(
885 roots = tuple(
889 os.path.abspath(os.path.expanduser(p)) + os.path.sep for p in static_paths
886 os.path.abspath(os.path.expanduser(p)) + os.path.sep for p in static_paths
890 )
887 )
891
888
892 try:
889 try:
893 abs_path = filefind(path, roots)
890 abs_path = filefind(path, roots)
894 except IOError:
891 except IOError:
895 app_log.error("Could not find static file %r", path)
892 app_log.error("Could not find static file %r", path)
896 return None
893 return None
897
894
898 # end subclass override
895 # end subclass override
899
896
900 with cls._lock:
897 with cls._lock:
901 hashes = cls._static_hashes
898 hashes = cls._static_hashes
902 if abs_path not in hashes:
899 if abs_path not in hashes:
903 try:
900 try:
904 f = open(abs_path, "rb")
901 f = open(abs_path, "rb")
905 hashes[abs_path] = hashlib.md5(f.read()).hexdigest()
902 hashes[abs_path] = hashlib.md5(f.read()).hexdigest()
906 f.close()
903 f.close()
907 except Exception:
904 except Exception:
908 app_log.error("Could not open static file %r", path)
905 app_log.error("Could not open static file %r", path)
909 hashes[abs_path] = None
906 hashes[abs_path] = None
910 hsh = hashes.get(abs_path)
907 hsh = hashes.get(abs_path)
911 if hsh:
908 if hsh:
912 return hsh[:5]
909 return hsh[:5]
913 return None
910 return None
914
911
915
912
916 def parse_url_path(self, url_path):
913 def parse_url_path(self, url_path):
917 """Converts a static URL path into a filesystem path.
914 """Converts a static URL path into a filesystem path.
918
915
919 ``url_path`` is the path component of the URL with
916 ``url_path`` is the path component of the URL with
920 ``static_url_prefix`` removed. The return value should be
917 ``static_url_prefix`` removed. The return value should be
921 filesystem path relative to ``static_path``.
918 filesystem path relative to ``static_path``.
922 """
919 """
923 if os.path.sep != "/":
920 if os.path.sep != "/":
924 url_path = url_path.replace("/", os.path.sep)
921 url_path = url_path.replace("/", os.path.sep)
925 return url_path
922 return url_path
926
923
927
924
@@ -1,740 +1,741 b''
1 # coding: utf-8
1 # coding: utf-8
2 """A tornado based IPython notebook server.
2 """A tornado based IPython notebook server.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # stdlib
19 # stdlib
20 import errno
20 import errno
21 import logging
21 import logging
22 import os
22 import os
23 import random
23 import random
24 import re
24 import re
25 import select
25 import select
26 import signal
26 import signal
27 import socket
27 import socket
28 import sys
28 import sys
29 import threading
29 import threading
30 import time
30 import time
31 import uuid
31 import uuid
32 import webbrowser
32 import webbrowser
33
33
34
34
35 # Third party
35 # Third party
36 # check for pyzmq 2.1.11
36 # check for pyzmq 2.1.11
37 from IPython.utils.zmqrelated import check_for_zmq
37 from IPython.utils.zmqrelated import check_for_zmq
38 check_for_zmq('2.1.11', 'IPython.frontend.html.notebook')
38 check_for_zmq('2.1.11', 'IPython.frontend.html.notebook')
39
39
40 import zmq
40 import zmq
41 from jinja2 import Environment, FileSystemLoader
41 from jinja2 import Environment, FileSystemLoader
42
42
43 # Install the pyzmq ioloop. This has to be done before anything else from
43 # Install the pyzmq ioloop. This has to be done before anything else from
44 # tornado is imported.
44 # tornado is imported.
45 from zmq.eventloop import ioloop
45 from zmq.eventloop import ioloop
46 ioloop.install()
46 ioloop.install()
47
47
48 # check for tornado 2.1.0
48 # check for tornado 2.1.0
49 msg = "The IPython Notebook requires tornado >= 2.1.0"
49 msg = "The IPython Notebook requires tornado >= 2.1.0"
50 try:
50 try:
51 import tornado
51 import tornado
52 except ImportError:
52 except ImportError:
53 raise ImportError(msg)
53 raise ImportError(msg)
54 try:
54 try:
55 version_info = tornado.version_info
55 version_info = tornado.version_info
56 except AttributeError:
56 except AttributeError:
57 raise ImportError(msg + ", but you have < 1.1.0")
57 raise ImportError(msg + ", but you have < 1.1.0")
58 if version_info < (2,1,0):
58 if version_info < (2,1,0):
59 raise ImportError(msg + ", but you have %s" % tornado.version)
59 raise ImportError(msg + ", but you have %s" % tornado.version)
60
60
61 from tornado import httpserver
61 from tornado import httpserver
62 from tornado import web
62 from tornado import web
63
63
64 # Our own libraries
64 # Our own libraries
65 from IPython.frontend.html.notebook import DEFAULT_STATIC_FILES_PATH
65 from IPython.frontend.html.notebook import DEFAULT_STATIC_FILES_PATH
66 from .kernelmanager import MappingKernelManager
66 from .kernelmanager import MappingKernelManager
67 from .handlers import (LoginHandler, LogoutHandler,
67 from .handlers import (LoginHandler, LogoutHandler,
68 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
68 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
69 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
69 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler, StdinHandler,
70 ShellHandler, NotebookRootHandler, NotebookHandler, NotebookCopyHandler,
70 ShellHandler, NotebookRootHandler, NotebookHandler, NotebookCopyHandler,
71 RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler,
71 RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler,
72 MainClusterHandler, ClusterProfileHandler, ClusterActionHandler,
72 MainClusterHandler, ClusterProfileHandler, ClusterActionHandler,
73 FileFindHandler, NotebookRedirectHandler,
73 FileFindHandler, NotebookRedirectHandler,
74 )
74 )
75 from .nbmanager import NotebookManager
75 from .nbmanager import NotebookManager
76 from .filenbmanager import FileNotebookManager
76 from .filenbmanager import FileNotebookManager
77 from .clustermanager import ClusterManager
77 from .clustermanager import ClusterManager
78
78
79 from IPython.config.application import catch_config_error, boolean_flag
79 from IPython.config.application import catch_config_error, boolean_flag
80 from IPython.core.application import BaseIPythonApplication
80 from IPython.core.application import BaseIPythonApplication
81 from IPython.core.profiledir import ProfileDir
81 from IPython.core.profiledir import ProfileDir
82 from IPython.frontend.consoleapp import IPythonConsoleApp
82 from IPython.frontend.consoleapp import IPythonConsoleApp
83 from IPython.kernel import swallow_argv
83 from IPython.kernel import swallow_argv
84 from IPython.kernel.zmq.session import Session, default_secure
84 from IPython.kernel.zmq.session import Session, default_secure
85 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
85 from IPython.kernel.zmq.zmqshell import ZMQInteractiveShell
86 from IPython.kernel.zmq.kernelapp import (
86 from IPython.kernel.zmq.kernelapp import (
87 kernel_flags,
87 kernel_flags,
88 kernel_aliases,
88 kernel_aliases,
89 IPKernelApp
89 IPKernelApp
90 )
90 )
91 from IPython.utils.importstring import import_item
91 from IPython.utils.importstring import import_item
92 from IPython.utils.localinterfaces import LOCALHOST
92 from IPython.utils.localinterfaces import LOCALHOST
93 from IPython.utils.traitlets import (
93 from IPython.utils.traitlets import (
94 Dict, Unicode, Integer, List, Enum, Bool,
94 Dict, Unicode, Integer, List, Enum, Bool,
95 DottedObjectName
95 DottedObjectName
96 )
96 )
97 from IPython.utils import py3compat
97 from IPython.utils import py3compat
98 from IPython.utils.path import filefind
98 from IPython.utils.path import filefind
99
99
100 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
101 # Module globals
101 # Module globals
102 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
103
103
104 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
104 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
105 _kernel_action_regex = r"(?P<action>restart|interrupt)"
105 _kernel_action_regex = r"(?P<action>restart|interrupt)"
106 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
106 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
107 _notebook_name_regex = r"(?P<notebook_name>.+\.ipynb)"
107 _notebook_name_regex = r"(?P<notebook_name>.+\.ipynb)"
108 _profile_regex = r"(?P<profile>[^\/]+)" # there is almost no text that is invalid
108 _profile_regex = r"(?P<profile>[^\/]+)" # there is almost no text that is invalid
109 _cluster_action_regex = r"(?P<action>start|stop)"
109 _cluster_action_regex = r"(?P<action>start|stop)"
110
110
111 _examples = """
111 _examples = """
112 ipython notebook # start the notebook
112 ipython notebook # start the notebook
113 ipython notebook --profile=sympy # use the sympy profile
113 ipython notebook --profile=sympy # use the sympy profile
114 ipython notebook --pylab=inline # pylab in inline plotting mode
114 ipython notebook --pylab=inline # pylab in inline plotting mode
115 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
115 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
116 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
116 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
117 """
117 """
118
118
119 #-----------------------------------------------------------------------------
119 #-----------------------------------------------------------------------------
120 # Helper functions
120 # Helper functions
121 #-----------------------------------------------------------------------------
121 #-----------------------------------------------------------------------------
122
122
123 def url_path_join(a,b):
123 def url_path_join(a,b):
124 if a.endswith('/') and b.startswith('/'):
124 if a.endswith('/') and b.startswith('/'):
125 return a[:-1]+b
125 return a[:-1]+b
126 else:
126 else:
127 return a+b
127 return a+b
128
128
129 def random_ports(port, n):
129 def random_ports(port, n):
130 """Generate a list of n random ports near the given port.
130 """Generate a list of n random ports near the given port.
131
131
132 The first 5 ports will be sequential, and the remaining n-5 will be
132 The first 5 ports will be sequential, and the remaining n-5 will be
133 randomly selected in the range [port-2*n, port+2*n].
133 randomly selected in the range [port-2*n, port+2*n].
134 """
134 """
135 for i in range(min(5, n)):
135 for i in range(min(5, n)):
136 yield port + i
136 yield port + i
137 for i in range(n-5):
137 for i in range(n-5):
138 yield port + random.randint(-2*n, 2*n)
138 yield port + random.randint(-2*n, 2*n)
139
139
140 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
141 # The Tornado web application
141 # The Tornado web application
142 #-----------------------------------------------------------------------------
142 #-----------------------------------------------------------------------------
143
143
144 class NotebookWebApplication(web.Application):
144 class NotebookWebApplication(web.Application):
145
145
146 def __init__(self, ipython_app, kernel_manager, notebook_manager,
146 def __init__(self, ipython_app, kernel_manager, notebook_manager,
147 cluster_manager, log,
147 cluster_manager, log,
148 base_project_url, settings_overrides):
148 base_project_url, settings_overrides):
149 handlers = [
149 handlers = [
150 (r"/", ProjectDashboardHandler),
150 (r"/", ProjectDashboardHandler),
151 (r"/login", LoginHandler),
151 (r"/login", LoginHandler),
152 (r"/logout", LogoutHandler),
152 (r"/logout", LogoutHandler),
153 (r"/new", NewHandler),
153 (r"/new", NewHandler),
154 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
154 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
155 (r"/%s" % _notebook_name_regex, NotebookRedirectHandler),
155 (r"/%s" % _notebook_name_regex, NotebookRedirectHandler),
156 (r"/%s/copy" % _notebook_id_regex, NotebookCopyHandler),
156 (r"/%s/copy" % _notebook_id_regex, NotebookCopyHandler),
157 (r"/%s/print" % _notebook_id_regex, PrintNotebookHandler),
157 (r"/%s/print" % _notebook_id_regex, PrintNotebookHandler),
158 (r"/kernels", MainKernelHandler),
158 (r"/kernels", MainKernelHandler),
159 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
159 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
160 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
160 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
161 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
161 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
162 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
162 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
163 (r"/kernels/%s/stdin" % _kernel_id_regex, StdinHandler),
163 (r"/notebooks", NotebookRootHandler),
164 (r"/notebooks", NotebookRootHandler),
164 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
165 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
165 (r"/rstservice/render", RSTHandler),
166 (r"/rstservice/render", RSTHandler),
166 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : notebook_manager.notebook_dir}),
167 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : notebook_manager.notebook_dir}),
167 (r"/clusters", MainClusterHandler),
168 (r"/clusters", MainClusterHandler),
168 (r"/clusters/%s/%s" % (_profile_regex, _cluster_action_regex), ClusterActionHandler),
169 (r"/clusters/%s/%s" % (_profile_regex, _cluster_action_regex), ClusterActionHandler),
169 (r"/clusters/%s" % _profile_regex, ClusterProfileHandler),
170 (r"/clusters/%s" % _profile_regex, ClusterProfileHandler),
170 ]
171 ]
171
172
172 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
173 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
173 # base_project_url will always be unicode, which will in turn
174 # base_project_url will always be unicode, which will in turn
174 # make the patterns unicode, and ultimately result in unicode
175 # make the patterns unicode, and ultimately result in unicode
175 # keys in kwargs to handler._execute(**kwargs) in tornado.
176 # keys in kwargs to handler._execute(**kwargs) in tornado.
176 # This enforces that base_project_url be ascii in that situation.
177 # This enforces that base_project_url be ascii in that situation.
177 #
178 #
178 # Note that the URLs these patterns check against are escaped,
179 # Note that the URLs these patterns check against are escaped,
179 # and thus guaranteed to be ASCII: 'hΓ©llo' is really 'h%C3%A9llo'.
180 # and thus guaranteed to be ASCII: 'hΓ©llo' is really 'h%C3%A9llo'.
180 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
181 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
181 template_path = os.path.join(os.path.dirname(__file__), "templates")
182 template_path = os.path.join(os.path.dirname(__file__), "templates")
182 settings = dict(
183 settings = dict(
183 # basics
184 # basics
184 base_project_url=base_project_url,
185 base_project_url=base_project_url,
185 base_kernel_url=ipython_app.base_kernel_url,
186 base_kernel_url=ipython_app.base_kernel_url,
186 template_path=template_path,
187 template_path=template_path,
187 static_path=ipython_app.static_file_path,
188 static_path=ipython_app.static_file_path,
188 static_handler_class = FileFindHandler,
189 static_handler_class = FileFindHandler,
189 static_url_prefix = url_path_join(base_project_url,'/static/'),
190 static_url_prefix = url_path_join(base_project_url,'/static/'),
190
191
191 # authentication
192 # authentication
192 cookie_secret=os.urandom(1024),
193 cookie_secret=os.urandom(1024),
193 login_url=url_path_join(base_project_url,'/login'),
194 login_url=url_path_join(base_project_url,'/login'),
194 cookie_name='username-%s' % uuid.uuid4(),
195 cookie_name='username-%s' % uuid.uuid4(),
195 read_only=ipython_app.read_only,
196 read_only=ipython_app.read_only,
196 password=ipython_app.password,
197 password=ipython_app.password,
197
198
198 # managers
199 # managers
199 kernel_manager=kernel_manager,
200 kernel_manager=kernel_manager,
200 notebook_manager=notebook_manager,
201 notebook_manager=notebook_manager,
201 cluster_manager=cluster_manager,
202 cluster_manager=cluster_manager,
202
203
203 # IPython stuff
204 # IPython stuff
204 max_msg_size=ipython_app.max_msg_size,
205 max_msg_size=ipython_app.max_msg_size,
205 config=ipython_app.config,
206 config=ipython_app.config,
206 use_less=ipython_app.use_less,
207 use_less=ipython_app.use_less,
207 jinja2_env=Environment(loader=FileSystemLoader(template_path)),
208 jinja2_env=Environment(loader=FileSystemLoader(template_path)),
208 )
209 )
209
210
210 # allow custom overrides for the tornado web app.
211 # allow custom overrides for the tornado web app.
211 settings.update(settings_overrides)
212 settings.update(settings_overrides)
212
213
213 # prepend base_project_url onto the patterns that we match
214 # prepend base_project_url onto the patterns that we match
214 new_handlers = []
215 new_handlers = []
215 for handler in handlers:
216 for handler in handlers:
216 pattern = url_path_join(base_project_url, handler[0])
217 pattern = url_path_join(base_project_url, handler[0])
217 new_handler = tuple([pattern] + list(handler[1:]))
218 new_handler = tuple([pattern] + list(handler[1:]))
218 new_handlers.append(new_handler)
219 new_handlers.append(new_handler)
219
220
220 super(NotebookWebApplication, self).__init__(new_handlers, **settings)
221 super(NotebookWebApplication, self).__init__(new_handlers, **settings)
221
222
222
223
223
224
224 #-----------------------------------------------------------------------------
225 #-----------------------------------------------------------------------------
225 # Aliases and Flags
226 # Aliases and Flags
226 #-----------------------------------------------------------------------------
227 #-----------------------------------------------------------------------------
227
228
228 flags = dict(kernel_flags)
229 flags = dict(kernel_flags)
229 flags['no-browser']=(
230 flags['no-browser']=(
230 {'NotebookApp' : {'open_browser' : False}},
231 {'NotebookApp' : {'open_browser' : False}},
231 "Don't open the notebook in a browser after startup."
232 "Don't open the notebook in a browser after startup."
232 )
233 )
233 flags['no-mathjax']=(
234 flags['no-mathjax']=(
234 {'NotebookApp' : {'enable_mathjax' : False}},
235 {'NotebookApp' : {'enable_mathjax' : False}},
235 """Disable MathJax
236 """Disable MathJax
236
237
237 MathJax is the javascript library IPython uses to render math/LaTeX. It is
238 MathJax is the javascript library IPython uses to render math/LaTeX. It is
238 very large, so you may want to disable it if you have a slow internet
239 very large, so you may want to disable it if you have a slow internet
239 connection, or for offline use of the notebook.
240 connection, or for offline use of the notebook.
240
241
241 When disabled, equations etc. will appear as their untransformed TeX source.
242 When disabled, equations etc. will appear as their untransformed TeX source.
242 """
243 """
243 )
244 )
244 flags['read-only'] = (
245 flags['read-only'] = (
245 {'NotebookApp' : {'read_only' : True}},
246 {'NotebookApp' : {'read_only' : True}},
246 """Allow read-only access to notebooks.
247 """Allow read-only access to notebooks.
247
248
248 When using a password to protect the notebook server, this flag
249 When using a password to protect the notebook server, this flag
249 allows unauthenticated clients to view the notebook list, and
250 allows unauthenticated clients to view the notebook list, and
250 individual notebooks, but not edit them, start kernels, or run
251 individual notebooks, but not edit them, start kernels, or run
251 code.
252 code.
252
253
253 If no password is set, the server will be entirely read-only.
254 If no password is set, the server will be entirely read-only.
254 """
255 """
255 )
256 )
256
257
257 # Add notebook manager flags
258 # Add notebook manager flags
258 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
259 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
259 'Auto-save a .py script everytime the .ipynb notebook is saved',
260 'Auto-save a .py script everytime the .ipynb notebook is saved',
260 'Do not auto-save .py scripts for every notebook'))
261 'Do not auto-save .py scripts for every notebook'))
261
262
262 # the flags that are specific to the frontend
263 # the flags that are specific to the frontend
263 # these must be scrubbed before being passed to the kernel,
264 # these must be scrubbed before being passed to the kernel,
264 # or it will raise an error on unrecognized flags
265 # or it will raise an error on unrecognized flags
265 notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script']
266 notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script']
266
267
267 aliases = dict(kernel_aliases)
268 aliases = dict(kernel_aliases)
268
269
269 aliases.update({
270 aliases.update({
270 'ip': 'NotebookApp.ip',
271 'ip': 'NotebookApp.ip',
271 'port': 'NotebookApp.port',
272 'port': 'NotebookApp.port',
272 'port-retries': 'NotebookApp.port_retries',
273 'port-retries': 'NotebookApp.port_retries',
273 'transport': 'KernelManager.transport',
274 'transport': 'KernelManager.transport',
274 'keyfile': 'NotebookApp.keyfile',
275 'keyfile': 'NotebookApp.keyfile',
275 'certfile': 'NotebookApp.certfile',
276 'certfile': 'NotebookApp.certfile',
276 'notebook-dir': 'NotebookManager.notebook_dir',
277 'notebook-dir': 'NotebookManager.notebook_dir',
277 'browser': 'NotebookApp.browser',
278 'browser': 'NotebookApp.browser',
278 })
279 })
279
280
280 # remove ipkernel flags that are singletons, and don't make sense in
281 # remove ipkernel flags that are singletons, and don't make sense in
281 # multi-kernel evironment:
282 # multi-kernel evironment:
282 aliases.pop('f', None)
283 aliases.pop('f', None)
283
284
284 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
285 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
285 u'notebook-dir']
286 u'notebook-dir']
286
287
287 #-----------------------------------------------------------------------------
288 #-----------------------------------------------------------------------------
288 # NotebookApp
289 # NotebookApp
289 #-----------------------------------------------------------------------------
290 #-----------------------------------------------------------------------------
290
291
291 class NotebookApp(BaseIPythonApplication):
292 class NotebookApp(BaseIPythonApplication):
292
293
293 name = 'ipython-notebook'
294 name = 'ipython-notebook'
294 default_config_file_name='ipython_notebook_config.py'
295 default_config_file_name='ipython_notebook_config.py'
295
296
296 description = """
297 description = """
297 The IPython HTML Notebook.
298 The IPython HTML Notebook.
298
299
299 This launches a Tornado based HTML Notebook Server that serves up an
300 This launches a Tornado based HTML Notebook Server that serves up an
300 HTML5/Javascript Notebook client.
301 HTML5/Javascript Notebook client.
301 """
302 """
302 examples = _examples
303 examples = _examples
303
304
304 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
305 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
305 FileNotebookManager]
306 FileNotebookManager]
306 flags = Dict(flags)
307 flags = Dict(flags)
307 aliases = Dict(aliases)
308 aliases = Dict(aliases)
308
309
309 kernel_argv = List(Unicode)
310 kernel_argv = List(Unicode)
310
311
311 max_msg_size = Integer(65536, config=True, help="""
312 max_msg_size = Integer(65536, config=True, help="""
312 The max raw message size accepted from the browser
313 The max raw message size accepted from the browser
313 over a WebSocket connection.
314 over a WebSocket connection.
314 """)
315 """)
315
316
316 def _log_level_default(self):
317 def _log_level_default(self):
317 return logging.INFO
318 return logging.INFO
318
319
319 def _log_format_default(self):
320 def _log_format_default(self):
320 """override default log format to include time"""
321 """override default log format to include time"""
321 return u"%(asctime)s.%(msecs).03d [%(name)s] %(message)s"
322 return u"%(asctime)s.%(msecs).03d [%(name)s] %(message)s"
322
323
323 # create requested profiles by default, if they don't exist:
324 # create requested profiles by default, if they don't exist:
324 auto_create = Bool(True)
325 auto_create = Bool(True)
325
326
326 # file to be opened in the notebook server
327 # file to be opened in the notebook server
327 file_to_run = Unicode('')
328 file_to_run = Unicode('')
328
329
329 # Network related information.
330 # Network related information.
330
331
331 ip = Unicode(LOCALHOST, config=True,
332 ip = Unicode(LOCALHOST, config=True,
332 help="The IP address the notebook server will listen on."
333 help="The IP address the notebook server will listen on."
333 )
334 )
334
335
335 def _ip_changed(self, name, old, new):
336 def _ip_changed(self, name, old, new):
336 if new == u'*': self.ip = u''
337 if new == u'*': self.ip = u''
337
338
338 port = Integer(8888, config=True,
339 port = Integer(8888, config=True,
339 help="The port the notebook server will listen on."
340 help="The port the notebook server will listen on."
340 )
341 )
341 port_retries = Integer(50, config=True,
342 port_retries = Integer(50, config=True,
342 help="The number of additional ports to try if the specified port is not available."
343 help="The number of additional ports to try if the specified port is not available."
343 )
344 )
344
345
345 certfile = Unicode(u'', config=True,
346 certfile = Unicode(u'', config=True,
346 help="""The full path to an SSL/TLS certificate file."""
347 help="""The full path to an SSL/TLS certificate file."""
347 )
348 )
348
349
349 keyfile = Unicode(u'', config=True,
350 keyfile = Unicode(u'', config=True,
350 help="""The full path to a private key file for usage with SSL/TLS."""
351 help="""The full path to a private key file for usage with SSL/TLS."""
351 )
352 )
352
353
353 password = Unicode(u'', config=True,
354 password = Unicode(u'', config=True,
354 help="""Hashed password to use for web authentication.
355 help="""Hashed password to use for web authentication.
355
356
356 To generate, type in a python/IPython shell:
357 To generate, type in a python/IPython shell:
357
358
358 from IPython.lib import passwd; passwd()
359 from IPython.lib import passwd; passwd()
359
360
360 The string should be of the form type:salt:hashed-password.
361 The string should be of the form type:salt:hashed-password.
361 """
362 """
362 )
363 )
363
364
364 open_browser = Bool(True, config=True,
365 open_browser = Bool(True, config=True,
365 help="""Whether to open in a browser after starting.
366 help="""Whether to open in a browser after starting.
366 The specific browser used is platform dependent and
367 The specific browser used is platform dependent and
367 determined by the python standard library `webbrowser`
368 determined by the python standard library `webbrowser`
368 module, unless it is overridden using the --browser
369 module, unless it is overridden using the --browser
369 (NotebookApp.browser) configuration option.
370 (NotebookApp.browser) configuration option.
370 """)
371 """)
371
372
372 browser = Unicode(u'', config=True,
373 browser = Unicode(u'', config=True,
373 help="""Specify what command to use to invoke a web
374 help="""Specify what command to use to invoke a web
374 browser when opening the notebook. If not specified, the
375 browser when opening the notebook. If not specified, the
375 default browser will be determined by the `webbrowser`
376 default browser will be determined by the `webbrowser`
376 standard library module, which allows setting of the
377 standard library module, which allows setting of the
377 BROWSER environment variable to override it.
378 BROWSER environment variable to override it.
378 """)
379 """)
379
380
380 read_only = Bool(False, config=True,
381 read_only = Bool(False, config=True,
381 help="Whether to prevent editing/execution of notebooks."
382 help="Whether to prevent editing/execution of notebooks."
382 )
383 )
383
384
384 use_less = Bool(False, config=True,
385 use_less = Bool(False, config=True,
385 help="""Wether to use Browser Side less-css parsing
386 help="""Wether to use Browser Side less-css parsing
386 instead of compiled css version in templates that allows
387 instead of compiled css version in templates that allows
387 it. This is mainly convenient when working on the less
388 it. This is mainly convenient when working on the less
388 file to avoid a build step, or if user want to overwrite
389 file to avoid a build step, or if user want to overwrite
389 some of the less variables without having to recompile
390 some of the less variables without having to recompile
390 everything.
391 everything.
391
392
392 You will need to install the less.js component in the static directory
393 You will need to install the less.js component in the static directory
393 either in the source tree or in your profile folder.
394 either in the source tree or in your profile folder.
394 """)
395 """)
395
396
396 webapp_settings = Dict(config=True,
397 webapp_settings = Dict(config=True,
397 help="Supply overrides for the tornado.web.Application that the "
398 help="Supply overrides for the tornado.web.Application that the "
398 "IPython notebook uses.")
399 "IPython notebook uses.")
399
400
400 enable_mathjax = Bool(True, config=True,
401 enable_mathjax = Bool(True, config=True,
401 help="""Whether to enable MathJax for typesetting math/TeX
402 help="""Whether to enable MathJax for typesetting math/TeX
402
403
403 MathJax is the javascript library IPython uses to render math/LaTeX. It is
404 MathJax is the javascript library IPython uses to render math/LaTeX. It is
404 very large, so you may want to disable it if you have a slow internet
405 very large, so you may want to disable it if you have a slow internet
405 connection, or for offline use of the notebook.
406 connection, or for offline use of the notebook.
406
407
407 When disabled, equations etc. will appear as their untransformed TeX source.
408 When disabled, equations etc. will appear as their untransformed TeX source.
408 """
409 """
409 )
410 )
410 def _enable_mathjax_changed(self, name, old, new):
411 def _enable_mathjax_changed(self, name, old, new):
411 """set mathjax url to empty if mathjax is disabled"""
412 """set mathjax url to empty if mathjax is disabled"""
412 if not new:
413 if not new:
413 self.mathjax_url = u''
414 self.mathjax_url = u''
414
415
415 base_project_url = Unicode('/', config=True,
416 base_project_url = Unicode('/', config=True,
416 help='''The base URL for the notebook server.
417 help='''The base URL for the notebook server.
417
418
418 Leading and trailing slashes can be omitted,
419 Leading and trailing slashes can be omitted,
419 and will automatically be added.
420 and will automatically be added.
420 ''')
421 ''')
421 def _base_project_url_changed(self, name, old, new):
422 def _base_project_url_changed(self, name, old, new):
422 if not new.startswith('/'):
423 if not new.startswith('/'):
423 self.base_project_url = '/'+new
424 self.base_project_url = '/'+new
424 elif not new.endswith('/'):
425 elif not new.endswith('/'):
425 self.base_project_url = new+'/'
426 self.base_project_url = new+'/'
426
427
427 base_kernel_url = Unicode('/', config=True,
428 base_kernel_url = Unicode('/', config=True,
428 help='''The base URL for the kernel server
429 help='''The base URL for the kernel server
429
430
430 Leading and trailing slashes can be omitted,
431 Leading and trailing slashes can be omitted,
431 and will automatically be added.
432 and will automatically be added.
432 ''')
433 ''')
433 def _base_kernel_url_changed(self, name, old, new):
434 def _base_kernel_url_changed(self, name, old, new):
434 if not new.startswith('/'):
435 if not new.startswith('/'):
435 self.base_kernel_url = '/'+new
436 self.base_kernel_url = '/'+new
436 elif not new.endswith('/'):
437 elif not new.endswith('/'):
437 self.base_kernel_url = new+'/'
438 self.base_kernel_url = new+'/'
438
439
439 websocket_host = Unicode("", config=True,
440 websocket_host = Unicode("", config=True,
440 help="""The hostname for the websocket server."""
441 help="""The hostname for the websocket server."""
441 )
442 )
442
443
443 extra_static_paths = List(Unicode, config=True,
444 extra_static_paths = List(Unicode, config=True,
444 help="""Extra paths to search for serving static files.
445 help="""Extra paths to search for serving static files.
445
446
446 This allows adding javascript/css to be available from the notebook server machine,
447 This allows adding javascript/css to be available from the notebook server machine,
447 or overriding individual files in the IPython"""
448 or overriding individual files in the IPython"""
448 )
449 )
449 def _extra_static_paths_default(self):
450 def _extra_static_paths_default(self):
450 return [os.path.join(self.profile_dir.location, 'static')]
451 return [os.path.join(self.profile_dir.location, 'static')]
451
452
452 @property
453 @property
453 def static_file_path(self):
454 def static_file_path(self):
454 """return extra paths + the default location"""
455 """return extra paths + the default location"""
455 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
456 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
456
457
457 mathjax_url = Unicode("", config=True,
458 mathjax_url = Unicode("", config=True,
458 help="""The url for MathJax.js."""
459 help="""The url for MathJax.js."""
459 )
460 )
460 def _mathjax_url_default(self):
461 def _mathjax_url_default(self):
461 if not self.enable_mathjax:
462 if not self.enable_mathjax:
462 return u''
463 return u''
463 static_url_prefix = self.webapp_settings.get("static_url_prefix",
464 static_url_prefix = self.webapp_settings.get("static_url_prefix",
464 "/static/")
465 "/static/")
465 try:
466 try:
466 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), self.static_file_path)
467 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), self.static_file_path)
467 except IOError:
468 except IOError:
468 if self.certfile:
469 if self.certfile:
469 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
470 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
470 base = u"https://c328740.ssl.cf1.rackcdn.com"
471 base = u"https://c328740.ssl.cf1.rackcdn.com"
471 else:
472 else:
472 base = u"http://cdn.mathjax.org"
473 base = u"http://cdn.mathjax.org"
473
474
474 url = base + u"/mathjax/latest/MathJax.js"
475 url = base + u"/mathjax/latest/MathJax.js"
475 self.log.info("Using MathJax from CDN: %s", url)
476 self.log.info("Using MathJax from CDN: %s", url)
476 return url
477 return url
477 else:
478 else:
478 self.log.info("Using local MathJax from %s" % mathjax)
479 self.log.info("Using local MathJax from %s" % mathjax)
479 return static_url_prefix+u"mathjax/MathJax.js"
480 return static_url_prefix+u"mathjax/MathJax.js"
480
481
481 def _mathjax_url_changed(self, name, old, new):
482 def _mathjax_url_changed(self, name, old, new):
482 if new and not self.enable_mathjax:
483 if new and not self.enable_mathjax:
483 # enable_mathjax=False overrides mathjax_url
484 # enable_mathjax=False overrides mathjax_url
484 self.mathjax_url = u''
485 self.mathjax_url = u''
485 else:
486 else:
486 self.log.info("Using MathJax: %s", new)
487 self.log.info("Using MathJax: %s", new)
487
488
488 notebook_manager_class = DottedObjectName('IPython.frontend.html.notebook.filenbmanager.FileNotebookManager',
489 notebook_manager_class = DottedObjectName('IPython.frontend.html.notebook.filenbmanager.FileNotebookManager',
489 config=True,
490 config=True,
490 help='The notebook manager class to use.')
491 help='The notebook manager class to use.')
491
492
492 trust_xheaders = Bool(False, config=True,
493 trust_xheaders = Bool(False, config=True,
493 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
494 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
494 "sent by the upstream reverse proxy. Neccesary if the proxy handles SSL")
495 "sent by the upstream reverse proxy. Neccesary if the proxy handles SSL")
495 )
496 )
496
497
497 def parse_command_line(self, argv=None):
498 def parse_command_line(self, argv=None):
498 super(NotebookApp, self).parse_command_line(argv)
499 super(NotebookApp, self).parse_command_line(argv)
499 if argv is None:
500 if argv is None:
500 argv = sys.argv[1:]
501 argv = sys.argv[1:]
501
502
502 # Scrub frontend-specific flags
503 # Scrub frontend-specific flags
503 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
504 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
504 # Kernel should inherit default config file from frontend
505 # Kernel should inherit default config file from frontend
505 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
506 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
506
507
507 if self.extra_args:
508 if self.extra_args:
508 f = os.path.abspath(self.extra_args[0])
509 f = os.path.abspath(self.extra_args[0])
509 if os.path.isdir(f):
510 if os.path.isdir(f):
510 nbdir = f
511 nbdir = f
511 else:
512 else:
512 self.file_to_run = f
513 self.file_to_run = f
513 nbdir = os.path.dirname(f)
514 nbdir = os.path.dirname(f)
514 self.config.NotebookManager.notebook_dir = nbdir
515 self.config.NotebookManager.notebook_dir = nbdir
515
516
516 def init_configurables(self):
517 def init_configurables(self):
517 # force Session default to be secure
518 # force Session default to be secure
518 default_secure(self.config)
519 default_secure(self.config)
519 self.kernel_manager = MappingKernelManager(
520 self.kernel_manager = MappingKernelManager(
520 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
521 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
521 connection_dir = self.profile_dir.security_dir,
522 connection_dir = self.profile_dir.security_dir,
522 )
523 )
523 kls = import_item(self.notebook_manager_class)
524 kls = import_item(self.notebook_manager_class)
524 self.notebook_manager = kls(config=self.config, log=self.log)
525 self.notebook_manager = kls(config=self.config, log=self.log)
525 self.notebook_manager.load_notebook_names()
526 self.notebook_manager.load_notebook_names()
526 self.cluster_manager = ClusterManager(config=self.config, log=self.log)
527 self.cluster_manager = ClusterManager(config=self.config, log=self.log)
527 self.cluster_manager.update_profiles()
528 self.cluster_manager.update_profiles()
528
529
529 def init_logging(self):
530 def init_logging(self):
530 # This prevents double log messages because tornado use a root logger that
531 # This prevents double log messages because tornado use a root logger that
531 # self.log is a child of. The logging module dipatches log messages to a log
532 # self.log is a child of. The logging module dipatches log messages to a log
532 # and all of its ancenstors until propagate is set to False.
533 # and all of its ancenstors until propagate is set to False.
533 self.log.propagate = False
534 self.log.propagate = False
534
535
535 # set the date format
536 # set the date format
536 formatter = logging.Formatter(self.log_format, datefmt="%Y-%m-%d %H:%M:%S")
537 formatter = logging.Formatter(self.log_format, datefmt="%Y-%m-%d %H:%M:%S")
537 self.log.handlers[0].setFormatter(formatter)
538 self.log.handlers[0].setFormatter(formatter)
538
539
539 # hook up tornado 3's loggers to our app handlers
540 # hook up tornado 3's loggers to our app handlers
540 for name in ('access', 'application', 'general'):
541 for name in ('access', 'application', 'general'):
541 logging.getLogger('tornado.%s' % name).handlers = self.log.handlers
542 logging.getLogger('tornado.%s' % name).handlers = self.log.handlers
542
543
543 def init_webapp(self):
544 def init_webapp(self):
544 """initialize tornado webapp and httpserver"""
545 """initialize tornado webapp and httpserver"""
545 self.web_app = NotebookWebApplication(
546 self.web_app = NotebookWebApplication(
546 self, self.kernel_manager, self.notebook_manager,
547 self, self.kernel_manager, self.notebook_manager,
547 self.cluster_manager, self.log,
548 self.cluster_manager, self.log,
548 self.base_project_url, self.webapp_settings
549 self.base_project_url, self.webapp_settings
549 )
550 )
550 if self.certfile:
551 if self.certfile:
551 ssl_options = dict(certfile=self.certfile)
552 ssl_options = dict(certfile=self.certfile)
552 if self.keyfile:
553 if self.keyfile:
553 ssl_options['keyfile'] = self.keyfile
554 ssl_options['keyfile'] = self.keyfile
554 else:
555 else:
555 ssl_options = None
556 ssl_options = None
556 self.web_app.password = self.password
557 self.web_app.password = self.password
557 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
558 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
558 xheaders=self.trust_xheaders)
559 xheaders=self.trust_xheaders)
559 if not self.ip:
560 if not self.ip:
560 warning = "WARNING: The notebook server is listening on all IP addresses"
561 warning = "WARNING: The notebook server is listening on all IP addresses"
561 if ssl_options is None:
562 if ssl_options is None:
562 self.log.critical(warning + " and not using encryption. This"
563 self.log.critical(warning + " and not using encryption. This"
563 "is not recommended.")
564 "is not recommended.")
564 if not self.password and not self.read_only:
565 if not self.password and not self.read_only:
565 self.log.critical(warning + "and not using authentication."
566 self.log.critical(warning + "and not using authentication."
566 "This is highly insecure and not recommended.")
567 "This is highly insecure and not recommended.")
567 success = None
568 success = None
568 for port in random_ports(self.port, self.port_retries+1):
569 for port in random_ports(self.port, self.port_retries+1):
569 try:
570 try:
570 self.http_server.listen(port, self.ip)
571 self.http_server.listen(port, self.ip)
571 except socket.error as e:
572 except socket.error as e:
572 # XXX: remove the e.errno == -9 block when we require
573 # XXX: remove the e.errno == -9 block when we require
573 # tornado >= 3.0
574 # tornado >= 3.0
574 if e.errno == -9 and tornado.version_info[0] < 3:
575 if e.errno == -9 and tornado.version_info[0] < 3:
575 # The flags passed to socket.getaddrinfo from
576 # The flags passed to socket.getaddrinfo from
576 # tornado.netutils.bind_sockets can cause "gaierror:
577 # tornado.netutils.bind_sockets can cause "gaierror:
577 # [Errno -9] Address family for hostname not supported"
578 # [Errno -9] Address family for hostname not supported"
578 # when the interface is not associated, for example.
579 # when the interface is not associated, for example.
579 # Changing the flags to exclude socket.AI_ADDRCONFIG does
580 # Changing the flags to exclude socket.AI_ADDRCONFIG does
580 # not cause this error, but the only way to do this is to
581 # not cause this error, but the only way to do this is to
581 # monkeypatch socket to remove the AI_ADDRCONFIG attribute
582 # monkeypatch socket to remove the AI_ADDRCONFIG attribute
582 saved_AI_ADDRCONFIG = socket.AI_ADDRCONFIG
583 saved_AI_ADDRCONFIG = socket.AI_ADDRCONFIG
583 self.log.warn('Monkeypatching socket to fix tornado bug')
584 self.log.warn('Monkeypatching socket to fix tornado bug')
584 del(socket.AI_ADDRCONFIG)
585 del(socket.AI_ADDRCONFIG)
585 try:
586 try:
586 # retry the tornado call without AI_ADDRCONFIG flags
587 # retry the tornado call without AI_ADDRCONFIG flags
587 self.http_server.listen(port, self.ip)
588 self.http_server.listen(port, self.ip)
588 except socket.error as e2:
589 except socket.error as e2:
589 e = e2
590 e = e2
590 else:
591 else:
591 self.port = port
592 self.port = port
592 success = True
593 success = True
593 break
594 break
594 # restore the monekypatch
595 # restore the monekypatch
595 socket.AI_ADDRCONFIG = saved_AI_ADDRCONFIG
596 socket.AI_ADDRCONFIG = saved_AI_ADDRCONFIG
596 if e.errno != errno.EADDRINUSE:
597 if e.errno != errno.EADDRINUSE:
597 raise
598 raise
598 self.log.info('The port %i is already in use, trying another random port.' % port)
599 self.log.info('The port %i is already in use, trying another random port.' % port)
599 else:
600 else:
600 self.port = port
601 self.port = port
601 success = True
602 success = True
602 break
603 break
603 if not success:
604 if not success:
604 self.log.critical('ERROR: the notebook server could not be started because '
605 self.log.critical('ERROR: the notebook server could not be started because '
605 'no available port could be found.')
606 'no available port could be found.')
606 self.exit(1)
607 self.exit(1)
607
608
608 def init_signal(self):
609 def init_signal(self):
609 if not sys.platform.startswith('win'):
610 if not sys.platform.startswith('win'):
610 signal.signal(signal.SIGINT, self._handle_sigint)
611 signal.signal(signal.SIGINT, self._handle_sigint)
611 signal.signal(signal.SIGTERM, self._signal_stop)
612 signal.signal(signal.SIGTERM, self._signal_stop)
612 if hasattr(signal, 'SIGUSR1'):
613 if hasattr(signal, 'SIGUSR1'):
613 # Windows doesn't support SIGUSR1
614 # Windows doesn't support SIGUSR1
614 signal.signal(signal.SIGUSR1, self._signal_info)
615 signal.signal(signal.SIGUSR1, self._signal_info)
615 if hasattr(signal, 'SIGINFO'):
616 if hasattr(signal, 'SIGINFO'):
616 # only on BSD-based systems
617 # only on BSD-based systems
617 signal.signal(signal.SIGINFO, self._signal_info)
618 signal.signal(signal.SIGINFO, self._signal_info)
618
619
619 def _handle_sigint(self, sig, frame):
620 def _handle_sigint(self, sig, frame):
620 """SIGINT handler spawns confirmation dialog"""
621 """SIGINT handler spawns confirmation dialog"""
621 # register more forceful signal handler for ^C^C case
622 # register more forceful signal handler for ^C^C case
622 signal.signal(signal.SIGINT, self._signal_stop)
623 signal.signal(signal.SIGINT, self._signal_stop)
623 # request confirmation dialog in bg thread, to avoid
624 # request confirmation dialog in bg thread, to avoid
624 # blocking the App
625 # blocking the App
625 thread = threading.Thread(target=self._confirm_exit)
626 thread = threading.Thread(target=self._confirm_exit)
626 thread.daemon = True
627 thread.daemon = True
627 thread.start()
628 thread.start()
628
629
629 def _restore_sigint_handler(self):
630 def _restore_sigint_handler(self):
630 """callback for restoring original SIGINT handler"""
631 """callback for restoring original SIGINT handler"""
631 signal.signal(signal.SIGINT, self._handle_sigint)
632 signal.signal(signal.SIGINT, self._handle_sigint)
632
633
633 def _confirm_exit(self):
634 def _confirm_exit(self):
634 """confirm shutdown on ^C
635 """confirm shutdown on ^C
635
636
636 A second ^C, or answering 'y' within 5s will cause shutdown,
637 A second ^C, or answering 'y' within 5s will cause shutdown,
637 otherwise original SIGINT handler will be restored.
638 otherwise original SIGINT handler will be restored.
638
639
639 This doesn't work on Windows.
640 This doesn't work on Windows.
640 """
641 """
641 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
642 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
642 time.sleep(0.1)
643 time.sleep(0.1)
643 info = self.log.info
644 info = self.log.info
644 info('interrupted')
645 info('interrupted')
645 print self.notebook_info()
646 print self.notebook_info()
646 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
647 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
647 sys.stdout.flush()
648 sys.stdout.flush()
648 r,w,x = select.select([sys.stdin], [], [], 5)
649 r,w,x = select.select([sys.stdin], [], [], 5)
649 if r:
650 if r:
650 line = sys.stdin.readline()
651 line = sys.stdin.readline()
651 if line.lower().startswith('y'):
652 if line.lower().startswith('y'):
652 self.log.critical("Shutdown confirmed")
653 self.log.critical("Shutdown confirmed")
653 ioloop.IOLoop.instance().stop()
654 ioloop.IOLoop.instance().stop()
654 return
655 return
655 else:
656 else:
656 print "No answer for 5s:",
657 print "No answer for 5s:",
657 print "resuming operation..."
658 print "resuming operation..."
658 # no answer, or answer is no:
659 # no answer, or answer is no:
659 # set it back to original SIGINT handler
660 # set it back to original SIGINT handler
660 # use IOLoop.add_callback because signal.signal must be called
661 # use IOLoop.add_callback because signal.signal must be called
661 # from main thread
662 # from main thread
662 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
663 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
663
664
664 def _signal_stop(self, sig, frame):
665 def _signal_stop(self, sig, frame):
665 self.log.critical("received signal %s, stopping", sig)
666 self.log.critical("received signal %s, stopping", sig)
666 ioloop.IOLoop.instance().stop()
667 ioloop.IOLoop.instance().stop()
667
668
668 def _signal_info(self, sig, frame):
669 def _signal_info(self, sig, frame):
669 print self.notebook_info()
670 print self.notebook_info()
670
671
671 @catch_config_error
672 @catch_config_error
672 def initialize(self, argv=None):
673 def initialize(self, argv=None):
673 self.init_logging()
674 self.init_logging()
674 super(NotebookApp, self).initialize(argv)
675 super(NotebookApp, self).initialize(argv)
675 self.init_configurables()
676 self.init_configurables()
676 self.init_webapp()
677 self.init_webapp()
677 self.init_signal()
678 self.init_signal()
678
679
679 def cleanup_kernels(self):
680 def cleanup_kernels(self):
680 """Shutdown all kernels.
681 """Shutdown all kernels.
681
682
682 The kernels will shutdown themselves when this process no longer exists,
683 The kernels will shutdown themselves when this process no longer exists,
683 but explicit shutdown allows the KernelManagers to cleanup the connection files.
684 but explicit shutdown allows the KernelManagers to cleanup the connection files.
684 """
685 """
685 self.log.info('Shutting down kernels')
686 self.log.info('Shutting down kernels')
686 self.kernel_manager.shutdown_all()
687 self.kernel_manager.shutdown_all()
687
688
688 def notebook_info(self):
689 def notebook_info(self):
689 "Return the current working directory and the server url information"
690 "Return the current working directory and the server url information"
690 mgr_info = self.notebook_manager.info_string() + "\n"
691 mgr_info = self.notebook_manager.info_string() + "\n"
691 return mgr_info +"The IPython Notebook is running at: %s" % self._url
692 return mgr_info +"The IPython Notebook is running at: %s" % self._url
692
693
693 def start(self):
694 def start(self):
694 """ Start the IPython Notebook server app, after initialization
695 """ Start the IPython Notebook server app, after initialization
695
696
696 This method takes no arguments so all configuration and initialization
697 This method takes no arguments so all configuration and initialization
697 must be done prior to calling this method."""
698 must be done prior to calling this method."""
698 ip = self.ip if self.ip else '[all ip addresses on your system]'
699 ip = self.ip if self.ip else '[all ip addresses on your system]'
699 proto = 'https' if self.certfile else 'http'
700 proto = 'https' if self.certfile else 'http'
700 info = self.log.info
701 info = self.log.info
701 self._url = "%s://%s:%i%s" % (proto, ip, self.port,
702 self._url = "%s://%s:%i%s" % (proto, ip, self.port,
702 self.base_project_url)
703 self.base_project_url)
703 for line in self.notebook_info().split("\n"):
704 for line in self.notebook_info().split("\n"):
704 info(line)
705 info(line)
705 info("Use Control-C to stop this server and shut down all kernels.")
706 info("Use Control-C to stop this server and shut down all kernels.")
706
707
707 if self.open_browser or self.file_to_run:
708 if self.open_browser or self.file_to_run:
708 ip = self.ip or LOCALHOST
709 ip = self.ip or LOCALHOST
709 try:
710 try:
710 browser = webbrowser.get(self.browser or None)
711 browser = webbrowser.get(self.browser or None)
711 except webbrowser.Error as e:
712 except webbrowser.Error as e:
712 self.log.warn('No web browser found: %s.' % e)
713 self.log.warn('No web browser found: %s.' % e)
713 browser = None
714 browser = None
714
715
715 if self.file_to_run:
716 if self.file_to_run:
716 name, _ = os.path.splitext(os.path.basename(self.file_to_run))
717 name, _ = os.path.splitext(os.path.basename(self.file_to_run))
717 url = self.notebook_manager.rev_mapping.get(name, '')
718 url = self.notebook_manager.rev_mapping.get(name, '')
718 else:
719 else:
719 url = ''
720 url = ''
720 if browser:
721 if browser:
721 b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip,
722 b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip,
722 self.port, self.base_project_url, url), new=2)
723 self.port, self.base_project_url, url), new=2)
723 threading.Thread(target=b).start()
724 threading.Thread(target=b).start()
724 try:
725 try:
725 ioloop.IOLoop.instance().start()
726 ioloop.IOLoop.instance().start()
726 except KeyboardInterrupt:
727 except KeyboardInterrupt:
727 info("Interrupted...")
728 info("Interrupted...")
728 finally:
729 finally:
729 self.cleanup_kernels()
730 self.cleanup_kernels()
730
731
731
732
732 #-----------------------------------------------------------------------------
733 #-----------------------------------------------------------------------------
733 # Main entry point
734 # Main entry point
734 #-----------------------------------------------------------------------------
735 #-----------------------------------------------------------------------------
735
736
736 def launch_new_instance():
737 def launch_new_instance():
737 app = NotebookApp.instance()
738 app = NotebookApp.instance()
738 app.initialize()
739 app.initialize()
739 app.start()
740 app.start()
740
741
@@ -1,973 +1,976 b''
1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
3 audio:not([controls]){display:none;}
3 audio:not([controls]){display:none;}
4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
6 a:hover,a:active{outline:0;}
6 a:hover,a:active{outline:0;}
7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
8 sup{top:-0.5em;}
8 sup{top:-0.5em;}
9 sub{bottom:-0.25em;}
9 sub{bottom:-0.25em;}
10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}
10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}
11 #map_canvas img,.google-maps img{max-width:none;}
11 #map_canvas img,.google-maps img{max-width:none;}
12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
13 button,input{*overflow:visible;line-height:normal;}
13 button,input{*overflow:visible;line-height:normal;}
14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}
15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;}
16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;}
16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;}
17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}
17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}
18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
19 textarea{overflow:auto;vertical-align:top;}
19 textarea{overflow:auto;vertical-align:top;}
20 @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important;} a,a:visited{text-decoration:underline;} a[href]:after{content:" (" attr(href) ")";} abbr[title]:after{content:" (" attr(title) ")";} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:"";} pre,blockquote{border:1px solid #999;page-break-inside:avoid;} thead{display:table-header-group;} tr,img{page-break-inside:avoid;} img{max-width:100% !important;} @page {margin:0.5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;}}.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
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:0.5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;}}.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
21 .clearfix:after{clear:both;}
21 .clearfix:after{clear:both;}
22 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
22 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
23 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
23 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
24 body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000000;background-color:#ffffff;}
24 body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000000;background-color:#ffffff;}
25 a{color:#0088cc;text-decoration:none;}
25 a{color:#0088cc;text-decoration:none;}
26 a:hover{color:#005580;text-decoration:underline;}
26 a:hover{color:#005580;text-decoration:underline;}
27 .img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
27 .img-rounded{-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);}
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);}
29 .img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;}
29 .img-circle{-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;}
30 .row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;}
31 .row:after{clear:both;}
31 .row:after{clear:both;}
32 [class*="span"]{float:left;min-height:1px;margin-left:20px;}
32 [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;}
33 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
34 .span12{width:940px;}
34 .span12{width:940px;}
35 .span11{width:860px;}
35 .span11{width:860px;}
36 .span10{width:780px;}
36 .span10{width:780px;}
37 .span9{width:700px;}
37 .span9{width:700px;}
38 .span8{width:620px;}
38 .span8{width:620px;}
39 .span7{width:540px;}
39 .span7{width:540px;}
40 .span6{width:460px;}
40 .span6{width:460px;}
41 .span5{width:380px;}
41 .span5{width:380px;}
42 .span4{width:300px;}
42 .span4{width:300px;}
43 .span3{width:220px;}
43 .span3{width:220px;}
44 .span2{width:140px;}
44 .span2{width:140px;}
45 .span1{width:60px;}
45 .span1{width:60px;}
46 .offset12{margin-left:980px;}
46 .offset12{margin-left:980px;}
47 .offset11{margin-left:900px;}
47 .offset11{margin-left:900px;}
48 .offset10{margin-left:820px;}
48 .offset10{margin-left:820px;}
49 .offset9{margin-left:740px;}
49 .offset9{margin-left:740px;}
50 .offset8{margin-left:660px;}
50 .offset8{margin-left:660px;}
51 .offset7{margin-left:580px;}
51 .offset7{margin-left:580px;}
52 .offset6{margin-left:500px;}
52 .offset6{margin-left:500px;}
53 .offset5{margin-left:420px;}
53 .offset5{margin-left:420px;}
54 .offset4{margin-left:340px;}
54 .offset4{margin-left:340px;}
55 .offset3{margin-left:260px;}
55 .offset3{margin-left:260px;}
56 .offset2{margin-left:180px;}
56 .offset2{margin-left:180px;}
57 .offset1{margin-left:100px;}
57 .offset1{margin-left:100px;}
58 .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;}
58 .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;}
59 .row-fluid:after{clear:both;}
59 .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%;}
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%;}
61 .row-fluid [class*="span"]:first-child{margin-left:0;}
61 .row-fluid [class*="span"]:first-child{margin-left:0;}
62 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;}
62 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;}
63 .row-fluid .span12{width:100%;*width:99.94680851063829%;}
63 .row-fluid .span12{width:100%;*width:99.94680851063829%;}
64 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;}
64 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;}
65 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;}
65 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;}
66 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;}
66 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;}
67 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;}
67 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;}
68 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;}
68 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;}
69 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;}
69 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;}
70 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;}
70 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;}
71 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;}
71 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;}
72 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;}
72 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;}
73 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;}
73 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;}
74 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;}
74 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;}
75 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;}
75 .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%;}
76 .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%;}
77 .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%;}
78 .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%;}
79 .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%;}
80 .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%;}
81 .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%;}
82 .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%;}
83 .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%;}
84 .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%;}
85 .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%;}
86 .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%;}
87 .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%;}
88 .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%;}
89 .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%;}
90 .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%;}
91 .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%;}
92 .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%;}
93 .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%;}
94 .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%;}
95 .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%;}
96 .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%;}
97 .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%;}
98 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;}
99 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none;}
99 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none;}
100 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;}
100 [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;}
101 .container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;}
102 .container:after{clear:both;}
102 .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;}
103 .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;}
104 .container-fluid:after{clear:both;}
105 p{margin:0 0 10px;}
105 p{margin:0 0 10px;}
106 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px;}
106 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px;}
107 small{font-size:85%;}
107 small{font-size:85%;}
108 strong{font-weight:bold;}
108 strong{font-weight:bold;}
109 em{font-style:italic;}
109 em{font-style:italic;}
110 cite{font-style:normal;}
110 cite{font-style:normal;}
111 .muted{color:#999999;}
111 .muted{color:#999999;}
112 a.muted:hover{color:#808080;}
112 a.muted:hover{color:#808080;}
113 .text-warning{color:#c09853;}
113 .text-warning{color:#c09853;}
114 a.text-warning:hover{color:#a47e3c;}
114 a.text-warning:hover{color:#a47e3c;}
115 .text-error{color:#b94a48;}
115 .text-error{color:#b94a48;}
116 a.text-error:hover{color:#953b39;}
116 a.text-error:hover{color:#953b39;}
117 .text-info{color:#3a87ad;}
117 .text-info{color:#3a87ad;}
118 a.text-info:hover{color:#2d6987;}
118 a.text-info:hover{color:#2d6987;}
119 .text-success{color:#468847;}
119 .text-success{color:#468847;}
120 a.text-success:hover{color:#356635;}
120 a.text-success:hover{color:#356635;}
121 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:#999999;}
121 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:#999999;}
122 h1,h2,h3{line-height:40px;}
122 h1,h2,h3{line-height:40px;}
123 h1{font-size:35.75px;}
123 h1{font-size:35.75px;}
124 h2{font-size:29.25px;}
124 h2{font-size:29.25px;}
125 h3{font-size:22.75px;}
125 h3{font-size:22.75px;}
126 h4{font-size:16.25px;}
126 h4{font-size:16.25px;}
127 h5{font-size:13px;}
127 h5{font-size:13px;}
128 h6{font-size:11.049999999999999px;}
128 h6{font-size:11.049999999999999px;}
129 h1 small{font-size:22.75px;}
129 h1 small{font-size:22.75px;}
130 h2 small{font-size:16.25px;}
130 h2 small{font-size:16.25px;}
131 h3 small{font-size:13px;}
131 h3 small{font-size:13px;}
132 h4 small{font-size:13px;}
132 h4 small{font-size:13px;}
133 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;}
133 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;}
134 ul,ol{padding:0;margin:0 0 10px 25px;}
134 ul,ol{padding:0;margin:0 0 10px 25px;}
135 ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
135 ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
136 li{line-height:20px;}
136 li{line-height:20px;}
137 ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
137 ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
138 ul.inline,ol.inline{margin-left:0;list-style:none;}ul.inline>li,ol.inline>li{display:inline-block;padding-left:5px;padding-right:5px;}
138 ul.inline,ol.inline{margin-left:0;list-style:none;}ul.inline>li,ol.inline>li{display:inline-block;padding-left:5px;padding-right:5px;}
139 dl{margin-bottom:20px;}
139 dl{margin-bottom:20px;}
140 dt,dd{line-height:20px;}
140 dt,dd{line-height:20px;}
141 dt{font-weight:bold;}
141 dt{font-weight:bold;}
142 dd{margin-left:10px;}
142 dd{margin-left:10px;}
143 .dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;}
143 .dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;}
144 .dl-horizontal:after{clear:both;}
144 .dl-horizontal:after{clear:both;}
145 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
145 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
146 .dl-horizontal dd{margin-left:180px;}
146 .dl-horizontal dd{margin-left:180px;}
147 hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
147 hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
148 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;}
148 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;}
149 abbr.initialism{font-size:90%;text-transform:uppercase;}
149 abbr.initialism{font-size:90%;text-transform:uppercase;}
150 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px;}
150 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px;}
151 blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
151 blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
152 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
152 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
153 blockquote.pull-right small:before{content:'';}
153 blockquote.pull-right small:before{content:'';}
154 blockquote.pull-right small:after{content:'\00A0 \2014';}
154 blockquote.pull-right small:after{content:'\00A0 \2014';}
155 q:before,q:after,blockquote:before,blockquote:after{content:"";}
155 q:before,q:after,blockquote:before,blockquote:after{content:"";}
156 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;}
156 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;}
157 form{margin:0 0 20px;}
157 form{margin:0 0 20px;}
158 fieldset{padding:0;margin:0;border:0;}
158 fieldset{padding:0;margin:0;border:0;}
159 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;}
159 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;}
160 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px;}
160 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px;}
161 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
161 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
162 label{display:block;margin-bottom:5px;}
162 label{display:block;margin-bottom:5px;}
163 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:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;}
163 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:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;}
164 input,textarea,.uneditable-input{width:206px;}
164 input,textarea,.uneditable-input{width:206px;}
165 textarea{height:auto;}
165 textarea{height:auto;}
166 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:#ffffff;border:1px solid #cccccc;-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);}
166 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:#ffffff;border:1px solid #cccccc;-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);}
167 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;}
167 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;}
168 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;}
168 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;}
169 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;}
169 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;}
170 select{width:220px;border:1px solid #cccccc;background-color:#ffffff;}
170 select{width:220px;border:1px solid #cccccc;background-color:#ffffff;}
171 select[multiple],select[size]{height:auto;}
171 select[multiple],select[size]{height:auto;}
172 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;}
172 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;}
173 .uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-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;}
173 .uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-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;}
174 .uneditable-input{overflow:hidden;white-space:nowrap;}
174 .uneditable-input{overflow:hidden;white-space:nowrap;}
175 .uneditable-textarea{width:auto;height:auto;}
175 .uneditable-textarea{width:auto;height:auto;}
176 input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;}
176 input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;}
177 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;}
177 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;}
178 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;}
178 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;}
179 .radio,.checkbox{min-height:20px;padding-left:20px;}
179 .radio,.checkbox{min-height:20px;padding-left:20px;}
180 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;}
180 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;}
181 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
181 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
182 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
182 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
183 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
183 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
184 .input-mini{width:60px;}
184 .input-mini{width:60px;}
185 .input-small{width:90px;}
185 .input-small{width:90px;}
186 .input-medium{width:150px;}
186 .input-medium{width:150px;}
187 .input-large{width:210px;}
187 .input-large{width:210px;}
188 .input-xlarge{width:270px;}
188 .input-xlarge{width:270px;}
189 .input-xxlarge{width:530px;}
189 .input-xxlarge{width:530px;}
190 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;}
190 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;}
191 .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;}
191 .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;}
192 input,textarea,.uneditable-input{margin-left:0;}
192 input,textarea,.uneditable-input{margin-left:0;}
193 .controls-row [class*="span"]+[class*="span"]{margin-left:20px;}
193 .controls-row [class*="span"]+[class*="span"]{margin-left:20px;}
194 input.span12, textarea.span12, .uneditable-input.span12{width:926px;}
194 input.span12, textarea.span12, .uneditable-input.span12{width:926px;}
195 input.span11, textarea.span11, .uneditable-input.span11{width:846px;}
195 input.span11, textarea.span11, .uneditable-input.span11{width:846px;}
196 input.span10, textarea.span10, .uneditable-input.span10{width:766px;}
196 input.span10, textarea.span10, .uneditable-input.span10{width:766px;}
197 input.span9, textarea.span9, .uneditable-input.span9{width:686px;}
197 input.span9, textarea.span9, .uneditable-input.span9{width:686px;}
198 input.span8, textarea.span8, .uneditable-input.span8{width:606px;}
198 input.span8, textarea.span8, .uneditable-input.span8{width:606px;}
199 input.span7, textarea.span7, .uneditable-input.span7{width:526px;}
199 input.span7, textarea.span7, .uneditable-input.span7{width:526px;}
200 input.span6, textarea.span6, .uneditable-input.span6{width:446px;}
200 input.span6, textarea.span6, .uneditable-input.span6{width:446px;}
201 input.span5, textarea.span5, .uneditable-input.span5{width:366px;}
201 input.span5, textarea.span5, .uneditable-input.span5{width:366px;}
202 input.span4, textarea.span4, .uneditable-input.span4{width:286px;}
202 input.span4, textarea.span4, .uneditable-input.span4{width:286px;}
203 input.span3, textarea.span3, .uneditable-input.span3{width:206px;}
203 input.span3, textarea.span3, .uneditable-input.span3{width:206px;}
204 input.span2, textarea.span2, .uneditable-input.span2{width:126px;}
204 input.span2, textarea.span2, .uneditable-input.span2{width:126px;}
205 input.span1, textarea.span1, .uneditable-input.span1{width:46px;}
205 input.span1, textarea.span1, .uneditable-input.span1{width:46px;}
206 .controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;}
206 .controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;}
207 .controls-row:after{clear:both;}
207 .controls-row:after{clear:both;}
208 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;}
208 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;}
209 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;}
209 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;}
210 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;}
210 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;}
211 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;}
211 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;}
212 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
212 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
213 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;}
213 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;}
214 .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;}
214 .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;}
215 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
215 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
216 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
216 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
217 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;}
217 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;}
218 .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;}
218 .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;}
219 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
219 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
220 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
220 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
221 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;}
221 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;}
222 .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;}
222 .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;}
223 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
223 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
224 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;}
224 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;}
225 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;}
225 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;}
226 .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;}
226 .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;}
227 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;}
227 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;}
228 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;}
228 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;}
229 .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;}
229 .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;}
230 .form-actions:after{clear:both;}
230 .form-actions:after{clear:both;}
231 .help-block,.help-inline{color:#262626;}
231 .help-block,.help-inline{color:#262626;}
232 .help-block{display:block;margin-bottom:10px;}
232 .help-block{display:block;margin-bottom:10px;}
233 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
233 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}
234 .input-append,.input-prepend{margin-bottom:5px;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{font-size:13px;}
234 .input-append,.input-prepend{margin-bottom:5px;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{font-size:13px;}
235 .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;-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;}
235 .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;-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;}
236 .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 #ffffff;background-color:#eeeeee;border:1px solid #ccc;}
236 .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 #ffffff;background-color:#eeeeee;border:1px solid #ccc;}
237 .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;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
237 .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;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
238 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;}
238 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;}
239 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
239 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}
240 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
240 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
241 .input-append input,.input-append select,.input-append .uneditable-input{-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{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
241 .input-append input,.input-append select,.input-append .uneditable-input{-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{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
242 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;}
242 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;}
243 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
243 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
244 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-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{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
244 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-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{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
245 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
245 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
246 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
246 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
247 .input-prepend.input-append .btn-group:first-child{margin-left:0;}
247 .input-prepend.input-append .btn-group:first-child{margin-left:0;}
248 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
248 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
249 .form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
249 .form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
250 .form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
250 .form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
251 .form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
251 .form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
252 .form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
252 .form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}
253 .form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
253 .form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}
254 .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;}
254 .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;}
255 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
255 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
256 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;}
256 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;}
257 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
257 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}
258 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
258 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}
259 .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;}
259 .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;}
260 .control-group{margin-bottom:10px;}
260 .control-group{margin-bottom:10px;}
261 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;}
261 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;}
262 .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;}
262 .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;}
263 .form-horizontal .control-group:after{clear:both;}
263 .form-horizontal .control-group:after{clear:both;}
264 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;}
264 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;}
265 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;}
265 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;}
266 .form-horizontal .help-block{margin-bottom:0;}
266 .form-horizontal .help-block{margin-bottom:0;}
267 .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;}
267 .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;}
268 .form-horizontal .form-actions{padding-left:180px;}
268 .form-horizontal .form-actions{padding-left:180px;}
269 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}
269 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}
270 .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 #dddddd;}
270 .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 #dddddd;}
271 .table th{font-weight:bold;}
271 .table th{font-weight:bold;}
272 .table thead th{vertical-align:bottom;}
272 .table thead th{vertical-align:bottom;}
273 .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;}
273 .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;}
274 .table tbody+tbody{border-top:2px solid #dddddd;}
274 .table tbody+tbody{border-top:2px solid #dddddd;}
275 .table .table{background-color:#ffffff;}
275 .table .table{background-color:#ffffff;}
276 .table-condensed th,.table-condensed td{padding:4px 5px;}
276 .table-condensed th,.table-condensed td{padding:4px 5px;}
277 .table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
277 .table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}
278 .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;}
278 .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;}
279 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;}
279 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;}
280 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;}
280 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;}
281 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
281 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
282 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
282 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
283 .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;}
283 .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;}
284 .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;}
284 .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;}
285 .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;}
285 .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;}
286 .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;}
286 .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;}
287 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9;}
287 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9;}
288 .table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5;}
288 .table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5;}
289 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;}
289 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;}
290 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0;}
290 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0;}
291 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0;}
291 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0;}
292 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0;}
292 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0;}
293 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0;}
293 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0;}
294 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0;}
294 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0;}
295 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0;}
295 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0;}
296 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0;}
296 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0;}
297 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0;}
297 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0;}
298 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0;}
298 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0;}
299 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0;}
299 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0;}
300 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0;}
300 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0;}
301 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0;}
301 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0;}
302 .table tbody tr.success td{background-color:#dff0d8;}
302 .table tbody tr.success td{background-color:#dff0d8;}
303 .table tbody tr.error td{background-color:#f2dede;}
303 .table tbody tr.error td{background-color:#f2dede;}
304 .table tbody tr.warning td{background-color:#fcf8e3;}
304 .table tbody tr.warning td{background-color:#fcf8e3;}
305 .table tbody tr.info td{background-color:#d9edf7;}
305 .table tbody tr.info td{background-color:#d9edf7;}
306 .table-hover tbody tr.success:hover td{background-color:#d0e9c6;}
306 .table-hover tbody tr.success:hover td{background-color:#d0e9c6;}
307 .table-hover tbody tr.error:hover td{background-color:#ebcccc;}
307 .table-hover tbody tr.error:hover td{background-color:#ebcccc;}
308 .table-hover tbody tr.warning:hover td{background-color:#faf2cc;}
308 .table-hover tbody tr.warning:hover td{background-color:#faf2cc;}
309 .table-hover tbody tr.info:hover td{background-color:#c4e3f3;}
309 .table-hover tbody tr.info:hover td{background-color:#c4e3f3;}
310 [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;}
310 [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;}
311 .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:url("../img/glyphicons-halflings-white.png");}
311 .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:url("../img/glyphicons-halflings-white.png");}
312 .icon-glass{background-position:0 0;}
312 .icon-glass{background-position:0 0;}
313 .icon-music{background-position:-24px 0;}
313 .icon-music{background-position:-24px 0;}
314 .icon-search{background-position:-48px 0;}
314 .icon-search{background-position:-48px 0;}
315 .icon-envelope{background-position:-72px 0;}
315 .icon-envelope{background-position:-72px 0;}
316 .icon-heart{background-position:-96px 0;}
316 .icon-heart{background-position:-96px 0;}
317 .icon-star{background-position:-120px 0;}
317 .icon-star{background-position:-120px 0;}
318 .icon-star-empty{background-position:-144px 0;}
318 .icon-star-empty{background-position:-144px 0;}
319 .icon-user{background-position:-168px 0;}
319 .icon-user{background-position:-168px 0;}
320 .icon-film{background-position:-192px 0;}
320 .icon-film{background-position:-192px 0;}
321 .icon-th-large{background-position:-216px 0;}
321 .icon-th-large{background-position:-216px 0;}
322 .icon-th{background-position:-240px 0;}
322 .icon-th{background-position:-240px 0;}
323 .icon-th-list{background-position:-264px 0;}
323 .icon-th-list{background-position:-264px 0;}
324 .icon-ok{background-position:-288px 0;}
324 .icon-ok{background-position:-288px 0;}
325 .icon-remove{background-position:-312px 0;}
325 .icon-remove{background-position:-312px 0;}
326 .icon-zoom-in{background-position:-336px 0;}
326 .icon-zoom-in{background-position:-336px 0;}
327 .icon-zoom-out{background-position:-360px 0;}
327 .icon-zoom-out{background-position:-360px 0;}
328 .icon-off{background-position:-384px 0;}
328 .icon-off{background-position:-384px 0;}
329 .icon-signal{background-position:-408px 0;}
329 .icon-signal{background-position:-408px 0;}
330 .icon-cog{background-position:-432px 0;}
330 .icon-cog{background-position:-432px 0;}
331 .icon-trash{background-position:-456px 0;}
331 .icon-trash{background-position:-456px 0;}
332 .icon-home{background-position:0 -24px;}
332 .icon-home{background-position:0 -24px;}
333 .icon-file{background-position:-24px -24px;}
333 .icon-file{background-position:-24px -24px;}
334 .icon-time{background-position:-48px -24px;}
334 .icon-time{background-position:-48px -24px;}
335 .icon-road{background-position:-72px -24px;}
335 .icon-road{background-position:-72px -24px;}
336 .icon-download-alt{background-position:-96px -24px;}
336 .icon-download-alt{background-position:-96px -24px;}
337 .icon-download{background-position:-120px -24px;}
337 .icon-download{background-position:-120px -24px;}
338 .icon-upload{background-position:-144px -24px;}
338 .icon-upload{background-position:-144px -24px;}
339 .icon-inbox{background-position:-168px -24px;}
339 .icon-inbox{background-position:-168px -24px;}
340 .icon-play-circle{background-position:-192px -24px;}
340 .icon-play-circle{background-position:-192px -24px;}
341 .icon-repeat{background-position:-216px -24px;}
341 .icon-repeat{background-position:-216px -24px;}
342 .icon-refresh{background-position:-240px -24px;}
342 .icon-refresh{background-position:-240px -24px;}
343 .icon-list-alt{background-position:-264px -24px;}
343 .icon-list-alt{background-position:-264px -24px;}
344 .icon-lock{background-position:-287px -24px;}
344 .icon-lock{background-position:-287px -24px;}
345 .icon-flag{background-position:-312px -24px;}
345 .icon-flag{background-position:-312px -24px;}
346 .icon-headphones{background-position:-336px -24px;}
346 .icon-headphones{background-position:-336px -24px;}
347 .icon-volume-off{background-position:-360px -24px;}
347 .icon-volume-off{background-position:-360px -24px;}
348 .icon-volume-down{background-position:-384px -24px;}
348 .icon-volume-down{background-position:-384px -24px;}
349 .icon-volume-up{background-position:-408px -24px;}
349 .icon-volume-up{background-position:-408px -24px;}
350 .icon-qrcode{background-position:-432px -24px;}
350 .icon-qrcode{background-position:-432px -24px;}
351 .icon-barcode{background-position:-456px -24px;}
351 .icon-barcode{background-position:-456px -24px;}
352 .icon-tag{background-position:0 -48px;}
352 .icon-tag{background-position:0 -48px;}
353 .icon-tags{background-position:-25px -48px;}
353 .icon-tags{background-position:-25px -48px;}
354 .icon-book{background-position:-48px -48px;}
354 .icon-book{background-position:-48px -48px;}
355 .icon-bookmark{background-position:-72px -48px;}
355 .icon-bookmark{background-position:-72px -48px;}
356 .icon-print{background-position:-96px -48px;}
356 .icon-print{background-position:-96px -48px;}
357 .icon-camera{background-position:-120px -48px;}
357 .icon-camera{background-position:-120px -48px;}
358 .icon-font{background-position:-144px -48px;}
358 .icon-font{background-position:-144px -48px;}
359 .icon-bold{background-position:-167px -48px;}
359 .icon-bold{background-position:-167px -48px;}
360 .icon-italic{background-position:-192px -48px;}
360 .icon-italic{background-position:-192px -48px;}
361 .icon-text-height{background-position:-216px -48px;}
361 .icon-text-height{background-position:-216px -48px;}
362 .icon-text-width{background-position:-240px -48px;}
362 .icon-text-width{background-position:-240px -48px;}
363 .icon-align-left{background-position:-264px -48px;}
363 .icon-align-left{background-position:-264px -48px;}
364 .icon-align-center{background-position:-288px -48px;}
364 .icon-align-center{background-position:-288px -48px;}
365 .icon-align-right{background-position:-312px -48px;}
365 .icon-align-right{background-position:-312px -48px;}
366 .icon-align-justify{background-position:-336px -48px;}
366 .icon-align-justify{background-position:-336px -48px;}
367 .icon-list{background-position:-360px -48px;}
367 .icon-list{background-position:-360px -48px;}
368 .icon-indent-left{background-position:-384px -48px;}
368 .icon-indent-left{background-position:-384px -48px;}
369 .icon-indent-right{background-position:-408px -48px;}
369 .icon-indent-right{background-position:-408px -48px;}
370 .icon-facetime-video{background-position:-432px -48px;}
370 .icon-facetime-video{background-position:-432px -48px;}
371 .icon-picture{background-position:-456px -48px;}
371 .icon-picture{background-position:-456px -48px;}
372 .icon-pencil{background-position:0 -72px;}
372 .icon-pencil{background-position:0 -72px;}
373 .icon-map-marker{background-position:-24px -72px;}
373 .icon-map-marker{background-position:-24px -72px;}
374 .icon-adjust{background-position:-48px -72px;}
374 .icon-adjust{background-position:-48px -72px;}
375 .icon-tint{background-position:-72px -72px;}
375 .icon-tint{background-position:-72px -72px;}
376 .icon-edit{background-position:-96px -72px;}
376 .icon-edit{background-position:-96px -72px;}
377 .icon-share{background-position:-120px -72px;}
377 .icon-share{background-position:-120px -72px;}
378 .icon-check{background-position:-144px -72px;}
378 .icon-check{background-position:-144px -72px;}
379 .icon-move{background-position:-168px -72px;}
379 .icon-move{background-position:-168px -72px;}
380 .icon-step-backward{background-position:-192px -72px;}
380 .icon-step-backward{background-position:-192px -72px;}
381 .icon-fast-backward{background-position:-216px -72px;}
381 .icon-fast-backward{background-position:-216px -72px;}
382 .icon-backward{background-position:-240px -72px;}
382 .icon-backward{background-position:-240px -72px;}
383 .icon-play{background-position:-264px -72px;}
383 .icon-play{background-position:-264px -72px;}
384 .icon-pause{background-position:-288px -72px;}
384 .icon-pause{background-position:-288px -72px;}
385 .icon-stop{background-position:-312px -72px;}
385 .icon-stop{background-position:-312px -72px;}
386 .icon-forward{background-position:-336px -72px;}
386 .icon-forward{background-position:-336px -72px;}
387 .icon-fast-forward{background-position:-360px -72px;}
387 .icon-fast-forward{background-position:-360px -72px;}
388 .icon-step-forward{background-position:-384px -72px;}
388 .icon-step-forward{background-position:-384px -72px;}
389 .icon-eject{background-position:-408px -72px;}
389 .icon-eject{background-position:-408px -72px;}
390 .icon-chevron-left{background-position:-432px -72px;}
390 .icon-chevron-left{background-position:-432px -72px;}
391 .icon-chevron-right{background-position:-456px -72px;}
391 .icon-chevron-right{background-position:-456px -72px;}
392 .icon-plus-sign{background-position:0 -96px;}
392 .icon-plus-sign{background-position:0 -96px;}
393 .icon-minus-sign{background-position:-24px -96px;}
393 .icon-minus-sign{background-position:-24px -96px;}
394 .icon-remove-sign{background-position:-48px -96px;}
394 .icon-remove-sign{background-position:-48px -96px;}
395 .icon-ok-sign{background-position:-72px -96px;}
395 .icon-ok-sign{background-position:-72px -96px;}
396 .icon-question-sign{background-position:-96px -96px;}
396 .icon-question-sign{background-position:-96px -96px;}
397 .icon-info-sign{background-position:-120px -96px;}
397 .icon-info-sign{background-position:-120px -96px;}
398 .icon-screenshot{background-position:-144px -96px;}
398 .icon-screenshot{background-position:-144px -96px;}
399 .icon-remove-circle{background-position:-168px -96px;}
399 .icon-remove-circle{background-position:-168px -96px;}
400 .icon-ok-circle{background-position:-192px -96px;}
400 .icon-ok-circle{background-position:-192px -96px;}
401 .icon-ban-circle{background-position:-216px -96px;}
401 .icon-ban-circle{background-position:-216px -96px;}
402 .icon-arrow-left{background-position:-240px -96px;}
402 .icon-arrow-left{background-position:-240px -96px;}
403 .icon-arrow-right{background-position:-264px -96px;}
403 .icon-arrow-right{background-position:-264px -96px;}
404 .icon-arrow-up{background-position:-289px -96px;}
404 .icon-arrow-up{background-position:-289px -96px;}
405 .icon-arrow-down{background-position:-312px -96px;}
405 .icon-arrow-down{background-position:-312px -96px;}
406 .icon-share-alt{background-position:-336px -96px;}
406 .icon-share-alt{background-position:-336px -96px;}
407 .icon-resize-full{background-position:-360px -96px;}
407 .icon-resize-full{background-position:-360px -96px;}
408 .icon-resize-small{background-position:-384px -96px;}
408 .icon-resize-small{background-position:-384px -96px;}
409 .icon-plus{background-position:-408px -96px;}
409 .icon-plus{background-position:-408px -96px;}
410 .icon-minus{background-position:-433px -96px;}
410 .icon-minus{background-position:-433px -96px;}
411 .icon-asterisk{background-position:-456px -96px;}
411 .icon-asterisk{background-position:-456px -96px;}
412 .icon-exclamation-sign{background-position:0 -120px;}
412 .icon-exclamation-sign{background-position:0 -120px;}
413 .icon-gift{background-position:-24px -120px;}
413 .icon-gift{background-position:-24px -120px;}
414 .icon-leaf{background-position:-48px -120px;}
414 .icon-leaf{background-position:-48px -120px;}
415 .icon-fire{background-position:-72px -120px;}
415 .icon-fire{background-position:-72px -120px;}
416 .icon-eye-open{background-position:-96px -120px;}
416 .icon-eye-open{background-position:-96px -120px;}
417 .icon-eye-close{background-position:-120px -120px;}
417 .icon-eye-close{background-position:-120px -120px;}
418 .icon-warning-sign{background-position:-144px -120px;}
418 .icon-warning-sign{background-position:-144px -120px;}
419 .icon-plane{background-position:-168px -120px;}
419 .icon-plane{background-position:-168px -120px;}
420 .icon-calendar{background-position:-192px -120px;}
420 .icon-calendar{background-position:-192px -120px;}
421 .icon-random{background-position:-216px -120px;width:16px;}
421 .icon-random{background-position:-216px -120px;width:16px;}
422 .icon-comment{background-position:-240px -120px;}
422 .icon-comment{background-position:-240px -120px;}
423 .icon-magnet{background-position:-264px -120px;}
423 .icon-magnet{background-position:-264px -120px;}
424 .icon-chevron-up{background-position:-288px -120px;}
424 .icon-chevron-up{background-position:-288px -120px;}
425 .icon-chevron-down{background-position:-313px -119px;}
425 .icon-chevron-down{background-position:-313px -119px;}
426 .icon-retweet{background-position:-336px -120px;}
426 .icon-retweet{background-position:-336px -120px;}
427 .icon-shopping-cart{background-position:-360px -120px;}
427 .icon-shopping-cart{background-position:-360px -120px;}
428 .icon-folder-close{background-position:-384px -120px;}
428 .icon-folder-close{background-position:-384px -120px;}
429 .icon-folder-open{background-position:-408px -120px;width:16px;}
429 .icon-folder-open{background-position:-408px -120px;width:16px;}
430 .icon-resize-vertical{background-position:-432px -119px;}
430 .icon-resize-vertical{background-position:-432px -119px;}
431 .icon-resize-horizontal{background-position:-456px -118px;}
431 .icon-resize-horizontal{background-position:-456px -118px;}
432 .icon-hdd{background-position:0 -144px;}
432 .icon-hdd{background-position:0 -144px;}
433 .icon-bullhorn{background-position:-24px -144px;}
433 .icon-bullhorn{background-position:-24px -144px;}
434 .icon-bell{background-position:-48px -144px;}
434 .icon-bell{background-position:-48px -144px;}
435 .icon-certificate{background-position:-72px -144px;}
435 .icon-certificate{background-position:-72px -144px;}
436 .icon-thumbs-up{background-position:-96px -144px;}
436 .icon-thumbs-up{background-position:-96px -144px;}
437 .icon-thumbs-down{background-position:-120px -144px;}
437 .icon-thumbs-down{background-position:-120px -144px;}
438 .icon-hand-right{background-position:-144px -144px;}
438 .icon-hand-right{background-position:-144px -144px;}
439 .icon-hand-left{background-position:-168px -144px;}
439 .icon-hand-left{background-position:-168px -144px;}
440 .icon-hand-up{background-position:-192px -144px;}
440 .icon-hand-up{background-position:-192px -144px;}
441 .icon-hand-down{background-position:-216px -144px;}
441 .icon-hand-down{background-position:-216px -144px;}
442 .icon-circle-arrow-right{background-position:-240px -144px;}
442 .icon-circle-arrow-right{background-position:-240px -144px;}
443 .icon-circle-arrow-left{background-position:-264px -144px;}
443 .icon-circle-arrow-left{background-position:-264px -144px;}
444 .icon-circle-arrow-up{background-position:-288px -144px;}
444 .icon-circle-arrow-up{background-position:-288px -144px;}
445 .icon-circle-arrow-down{background-position:-312px -144px;}
445 .icon-circle-arrow-down{background-position:-312px -144px;}
446 .icon-globe{background-position:-336px -144px;}
446 .icon-globe{background-position:-336px -144px;}
447 .icon-wrench{background-position:-360px -144px;}
447 .icon-wrench{background-position:-360px -144px;}
448 .icon-tasks{background-position:-384px -144px;}
448 .icon-tasks{background-position:-384px -144px;}
449 .icon-filter{background-position:-408px -144px;}
449 .icon-filter{background-position:-408px -144px;}
450 .icon-briefcase{background-position:-432px -144px;}
450 .icon-briefcase{background-position:-432px -144px;}
451 .icon-fullscreen{background-position:-456px -144px;}
451 .icon-fullscreen{background-position:-456px -144px;}
452 .dropup,.dropdown{position:relative;}
452 .dropup,.dropdown{position:relative;}
453 .dropdown-toggle{*margin-bottom:-3px;}
453 .dropdown-toggle{*margin-bottom:-3px;}
454 .dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
454 .dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
455 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";}
455 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";}
456 .dropdown .caret{margin-top:8px;margin-left:2px;}
456 .dropdown .caret{margin-top:8px;margin-left:2px;}
457 .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:#ffffff;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;}
457 .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:#ffffff;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;}
458 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
458 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
459 .dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;}
459 .dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;}
460 .dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
460 .dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
461 .dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
461 .dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}
462 .dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999999;}
462 .dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999999;}
463 .dropdown-menu .disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default;}
463 .dropdown-menu .disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default;}
464 .open{*z-index:1000;}.open>.dropdown-menu{display:block;}
464 .open{*z-index:1000;}.open>.dropdown-menu{display:block;}
465 .pull-right>.dropdown-menu{right:0;left:auto;}
465 .pull-right>.dropdown-menu{right:0;left:auto;}
466 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";}
466 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";}
467 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;}
467 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;}
468 .dropdown-submenu{position:relative;}
468 .dropdown-submenu{position:relative;}
469 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
469 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
470 .dropdown-submenu:hover>.dropdown-menu{display:block;}
470 .dropdown-submenu:hover>.dropdown-menu{display:block;}
471 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;}
471 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;}
472 .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:#cccccc;margin-top:5px;margin-right:-10px;}
472 .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:#cccccc;margin-top:5px;margin-right:-10px;}
473 .dropdown-submenu:hover>a:after{border-left-color:#ffffff;}
473 .dropdown-submenu:hover>a:after{border-left-color:#ffffff;}
474 .dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
474 .dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
475 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;}
475 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;}
476 .typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
476 .typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
477 .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);}
477 .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);}
478 .well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
478 .well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
479 .well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
479 .well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
480 .fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;}
480 .fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;}
481 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;}
481 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;}
482 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);}
482 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);}
483 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;}
483 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;}
484 .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:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #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 #bbbbbb;*border:0;border-bottom-color:#a2a2a2;-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:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;}
484 .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:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #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 #bbbbbb;*border:0;border-bottom-color:#a2a2a2;-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:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;}
485 .btn:active,.btn.active{background-color:#cccccc \9;}
485 .btn:active,.btn.active{background-color:#cccccc \9;}
486 .btn:first-child{*margin-left:0;}
486 .btn:first-child{*margin-left:0;}
487 .btn:hover{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
487 .btn:hover{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
488 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
488 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
489 .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);}
489 .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);}
490 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
490 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
491 .btn-large{padding:11px 19px;font-size:16.25px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
491 .btn-large{padding:11px 19px;font-size:16.25px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
492 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;}
492 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;}
493 .btn-small{padding:2px 10px;font-size:11.049999999999999px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
493 .btn-small{padding:2px 10px;font-size:11.049999999999999px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
494 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;}
494 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;}
495 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;}
495 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;}
496 .btn-mini{padding:0 6px;font-size:9.75px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
496 .btn-mini{padding:0 6px;font-size:9.75px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
497 .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;}
497 .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;}
498 .btn-block+.btn-block{margin-top:5px;}
498 .btn-block+.btn-block{margin-top:5px;}
499 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;}
499 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;}
500 .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);}
500 .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);}
501 .btn{border-color:#c5c5c5;border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);}
501 .btn{border-color:#c5c5c5;border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);}
502 .btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;}
502 .btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;}
503 .btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
503 .btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
504 .btn-warning{color:#ffffff;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:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;}
504 .btn-warning{color:#ffffff;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:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;}
505 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
505 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
506 .btn-danger{color:#ffffff;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:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;}
506 .btn-danger{color:#ffffff;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:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;}
507 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
507 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
508 .btn-success{color:#ffffff;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:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;}
508 .btn-success{color:#ffffff;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:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;}
509 .btn-success:active,.btn-success.active{background-color:#408140 \9;}
509 .btn-success:active,.btn-success.active{background-color:#408140 \9;}
510 .btn-info{color:#ffffff;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:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;}
510 .btn-info{color:#ffffff;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:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;}
511 .btn-info:active,.btn-info.active{background-color:#24748c \9;}
511 .btn-info:active,.btn-info.active{background-color:#24748c \9;}
512 .btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;}
512 .btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;}
513 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
513 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;}
514 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;}
514 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;}
515 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
515 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}
516 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
516 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}
517 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
517 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}
518 .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;}
518 .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;}
519 .btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
519 .btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
520 .btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent;}
520 .btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent;}
521 .btn-link[disabled]:hover{color:#333333;text-decoration:none;}
521 .btn-link[disabled]:hover{color:#333333;text-decoration:none;}
522 .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;}
522 .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;}
523 .btn-group+.btn-group{margin-left:5px;}
523 .btn-group+.btn-group{margin-left:5px;}
524 .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;}
524 .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;}
525 .btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
525 .btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
526 .btn-group>.btn+.btn{margin-left:-1px;}
526 .btn-group>.btn+.btn{margin-left:-1px;}
527 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px;}
527 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px;}
528 .btn-group>.btn-mini{font-size:9.75px;}
528 .btn-group>.btn-mini{font-size:9.75px;}
529 .btn-group>.btn-small{font-size:11.049999999999999px;}
529 .btn-group>.btn-small{font-size:11.049999999999999px;}
530 .btn-group>.btn-large{font-size:16.25px;}
530 .btn-group>.btn-large{font-size:16.25px;}
531 .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;}
531 .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;}
532 .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;}
532 .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;}
533 .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;}
533 .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;}
534 .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;}
534 .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;}
535 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;}
535 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;}
536 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
536 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
537 .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;}
537 .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;}
538 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;}
538 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;}
539 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;}
539 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;}
540 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;}
540 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;}
541 .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);}
541 .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);}
542 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;}
542 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;}
543 .btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;}
543 .btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;}
544 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;}
544 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;}
545 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;}
545 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;}
546 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;}
546 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;}
547 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;}
547 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;}
548 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;}
548 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;}
549 .btn .caret{margin-top:8px;margin-left:0;}
549 .btn .caret{margin-top:8px;margin-left:0;}
550 .btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px;}
550 .btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px;}
551 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;}
551 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;}
552 .dropup .btn-large .caret{border-bottom-width:5px;}
552 .dropup .btn-large .caret{border-bottom-width:5px;}
553 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
553 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
554 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1;}
554 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1;}
555 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
555 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
556 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;}
556 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;}
557 .btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
557 .btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
558 .btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
558 .btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
559 .btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;}
559 .btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;}
560 .btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
560 .btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
561 .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;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
561 .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;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
562 .alert,.alert h4{color:#c09853;}
562 .alert,.alert h4{color:#c09853;}
563 .alert h4{margin:0;}
563 .alert h4{margin:0;}
564 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px;}
564 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px;}
565 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
565 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}
566 .alert-success h4{color:#468847;}
566 .alert-success h4{color:#468847;}
567 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
567 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}
568 .alert-danger h4,.alert-error h4{color:#b94a48;}
568 .alert-danger h4,.alert-error h4{color:#b94a48;}
569 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
569 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}
570 .alert-info h4{color:#3a87ad;}
570 .alert-info h4{color:#3a87ad;}
571 .alert-block{padding-top:14px;padding-bottom:14px;}
571 .alert-block{padding-top:14px;padding-bottom:14px;}
572 .alert-block>p,.alert-block>ul{margin-bottom:0;}
572 .alert-block>p,.alert-block>ul{margin-bottom:0;}
573 .alert-block p+p{margin-top:5px;}
573 .alert-block p+p{margin-top:5px;}
574 .nav{margin-left:0;margin-bottom:20px;list-style:none;}
574 .nav{margin-left:0;margin-bottom:20px;list-style:none;}
575 .nav>li>a{display:block;}
575 .nav>li>a{display:block;}
576 .nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
576 .nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
577 .nav>li>a>img{max-width:none;}
577 .nav>li>a>img{max-width:none;}
578 .nav>.pull-right{float:right;}
578 .nav>.pull-right{float:right;}
579 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
579 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
580 .nav li+.nav-header{margin-top:9px;}
580 .nav li+.nav-header{margin-top:9px;}
581 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}
581 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}
582 .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);}
582 .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);}
583 .nav-list>li>a{padding:3px 15px;}
583 .nav-list>li>a{padding:3px 15px;}
584 .nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
584 .nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
585 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px;}
585 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px;}
586 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
586 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}
587 .nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;}
587 .nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;}
588 .nav-tabs:after,.nav-pills:after{clear:both;}
588 .nav-tabs:after,.nav-pills:after{clear:both;}
589 .nav-tabs>li,.nav-pills>li{float:left;}
589 .nav-tabs>li,.nav-pills>li{float:left;}
590 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
590 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
591 .nav-tabs{border-bottom:1px solid #ddd;}
591 .nav-tabs{border-bottom:1px solid #ddd;}
592 .nav-tabs>li{margin-bottom:-1px;}
592 .nav-tabs>li{margin-bottom:-1px;}
593 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-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{border-color:#eeeeee #eeeeee #dddddd;}
593 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-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{border-color:#eeeeee #eeeeee #dddddd;}
594 .nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
594 .nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
595 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
595 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
596 .nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;}
596 .nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;}
597 .nav-stacked>li{float:none;}
597 .nav-stacked>li{float:none;}
598 .nav-stacked>li>a{margin-right:0;}
598 .nav-stacked>li>a{margin-right:0;}
599 .nav-tabs.nav-stacked{border-bottom:0;}
599 .nav-tabs.nav-stacked{border-bottom:0;}
600 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
600 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
601 .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;}
601 .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;}
602 .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;}
602 .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;}
603 .nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
603 .nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
604 .nav-pills.nav-stacked>li>a{margin-bottom:3px;}
604 .nav-pills.nav-stacked>li>a{margin-bottom:3px;}
605 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
605 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
606 .nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
606 .nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}
607 .nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
607 .nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}
608 .nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;}
608 .nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;}
609 .nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;}
609 .nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;}
610 .nav-tabs .dropdown-toggle .caret{margin-top:8px;}
610 .nav-tabs .dropdown-toggle .caret{margin-top:8px;}
611 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;}
611 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;}
612 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}
612 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}
613 .nav>.dropdown.active>a:hover{cursor:pointer;}
613 .nav>.dropdown.active>a:hover{cursor:pointer;}
614 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
614 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
615 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
615 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
616 .tabs-stacked .open>a:hover{border-color:#999999;}
616 .tabs-stacked .open>a:hover{border-color:#999999;}
617 .tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;}
617 .tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;}
618 .tabbable:after{clear:both;}
618 .tabbable:after{clear:both;}
619 .tab-content{overflow:auto;}
619 .tab-content{overflow:auto;}
620 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;}
620 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;}
621 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
621 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
622 .tab-content>.active,.pill-content>.active{display:block;}
622 .tab-content>.active,.pill-content>.active{display:block;}
623 .tabs-below>.nav-tabs{border-top:1px solid #ddd;}
623 .tabs-below>.nav-tabs{border-top:1px solid #ddd;}
624 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;}
624 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;}
625 .tabs-below>.nav-tabs>li>a{-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{border-bottom-color:transparent;border-top-color:#ddd;}
625 .tabs-below>.nav-tabs>li>a{-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{border-bottom-color:transparent;border-top-color:#ddd;}
626 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd;}
626 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd;}
627 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;}
627 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;}
628 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
628 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
629 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
629 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
630 .tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
630 .tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
631 .tabs-left>.nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
631 .tabs-left>.nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
632 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
632 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
633 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
633 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
634 .tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
634 .tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
635 .tabs-right>.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
635 .tabs-right>.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
636 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
636 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
637 .nav>.disabled>a{color:#999999;}
637 .nav>.disabled>a{color:#999999;}
638 .nav>.disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default;}
638 .nav>.disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default;}
639 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;}
639 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;}
640 .navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #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;}
640 .navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #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;}
641 .navbar-inner:after{clear:both;}
641 .navbar-inner:after{clear:both;}
642 .navbar .container{width:auto;}
642 .navbar .container{width:auto;}
643 .nav-collapse.collapse{height:auto;overflow:visible;}
643 .nav-collapse.collapse{height:auto;overflow:visible;}
644 .navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover{text-decoration:none;}
644 .navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover{text-decoration:none;}
645 .navbar-text{margin-bottom:0;line-height:40px;color:#777777;}
645 .navbar-text{margin-bottom:0;line-height:40px;color:#777777;}
646 .navbar-link{color:#777777;}.navbar-link:hover{color:#333333;}
646 .navbar-link{color:#777777;}.navbar-link:hover{color:#333333;}
647 .navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;}
647 .navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;}
648 .navbar .btn,.navbar .btn-group{margin-top:5px;}
648 .navbar .btn,.navbar .btn-group{margin-top:5px;}
649 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0;}
649 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0;}
650 .navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;}
650 .navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;}
651 .navbar-form:after{clear:both;}
651 .navbar-form:after{clear:both;}
652 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
652 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
653 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;}
653 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;}
654 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
654 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
655 .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;}
655 .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;}
656 .navbar-search{position:relative;float:left;margin-top:5px;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;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
656 .navbar-search{position:relative;float:left;margin-top:5px;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;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
657 .navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
657 .navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
658 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;}
658 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;}
659 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;}
659 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;}
660 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;}
660 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;}
661 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
661 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
662 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
662 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}
663 .navbar-fixed-top{top:0;}
663 .navbar-fixed-top{top:0;}
664 .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);}
664 .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);}
665 .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);}
665 .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);}
666 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
666 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
667 .navbar .nav.pull-right{float:right;margin-right:0;}
667 .navbar .nav.pull-right{float:right;margin-right:0;}
668 .navbar .nav>li{float:left;}
668 .navbar .nav>li{float:left;}
669 .navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;}
669 .navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;}
670 .navbar .nav .dropdown-toggle .caret{margin-top:8px;}
670 .navbar .nav .dropdown-toggle .caret{margin-top:8px;}
671 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;}
671 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;}
672 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;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);}
672 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;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);}
673 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;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:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;}
673 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;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:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;}
674 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;}
674 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;}
675 .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);}
675 .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);}
676 .btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
676 .btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
677 .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;}
677 .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;}
678 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
678 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
679 .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;}
679 .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;}
680 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;}
680 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;}
681 .navbar .nav li.dropdown>a:hover .caret{border-top-color:#555555;border-bottom-color:#555555;}
681 .navbar .nav li.dropdown>a:hover .caret{border-top-color:#555555;border-bottom-color:#555555;}
682 .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:#555555;}
682 .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:#555555;}
683 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;}
683 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;}
684 .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:#555555;border-bottom-color:#555555;}
684 .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:#555555;border-bottom-color:#555555;}
685 .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;}
685 .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;}
686 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;}
686 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;}
687 .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;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
687 .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;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
688 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;}
688 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;}
689 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#ffffff;}
689 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#ffffff;}
690 .navbar-inverse .brand{color:#999999;}
690 .navbar-inverse .brand{color:#999999;}
691 .navbar-inverse .navbar-text{color:#999999;}
691 .navbar-inverse .navbar-text{color:#999999;}
692 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;}
692 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;}
693 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;}
693 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;}
694 .navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover{color:#ffffff;}
694 .navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover{color:#ffffff;}
695 .navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;}
695 .navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;}
696 .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:#111111;color:#ffffff;}
696 .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:#111111;color:#ffffff;}
697 .navbar-inverse .nav li.dropdown>a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
697 .navbar-inverse .nav li.dropdown>a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}
698 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;}
698 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;}
699 .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:#ffffff;border-bottom-color:#ffffff;}
699 .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:#ffffff;border-bottom-color:#ffffff;}
700 .navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-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:#cccccc;}
700 .navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-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:#cccccc;}
701 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;}
701 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;}
702 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;}
702 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;}
703 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;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;}
703 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;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;}
704 .navbar-inverse .btn-navbar{color:#ffffff;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 #000000;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:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;}
704 .navbar-inverse .btn-navbar{color:#ffffff;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 #000000;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:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;}
705 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;}
705 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;}
706 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-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 #ffffff;}.breadcrumb>li>.divider{padding:0 5px;color:#ccc;}
706 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-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 #ffffff;}.breadcrumb>li>.divider{padding:0 5px;color:#ccc;}
707 .breadcrumb>.active{color:#999999;}
707 .breadcrumb>.active{color:#999999;}
708 .pagination{margin:20px 0;}
708 .pagination{margin:20px 0;}
709 .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);}
709 .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);}
710 .pagination ul>li{display:inline;}
710 .pagination ul>li{display:inline;}
711 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;}
711 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;}
712 .pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;}
712 .pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;}
713 .pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;}
713 .pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;}
714 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999999;background-color:transparent;cursor:default;}
714 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999999;background-color:transparent;cursor:default;}
715 .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;}
715 .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;}
716 .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;}
716 .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;}
717 .pagination-centered{text-align:center;}
717 .pagination-centered{text-align:center;}
718 .pagination-right{text-align:right;}
718 .pagination-right{text-align:right;}
719 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px;}
719 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px;}
720 .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;}
720 .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;}
721 .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;}
721 .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;}
722 .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;}
722 .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;}
723 .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;}
723 .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;}
724 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px;}
724 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px;}
725 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px;}
725 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px;}
726 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;}
726 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;}
727 .pager:after{clear:both;}
727 .pager:after{clear:both;}
728 .pager li{display:inline;}
728 .pager li{display:inline;}
729 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
729 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
730 .pager li>a:hover{text-decoration:none;background-color:#f5f5f5;}
730 .pager li>a:hover{text-decoration:none;background-color:#f5f5f5;}
731 .pager .next>a,.pager .next>span{float:right;}
731 .pager .next>a,.pager .next>span{float:right;}
732 .pager .previous>a,.pager .previous>span{float:left;}
732 .pager .previous>a,.pager .previous>span{float:left;}
733 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;}
733 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;}
734 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
734 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
735 .modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
735 .modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
736 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;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%;}
736 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;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%;}
737 .modal.fade.in{top:10%;}
737 .modal.fade.in{top:10%;}
738 .modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
738 .modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
739 .modal-header h3{margin:0;line-height:30px;}
739 .modal-header h3{margin:0;line-height:30px;}
740 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;}
740 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;}
741 .modal-form{margin-bottom:0;}
741 .modal-form{margin-bottom:0;}
742 .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 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;}
742 .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 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;}
743 .modal-footer:after{clear:both;}
743 .modal-footer:after{clear:both;}
744 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}
744 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}
745 .modal-footer .btn-group .btn+.btn{margin-left:-1px;}
745 .modal-footer .btn-group .btn+.btn{margin-left:-1px;}
746 .modal-footer .btn-block+.btn-block{margin-left:0;}
746 .modal-footer .btn-block+.btn-block{margin-left:0;}
747 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
747 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
748 .tooltip.top{margin-top:-3px;}
748 .tooltip.top{margin-top:-3px;}
749 .tooltip.right{margin-left:3px;}
749 .tooltip.right{margin-left:3px;}
750 .tooltip.bottom{margin-top:3px;}
750 .tooltip.bottom{margin-top:3px;}
751 .tooltip.left{margin-left:-3px;}
751 .tooltip.left{margin-left:-3px;}
752 .tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
752 .tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
753 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;}
753 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;}
754 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;}
754 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;}
755 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;}
755 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;}
756 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;}
756 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;}
757 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;}
757 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;}
758 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;background-color:#ffffff;-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;}
758 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;background-color:#ffffff;-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;}
759 .popover.right{margin-left:10px;}
759 .popover.right{margin-left:10px;}
760 .popover.bottom{margin-top:10px;}
760 .popover.bottom{margin-top:10px;}
761 .popover.left{margin-left:-10px;}
761 .popover.left{margin-left:-10px;}
762 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}
762 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}
763 .popover-content{padding:9px 14px;}
763 .popover-content{padding:9px 14px;}
764 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid;}
764 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid;}
765 .popover .arrow{border-width:11px;}
765 .popover .arrow{border-width:11px;}
766 .popover .arrow:after{border-width:10px;content:"";}
766 .popover .arrow:after{border-width:10px;content:"";}
767 .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:#ffffff;}
767 .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:#ffffff;}
768 .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:#ffffff;}
768 .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:#ffffff;}
769 .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:#ffffff;}
769 .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:#ffffff;}
770 .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:#ffffff;bottom:-10px;}
770 .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:#ffffff;bottom:-10px;}
771 .thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;}
771 .thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;}
772 .thumbnails:after{clear:both;}
772 .thumbnails:after{clear:both;}
773 .row-fluid .thumbnails{margin-left:0;}
773 .row-fluid .thumbnails{margin-left:0;}
774 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;}
774 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;}
775 .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 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}
775 .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 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}
776 a.thumbnail:hover{border-color:#0088cc;-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);}
776 a.thumbnail:hover{border-color:#0088cc;-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);}
777 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
777 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
778 .thumbnail .caption{padding:9px;color:#555555;}
778 .thumbnail .caption{padding:9px;color:#555555;}
779 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1;}
779 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1;}
780 .media,.media .media{margin-top:15px;}
780 .media,.media .media{margin-top:15px;}
781 .media:first-child{margin-top:0;}
781 .media:first-child{margin-top:0;}
782 .media-object{display:block;}
782 .media-object{display:block;}
783 .media-heading{margin:0 0 5px;}
783 .media-heading{margin:0 0 5px;}
784 .media .pull-left{margin-right:10px;}
784 .media .pull-left{margin-right:10px;}
785 .media .pull-right{margin-left:10px;}
785 .media .pull-right{margin-left:10px;}
786 .media-list{margin-left:0;list-style:none;}
786 .media-list{margin-left:0;list-style:none;}
787 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;}
787 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;}
788 .label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
788 .label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
789 .badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}
789 .badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}
790 .label:empty,.badge:empty{display:none;}
790 .label:empty,.badge:empty{display:none;}
791 a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}
791 a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}
792 .label-important,.badge-important{background-color:#b94a48;}
792 .label-important,.badge-important{background-color:#b94a48;}
793 .label-important[href],.badge-important[href]{background-color:#953b39;}
793 .label-important[href],.badge-important[href]{background-color:#953b39;}
794 .label-warning,.badge-warning{background-color:#f89406;}
794 .label-warning,.badge-warning{background-color:#f89406;}
795 .label-warning[href],.badge-warning[href]{background-color:#c67605;}
795 .label-warning[href],.badge-warning[href]{background-color:#c67605;}
796 .label-success,.badge-success{background-color:#468847;}
796 .label-success,.badge-success{background-color:#468847;}
797 .label-success[href],.badge-success[href]{background-color:#356635;}
797 .label-success[href],.badge-success[href]{background-color:#356635;}
798 .label-info,.badge-info{background-color:#3a87ad;}
798 .label-info,.badge-info{background-color:#3a87ad;}
799 .label-info[href],.badge-info[href]{background-color:#2d6987;}
799 .label-info[href],.badge-info[href]{background-color:#2d6987;}
800 .label-inverse,.badge-inverse{background-color:#333333;}
800 .label-inverse,.badge-inverse{background-color:#333333;}
801 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}
801 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}
802 .btn .label,.btn .badge{position:relative;top:-1px;}
802 .btn .label,.btn .badge{position:relative;top:-1px;}
803 .btn-mini .label,.btn-mini .badge{top:0;}
803 .btn-mini .label,.btn-mini .badge{top:0;}
804 @-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);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
804 @-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);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
805 .progress .bar{width:0%;height:100%;color:#ffffff;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 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
805 .progress .bar{width:0%;height:100%;color:#ffffff;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 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
806 .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);}
806 .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);}
807 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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;}
807 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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;}
808 .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;}
808 .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;}
809 .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);}
809 .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);}
810 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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);}
810 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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);}
811 .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);}
811 .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);}
812 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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);}
812 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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);}
813 .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);}
813 .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);}
814 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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);}
814 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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-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);}
815 .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);}
816 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
816 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.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 .accordion{margin-bottom:20px;}
817 .accordion{margin-bottom:20px;}
818 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
818 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
819 .accordion-heading{border-bottom:0;}
819 .accordion-heading{border-bottom:0;}
820 .accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
820 .accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
821 .accordion-toggle{cursor:pointer;}
821 .accordion-toggle{cursor:pointer;}
822 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
822 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
823 .carousel{position:relative;margin-bottom:20px;line-height:1;}
823 .carousel{position:relative;margin-bottom:20px;line-height:1;}
824 .carousel-inner{overflow:hidden;width:100%;position:relative;}
824 .carousel-inner{overflow:hidden;width:100%;position:relative;}
825 .carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
825 .carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
826 .carousel-inner>.item>img{display:block;line-height:1;}
826 .carousel-inner>.item>img{display:block;line-height:1;}
827 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block;}
827 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block;}
828 .carousel-inner>.active{left:0;}
828 .carousel-inner>.active{left:0;}
829 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%;}
829 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%;}
830 .carousel-inner>.next{left:100%;}
830 .carousel-inner>.next{left:100%;}
831 .carousel-inner>.prev{left:-100%;}
831 .carousel-inner>.prev{left:-100%;}
832 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0;}
832 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0;}
833 .carousel-inner>.active.left{left:-100%;}
833 .carousel-inner>.active.left{left:-100%;}
834 .carousel-inner>.active.right{left:100%;}
834 .carousel-inner>.active.right{left:100%;}
835 .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:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
835 .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:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
836 .carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
836 .carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
837 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);}
837 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);}
838 .carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;}
838 .carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;}
839 .carousel-caption h4{margin:0 0 5px;}
839 .carousel-caption h4{margin:0 0 5px;}
840 .carousel-caption p{margin-bottom:0;}
840 .carousel-caption p{margin-bottom:0;}
841 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-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;}
841 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-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;}
842 .hero-unit li{line-height:30px;}
842 .hero-unit li{line-height:30px;}
843 .pull-right{float:right;}
843 .pull-right{float:right;}
844 .pull-left{float:left;}
844 .pull-left{float:left;}
845 .hide{display:none;}
845 .hide{display:none;}
846 .show{display:block;}
846 .show{display:block;}
847 .invisible{visibility:hidden;}
847 .invisible{visibility:hidden;}
848 .affix{position:fixed;}
848 .affix{position:fixed;}
849 .corner-all{border-radius:4px;}
849 .corner-all{border-radius:4px;}
850 .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;}
850 .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;}
851 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;}
851 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;}
852 .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%;}
852 .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%;}
853 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;}
853 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;}
854 .reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;}
854 .reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;}
855 .box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;}
855 .box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;}
856 .box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;}
856 .box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;}
857 .box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;}
857 .box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;}
858 .box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;}
858 .box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;}
859 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1;}
859 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1;}
860 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2;}
860 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2;}
861 .start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;}
861 .start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;}
862 .end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;}
862 .end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;}
863 .center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;}
863 .center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;}
864 .corner-all{border-radius:4px;}
864 .corner-all{border-radius:4px;}
865 body{background-color:#ffffff;}
865 body{background-color:#ffffff;}
866 body.notebook_app{overflow:hidden;}
866 body.notebook_app{overflow:hidden;}
867 blockquote{border-left:4px solid #DDD;padding:0 15px;color:#777;}
867 blockquote{border-left:4px solid #DDD;padding:0 15px;color:#777;}
868 span#save_widget{padding:5px;margin:0px 0px 0px 300px;display:inline-block;}
868 span#save_widget{padding:5px;margin:0px 0px 0px 300px;display:inline-block;}
869 span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%;}
869 span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%;}
870 .ui-menubar-item .ui-button .ui-button-text{padding:0.4em 1.0em;font-size:100%;}
870 .ui-menubar-item .ui-button .ui-button-text{padding:0.4em 1.0em;font-size:100%;}
871 .ui-menu{-moz-box-shadow:0px 6px 10px -1px #adadad;-webkit-box-shadow:0px 6px 10px -1px #adadad;box-shadow:0px 6px 10px -1px #adadad;}
871 .ui-menu{-moz-box-shadow:0px 6px 10px -1px #adadad;-webkit-box-shadow:0px 6px 10px -1px #adadad;box-shadow:0px 6px 10px -1px #adadad;}
872 .ui-menu .ui-menu-item a{border:1px solid transparent;padding:2px 1.6em;}
872 .ui-menu .ui-menu-item a{border:1px solid transparent;padding:2px 1.6em;}
873 .ui-menu .ui-menu-item a.ui-state-focus{margin:0;}
873 .ui-menu .ui-menu-item a.ui-state-focus{margin:0;}
874 .ui-menu hr{margin:0.3em 0;}
874 .ui-menu hr{margin:0.3em 0;}
875 #menubar_container{position:relative;}
875 #menubar_container{position:relative;}
876 #notification_area{position:absolute;right:0px;top:0px;height:25px;padding:3px 0px;padding-right:3px;z-index:10;}
876 #notification_area{position:absolute;right:0px;top:0px;height:25px;padding:3px 0px;padding-right:3px;z-index:10;}
877 .notification_widget{float:right;right:0px;top:1px;height:25px;padding:3px 6px;z-index:10;}
877 .notification_widget{float:right;right:0px;top:1px;height:25px;padding:3px 6px;z-index:10;}
878 .toolbar{padding:3px 15px;border-bottom:1px #ababab solid;}.toolbar button{margin-top:2px;margin-bottom:2px;}
878 .toolbar{padding:3px 15px;border-bottom:1px #ababab solid;}.toolbar button{margin-top:2px;margin-bottom:2px;}
879 .toolbar select,.toolbar label{height:19px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:0.3em;margin-right:0.3em;padding:0px;}
879 .toolbar select,.toolbar label{height:19px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:0.3em;margin-right:0.3em;padding:0px;}
880 .toolbar select{width:auto;}
880 .toolbar select{width:auto;}
881 #ipython-main-app{width:100%;position:relative;font-size:110%;}
881 #ipython-main-app{width:100%;position:relative;font-size:110%;}
882 span#quick_help_area{position:static;padding:5px 0px;margin:0px 0px 0px 0px;}
882 span#quick_help_area{position:static;padding:5px 0px;margin:0px 0px 0px 0px;}
883 .help_string{float:right;width:170px;padding:0px 5px;text-align:left;font-size:85%;}
883 .help_string{float:right;width:170px;padding:0px 5px;text-align:left;font-size:85%;}
884 .help_string_label{float:right;font-size:85%;}
884 .help_string_label{float:right;font-size:85%;}
885 div#notebook_panel{margin:0px 0px 0px 0px;padding:0px;}
885 div#notebook_panel{margin:0px 0px 0px 0px;padding:0px;}
886 div#notebook{overflow-y:scroll;overflow-x:auto;width:100%;padding:5px 5px 15px 5px;margin:0px;}
886 div#notebook{overflow-y:scroll;overflow-x:auto;width:100%;padding:5px 5px 15px 5px;margin:0px;}
887 div#pager_splitter{height:8px;}
887 div#pager_splitter{height:8px;}
888 #pager_container{position:relative;}
888 #pager_container{position:relative;}
889 div#pager{padding:15px;overflow:auto;display:none;}
889 div#pager{padding:15px;overflow:auto;display:none;}
890 div.ui-widget-content{border:1px solid #ababab;outline:none;}
890 div.ui-widget-content{border:1px solid #ababab;outline:none;}
891 .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%;}.cell.selected{border-radius:4px;border:thin #ababab solid;}
891 .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%;}.cell.selected{border-radius:4px;border:thin #ababab solid;}
892 div.cell{width:100%;padding:5px 5px 5px 0px;margin:2px 0px 2px 0px;outline:none;}
892 div.cell{width:100%;padding:5px 5px 5px 0px;margin:2px 0px 2px 0px;outline:none;}
893 div.prompt{width:11ex;padding:0.4em;margin:0px;font-family:monospace;text-align:right;line-height:1.231;}
893 div.prompt{width:11ex;padding:0.4em;margin:0px;font-family:monospace;text-align:right;line-height:1.231;}
894 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;}
894 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;}
895 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7;}
895 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7;}
896 div.input_prompt{color:navy;border-top:1px solid transparent;}
896 div.input_prompt{color:navy;border-top:1px solid transparent;}
897 div.output_wrapper{margin-top:5px;margin-left:5px;width:100%;position:relative;}
897 div.output_wrapper{margin-top:5px;margin-left:5px;width:100%;position:relative;}
898 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;box-shadow:inset 0 2px 8px rgba(0, 0, 0, 0.8);}
898 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;box-shadow:inset 0 2px 8px rgba(0, 0, 0, 0.8);}
899 div.output_collapsed{margin-right:5px;}
899 div.output_collapsed{margin-right:5px;}
900 div.out_prompt_overlay{height:100%;padding:0px;position:absolute;border-radius:4px;}
900 div.out_prompt_overlay{height:100%;padding:0px;position:absolute;border-radius:4px;}
901 div.out_prompt_overlay:hover{box-shadow:inset 0 0 1px #000;background:rgba(240, 240, 240, 0.5);}
901 div.out_prompt_overlay:hover{box-shadow:inset 0 0 1px #000;background:rgba(240, 240, 240, 0.5);}
902 div.output_prompt{color:darkred;margin:0 5px 0 -5px;}
902 div.output_prompt{color:darkred;margin:0 5px 0 -5px;}
903 div.output_area{padding:0px;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;}
903 div.output_area{padding:0px;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;}
904 div.output_area pre{font-family:monospace;margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:black;}
904 div.output_area pre{font-family:monospace;margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:black;}
905 div.output_subarea{padding:0.44em 0.4em 0.4em 1px;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;}
905 div.output_subarea{padding:0.44em 0.4em 0.4em 1px;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;}
906 div.output_text{text-align:left;color:#000000;font-family:monospace;line-height:1.231;}
906 div.output_text{text-align:left;color:#000000;font-family:monospace;line-height:1.231;}
907 div.output_stream{padding-top:0.0em;padding-bottom:0.0em;}
907 div.output_stream{padding-top:0.0em;padding-bottom:0.0em;}
908 div.output_stderr{background:#fdd;}
908 div.output_stderr{background:#fdd;}
909 div.output_latex{text-align:left;}
909 div.output_latex{text-align:left;}
910 div.text_cell{padding:5px 5px 5px 5px;}
910 div.text_cell{padding:5px 5px 5px 5px;}
911 div.text_cell_input{color:#000000;border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7;}
911 div.text_cell_input{color:#000000;border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7;}
912 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:5px;color:#000000;}
912 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:5px;color:#000000;}
913 .CodeMirror{line-height:1.231;}
913 .CodeMirror{line-height:1.231;}
914 .CodeMirror-scroll{height:auto;overflow-y:hidden;overflow-x:auto;}
914 .CodeMirror-scroll{height:auto;overflow-y:hidden;overflow-x:auto;}
915 .ansiblack{color:#000000;}
915 .ansiblack{color:#000000;}
916 .ansired{color:darkred;}
916 .ansired{color:darkred;}
917 .ansigreen{color:darkgreen;}
917 .ansigreen{color:darkgreen;}
918 .ansiyellow{color:brown;}
918 .ansiyellow{color:brown;}
919 .ansiblue{color:darkblue;}
919 .ansiblue{color:darkblue;}
920 .ansipurple{color:darkviolet;}
920 .ansipurple{color:darkviolet;}
921 .ansicyan{color:steelblue;}
921 .ansicyan{color:steelblue;}
922 .ansigrey{color:grey;}
922 .ansigrey{color:grey;}
923 .ansibold{font-weight:bold;}
923 .ansibold{font-weight:bold;}
924 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;}
924 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;}
925 .completions select{background:white;outline:none;border:none;padding:0px;margin:0px;overflow:auto;font-family:monospace;}
925 .completions select{background:white;outline:none;border:none;padding:0px;margin:0px;overflow:auto;font-family:monospace;}
926 option.context{background-color:#DEF7FF;}
926 option.context{background-color:#DEF7FF;}
927 option.introspection{background-color:#EBF4EB;}
927 option.introspection{background-color:#EBF4EB;}
928 .completions p b{font-weight:bold;}
928 .completions p b{font-weight:bold;}
929 .completions p{background:#DDF;border-bottom:black solid 1px;padding:1px;font-family:monospace;}
929 .completions p{background:#DDF;border-bottom:black solid 1px;padding:1px;font-family:monospace;}
930 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:0.4em;padding-left:2em;}
930 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:0.4em;padding-left:2em;}
931 p.dialog{padding:0.2em;}
931 p.dialog{padding:0.2em;}
932 .shortcut_key{display:inline-block;width:15ex;text-align:right;font-family:monospace;}
932 .shortcut_key{display:inline-block;width:15ex;text-align:right;font-family:monospace;}
933 pre,code,kbd,samp{white-space:pre-wrap;}
933 pre,code,kbd,samp{white-space:pre-wrap;}
934 #fonttest{font-family:monospace;}
934 #fonttest{font-family:monospace;}
935 .js-error{color:darkred;}
935 .js-error{color:darkred;}
936 a{text-decoration:underline;}
936 a{text-decoration:underline;}
937 p{margin-bottom:0;}
937 p{margin-bottom:0;}
938 a.heading-anchor:link,a.heading-anchor:visited{text-decoration:none;color:inherit;}
938 a.heading-anchor:link,a.heading-anchor:visited{text-decoration:none;color:inherit;}
939 div.raw_input{padding-top:0px;padding-bottom:0px;height:1em;line-height:1em;font-family:monospace;}
940 span.input_prompt{font-family:inherit;}
941 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;margin:-2px 0px 0px 1px;padding-left:1px;padding-top:2px;height:1em;}
939 @media print{body{overflow:visible !important;} div#notebook{overflow:visible !important;} .ui-widget-content{border:0px;} #save_widget{margin:0px !important;} #header,#pager,#pager_splitter,#menubar,#toolbar{display:none !important;} .cell{border:none !important;} .toolbar{display:none;}}.rendered_html{color:black;}.rendered_html em{font-style:italic;}
942 @media print{body{overflow:visible !important;} div#notebook{overflow:visible !important;} .ui-widget-content{border:0px;} #save_widget{margin:0px !important;} #header,#pager,#pager_splitter,#menubar,#toolbar{display:none !important;} .cell{border:none !important;} .toolbar{display:none;}}.rendered_html{color:black;}.rendered_html em{font-style:italic;}
940 .rendered_html strong{font-weight:bold;}
943 .rendered_html strong{font-weight:bold;}
941 .rendered_html u{text-decoration:underline;}
944 .rendered_html u{text-decoration:underline;}
942 .rendered_html :link{text-decoration:underline;}
945 .rendered_html :link{text-decoration:underline;}
943 .rendered_html :visited{text-decoration:underline;}
946 .rendered_html :visited{text-decoration:underline;}
944 .rendered_html h1{font-size:197%;margin:.65em 0;font-weight:bold;}
947 .rendered_html h1{font-size:197%;margin:.65em 0;font-weight:bold;}
945 .rendered_html h2{font-size:153.9%;margin:.75em 0;font-weight:bold;}
948 .rendered_html h2{font-size:153.9%;margin:.75em 0;font-weight:bold;}
946 .rendered_html h3{font-size:123.1%;margin:.85em 0;font-weight:bold;}
949 .rendered_html h3{font-size:123.1%;margin:.85em 0;font-weight:bold;}
947 .rendered_html h4{font-size:100%;margin:0.95em 0;font-weight:bold;}
950 .rendered_html h4{font-size:100%;margin:0.95em 0;font-weight:bold;}
948 .rendered_html h5{font-size:85%;margin:1.5em 0;font-weight:bold;}
951 .rendered_html h5{font-size:85%;margin:1.5em 0;font-weight:bold;}
949 .rendered_html h6{font-size:77%;margin:1.65em 0;font-weight:bold;}
952 .rendered_html h6{font-size:77%;margin:1.65em 0;font-weight:bold;}
950 .rendered_html ul{list-style:disc;margin:1em 2em;}
953 .rendered_html ul{list-style:disc;margin:1em 2em;}
951 .rendered_html ul ul{list-style:square;margin:0em 2em;}
954 .rendered_html ul ul{list-style:square;margin:0em 2em;}
952 .rendered_html ul ul ul{list-style:circle;margin:0em 2em;}
955 .rendered_html ul ul ul{list-style:circle;margin:0em 2em;}
953 .rendered_html ol{list-style:decimal;margin:1em 2em;}
956 .rendered_html ol{list-style:decimal;margin:1em 2em;}
954 .rendered_html ol ol{list-style:upper-alpha;margin:0em 2em;}
957 .rendered_html ol ol{list-style:upper-alpha;margin:0em 2em;}
955 .rendered_html ol ol ol{list-style:lower-alpha;margin:0em 2em;}
958 .rendered_html ol ol ol{list-style:lower-alpha;margin:0em 2em;}
956 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0em 2em;}
959 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0em 2em;}
957 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0em 2em;}
960 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0em 2em;}
958 .rendered_html hr{color:black;background-color:black;}
961 .rendered_html hr{color:black;background-color:black;}
959 .rendered_html pre{margin:1em 2em;}
962 .rendered_html pre{margin:1em 2em;}
960 .rendered_html blockquote{margin:1em 2em;}
963 .rendered_html blockquote{margin:1em 2em;}
961 .rendered_html table,.rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid black;border-collapse:collapse;margin:1em 2em;}
964 .rendered_html table,.rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid black;border-collapse:collapse;margin:1em 2em;}
962 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px;}
965 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px;}
963 .rendered_html th{font-weight:bold;}
966 .rendered_html th{font-weight:bold;}
964 .rendered_html p{text-align:justify;}
967 .rendered_html p{text-align:justify;}
965 .rendered_html p+p{margin-top:1em;}
968 .rendered_html p+p{margin-top:1em;}
966 .corner-all{border-radius:4px;}
969 .corner-all{border-radius:4px;}
967 @-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;}
970 @-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;}
968 .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;}
971 .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;}
969 .tooltipbuttons{position:absolute;padding-right:15px;top:0px;right:0px;}
972 .tooltipbuttons{position:absolute;padding-right:15px;top:0px;right:0px;}
970 .tooltiptext{padding-right:30px;}
973 .tooltiptext{padding-right:30px;}
971 .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:0px;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0px 6px 10px -1px #adadad;-webkit-box-shadow:0px 6px 10px -1px #adadad;box-shadow:0px 6px 10px -1px #adadad;border-radius:4px;position:absolute;}.ipython_tooltip a{float:right;}
974 .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:0px;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0px 6px 10px -1px #adadad;-webkit-box-shadow:0px 6px 10px -1px #adadad;box-shadow:0px 6px 10px -1px #adadad;border-radius:4px;position:absolute;}.ipython_tooltip a{float:right;}
972 .pretooltiparrow{left:0px;margin:0px;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute;}
975 .pretooltiparrow{left:0px;margin:0px;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute;}
973 .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);}
976 .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,425 +1,439 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 var from = {ch:cur.ch-chToPrevTabStop,line:cur.line}
34 var 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 key = IPython.utils.keycodes;
48 var key = IPython.utils.keycodes;
49 CodeMirror.modeURL = "/static/codemirror/mode/%N/%N.js";
49 CodeMirror.modeURL = "/static/codemirror/mode/%N/%N.js";
50
50
51 /**
51 /**
52 * A Cell conceived to write code.
52 * A Cell conceived to write code.
53 *
53 *
54 * The kernel doesn't have to be set at creation time, in that case
54 * The kernel doesn't have to be set at creation time, in that case
55 * it will be null and set_kernel has to be called later.
55 * it will be null and set_kernel has to be called later.
56 * @class CodeCell
56 * @class CodeCell
57 * @extends IPython.Cell
57 * @extends IPython.Cell
58 *
58 *
59 * @constructor
59 * @constructor
60 * @param {Object|null} kernel
60 * @param {Object|null} kernel
61 * @param {object|undefined} [options]
61 * @param {object|undefined} [options]
62 * @param [options.cm_config] {object} config to pass to CodeMirror
62 * @param [options.cm_config] {object} config to pass to CodeMirror
63 */
63 */
64 var CodeCell = function (kernel, options) {
64 var CodeCell = function (kernel, options) {
65 this.kernel = kernel || null;
65 this.kernel = kernel || null;
66 this.code_mirror = null;
66 this.code_mirror = null;
67 this.input_prompt_number = null;
67 this.input_prompt_number = null;
68 this.collapsed = false;
68 this.collapsed = false;
69 this.default_mode = 'python';
69 this.default_mode = 'python';
70
70
71
71
72 var cm_overwrite_options = {
72 var cm_overwrite_options = {
73 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
73 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
74 };
74 };
75
75
76 options = this.mergeopt(CodeCell, options, {cm_config:cm_overwrite_options});
76 options = this.mergeopt(CodeCell, options, {cm_config:cm_overwrite_options});
77
77
78 IPython.Cell.apply(this,[options]);
78 IPython.Cell.apply(this,[options]);
79
79
80 var that = this;
80 var that = this;
81 this.element.focusout(
81 this.element.focusout(
82 function() { that.auto_highlight(); }
82 function() { that.auto_highlight(); }
83 );
83 );
84 };
84 };
85
85
86 CodeCell.options_default = {
86 CodeCell.options_default = {
87 cm_config : {
87 cm_config : {
88 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess",'Backspace':"delSpaceToPrevTabStop"},
88 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess",'Backspace':"delSpaceToPrevTabStop"},
89 mode: 'python',
89 mode: 'python',
90 theme: 'ipython',
90 theme: 'ipython',
91 matchBrackets: true
91 matchBrackets: true
92 }
92 }
93 };
93 };
94
94
95
95
96 CodeCell.prototype = new IPython.Cell();
96 CodeCell.prototype = new IPython.Cell();
97
97
98 /**
98 /**
99 * @method auto_highlight
99 * @method auto_highlight
100 */
100 */
101 CodeCell.prototype.auto_highlight = function () {
101 CodeCell.prototype.auto_highlight = function () {
102 this._auto_highlight(IPython.config.cell_magic_highlight)
102 this._auto_highlight(IPython.config.cell_magic_highlight)
103 };
103 };
104
104
105 /** @method create_element */
105 /** @method create_element */
106 CodeCell.prototype.create_element = function () {
106 CodeCell.prototype.create_element = function () {
107 IPython.Cell.prototype.create_element.apply(this, arguments);
107 IPython.Cell.prototype.create_element.apply(this, arguments);
108
108
109 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell');
109 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell');
110 cell.attr('tabindex','2');
110 cell.attr('tabindex','2');
111
111
112 this.celltoolbar = new IPython.CellToolbar(this);
112 this.celltoolbar = new IPython.CellToolbar(this);
113
113
114 var input = $('<div></div>').addClass('input');
114 var input = $('<div></div>').addClass('input');
115 var vbox = $('<div/>').addClass('vbox box-flex1')
115 var vbox = $('<div/>').addClass('vbox box-flex1')
116 input.append($('<div/>').addClass('prompt input_prompt'));
116 input.append($('<div/>').addClass('prompt input_prompt'));
117 vbox.append(this.celltoolbar.element);
117 vbox.append(this.celltoolbar.element);
118 var input_area = $('<div/>').addClass('input_area');
118 var input_area = $('<div/>').addClass('input_area');
119 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
119 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
120 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
120 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
121 vbox.append(input_area);
121 vbox.append(input_area);
122 input.append(vbox);
122 input.append(vbox);
123 var output = $('<div></div>');
123 var output = $('<div></div>');
124 cell.append(input).append(output);
124 cell.append(input).append(output);
125 this.element = cell;
125 this.element = cell;
126 this.output_area = new IPython.OutputArea(output, true);
126 this.output_area = new IPython.OutputArea(output, true);
127
127
128 // construct a completer only if class exist
128 // construct a completer only if class exist
129 // otherwise no print view
129 // otherwise no print view
130 if (IPython.Completer !== undefined)
130 if (IPython.Completer !== undefined)
131 {
131 {
132 this.completer = new IPython.Completer(this);
132 this.completer = new IPython.Completer(this);
133 }
133 }
134 };
134 };
135
135
136 /**
136 /**
137 * This method gets called in CodeMirror's onKeyDown/onKeyPress
137 * This method gets called in CodeMirror's onKeyDown/onKeyPress
138 * handlers and is used to provide custom key handling. Its return
138 * handlers and is used to provide custom key handling. Its return
139 * value is used to determine if CodeMirror should ignore the event:
139 * value is used to determine if CodeMirror should ignore the event:
140 * true = ignore, false = don't ignore.
140 * true = ignore, false = don't ignore.
141 * @method handle_codemirror_keyevent
141 * @method handle_codemirror_keyevent
142 */
142 */
143 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
143 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
144
144
145 if (this.read_only){
145 if (this.read_only){
146 return false;
146 return false;
147 }
147 }
148
148
149 var that = this;
149 var that = this;
150 // whatever key is pressed, first, cancel the tooltip request before
150 // whatever key is pressed, first, cancel the tooltip request before
151 // they are sent, and remove tooltip if any, except for tab again
151 // they are sent, and remove tooltip if any, except for tab again
152 if (event.type === 'keydown' && event.which != key.TAB ) {
152 if (event.type === 'keydown' && event.which != key.TAB ) {
153 IPython.tooltip.remove_and_cancel_tooltip();
153 IPython.tooltip.remove_and_cancel_tooltip();
154 };
154 };
155
155
156 var cur = editor.getCursor();
156 var cur = editor.getCursor();
157 if (event.keyCode === key.ENTER){
157 if (event.keyCode === key.ENTER){
158 this.auto_highlight();
158 this.auto_highlight();
159 }
159 }
160
160
161 if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
161 if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
162 // Always ignore shift-enter in CodeMirror as we handle it.
162 // Always ignore shift-enter in CodeMirror as we handle it.
163 return true;
163 return true;
164 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
164 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
165 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
165 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
166 // browser and keyboard layout !
166 // browser and keyboard layout !
167 // Pressing '(' , request tooltip, don't forget to reappend it
167 // Pressing '(' , request tooltip, don't forget to reappend it
168 IPython.tooltip.pending(that);
168 IPython.tooltip.pending(that);
169 } else if (event.which === key.UPARROW && event.type === 'keydown') {
169 } else if (event.which === key.UPARROW && event.type === 'keydown') {
170 // If we are not at the top, let CM handle the up arrow and
170 // If we are not at the top, let CM handle the up arrow and
171 // prevent the global keydown handler from handling it.
171 // prevent the global keydown handler from handling it.
172 if (!that.at_top()) {
172 if (!that.at_top()) {
173 event.stop();
173 event.stop();
174 return false;
174 return false;
175 } else {
175 } else {
176 return true;
176 return true;
177 };
177 };
178 } else if (event.which === key.ESC) {
178 } else if (event.which === key.ESC) {
179 IPython.tooltip.remove_and_cancel_tooltip(true);
179 IPython.tooltip.remove_and_cancel_tooltip(true);
180 return true;
180 return true;
181 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
181 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
182 // If we are not at the bottom, let CM handle the down arrow and
182 // If we are not at the bottom, let CM handle the down arrow and
183 // prevent the global keydown handler from handling it.
183 // prevent the global keydown handler from handling it.
184 if (!that.at_bottom()) {
184 if (!that.at_bottom()) {
185 event.stop();
185 event.stop();
186 return false;
186 return false;
187 } else {
187 } else {
188 return true;
188 return true;
189 };
189 };
190 } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) {
190 } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) {
191 if (editor.somethingSelected()){
191 if (editor.somethingSelected()){
192 var anchor = editor.getCursor("anchor");
192 var anchor = editor.getCursor("anchor");
193 var head = editor.getCursor("head");
193 var head = editor.getCursor("head");
194 if( anchor.line != head.line){
194 if( anchor.line != head.line){
195 return false;
195 return false;
196 }
196 }
197 }
197 }
198 IPython.tooltip.request(that);
198 IPython.tooltip.request(that);
199 event.stop();
199 event.stop();
200 return true;
200 return true;
201 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
201 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
202 // Tab completion.
202 // Tab completion.
203 //Do not trim here because of tooltip
203 //Do not trim here because of tooltip
204 if (editor.somethingSelected()){return false}
204 if (editor.somethingSelected()){return false}
205 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
205 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
206 if (pre_cursor.trim() === "") {
206 if (pre_cursor.trim() === "") {
207 // Don't autocomplete if the part of the line before the cursor
207 // Don't autocomplete if the part of the line before the cursor
208 // is empty. In this case, let CodeMirror handle indentation.
208 // is empty. In this case, let CodeMirror handle indentation.
209 return false;
209 return false;
210 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && IPython.config.tooltip_on_tab ) {
210 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && IPython.config.tooltip_on_tab ) {
211 IPython.tooltip.request(that);
211 IPython.tooltip.request(that);
212 // Prevent the event from bubbling up.
212 // Prevent the event from bubbling up.
213 event.stop();
213 event.stop();
214 // Prevent CodeMirror from handling the tab.
214 // Prevent CodeMirror from handling the tab.
215 return true;
215 return true;
216 } else {
216 } else {
217 event.stop();
217 event.stop();
218 this.completer.startCompletion();
218 this.completer.startCompletion();
219 return true;
219 return true;
220 };
220 };
221 } else {
221 } else {
222 // keypress/keyup also trigger on TAB press, and we don't want to
222 // keypress/keyup also trigger on TAB press, and we don't want to
223 // use those to disable tab completion.
223 // use those to disable tab completion.
224 return false;
224 return false;
225 };
225 };
226 return false;
226 return false;
227 };
227 };
228
228
229
229
230 // Kernel related calls.
230 // Kernel related calls.
231
231
232 CodeCell.prototype.set_kernel = function (kernel) {
232 CodeCell.prototype.set_kernel = function (kernel) {
233 this.kernel = kernel;
233 this.kernel = kernel;
234 }
234 }
235
235
236 /**
236 /**
237 * Execute current code cell to the kernel
237 * Execute current code cell to the kernel
238 * @method execute
238 * @method execute
239 */
239 */
240 CodeCell.prototype.execute = function () {
240 CodeCell.prototype.execute = function () {
241 this.output_area.clear_output(true, true, true);
241 this.output_area.clear_output(true, true, true);
242 this.set_input_prompt('*');
242 this.set_input_prompt('*');
243 this.element.addClass("running");
243 this.element.addClass("running");
244 var callbacks = {
244 var callbacks = {
245 'execute_reply': $.proxy(this._handle_execute_reply, this),
245 'execute_reply': $.proxy(this._handle_execute_reply, this),
246 'output': $.proxy(this.output_area.handle_output, this.output_area),
246 'output': $.proxy(this.output_area.handle_output, this.output_area),
247 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
247 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
248 'set_next_input': $.proxy(this._handle_set_next_input, this)
248 'set_next_input': $.proxy(this._handle_set_next_input, this),
249 'input_request': $.proxy(this._handle_input_request, this)
249 };
250 };
250 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
251 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
251 };
252 };
252
253
253 /**
254 /**
254 * @method _handle_execute_reply
255 * @method _handle_execute_reply
255 * @private
256 * @private
256 */
257 */
257 CodeCell.prototype._handle_execute_reply = function (content) {
258 CodeCell.prototype._handle_execute_reply = function (content) {
258 this.set_input_prompt(content.execution_count);
259 this.set_input_prompt(content.execution_count);
259 this.element.removeClass("running");
260 this.element.removeClass("running");
260 $([IPython.events]).trigger('set_dirty.Notebook', {'value': true});
261 $([IPython.events]).trigger('set_dirty.Notebook', {'value': true});
261 }
262 }
262
263
264 /**
265 * @method _handle_set_next_input
266 * @private
267 */
263 CodeCell.prototype._handle_set_next_input = function (text) {
268 CodeCell.prototype._handle_set_next_input = function (text) {
264 var data = {'cell': this, 'text': text}
269 var data = {'cell': this, 'text': text}
265 $([IPython.events]).trigger('set_next_input.Notebook', data);
270 $([IPython.events]).trigger('set_next_input.Notebook', data);
266 }
271 }
267
272
273 /**
274 * @method _handle_input_request
275 * @private
276 */
277 CodeCell.prototype._handle_input_request = function (content) {
278 this.output_area.append_raw_input(content);
279 }
280
281
268 // Basic cell manipulation.
282 // Basic cell manipulation.
269
283
270 CodeCell.prototype.select = function () {
284 CodeCell.prototype.select = function () {
271 IPython.Cell.prototype.select.apply(this);
285 IPython.Cell.prototype.select.apply(this);
272 this.code_mirror.refresh();
286 this.code_mirror.refresh();
273 this.code_mirror.focus();
287 this.code_mirror.focus();
274 this.auto_highlight();
288 this.auto_highlight();
275 // We used to need an additional refresh() after the focus, but
289 // We used to need an additional refresh() after the focus, but
276 // it appears that this has been fixed in CM. This bug would show
290 // it appears that this has been fixed in CM. This bug would show
277 // up on FF when a newly loaded markdown cell was edited.
291 // up on FF when a newly loaded markdown cell was edited.
278 };
292 };
279
293
280
294
281 CodeCell.prototype.select_all = function () {
295 CodeCell.prototype.select_all = function () {
282 var start = {line: 0, ch: 0};
296 var start = {line: 0, ch: 0};
283 var nlines = this.code_mirror.lineCount();
297 var nlines = this.code_mirror.lineCount();
284 var last_line = this.code_mirror.getLine(nlines-1);
298 var last_line = this.code_mirror.getLine(nlines-1);
285 var end = {line: nlines-1, ch: last_line.length};
299 var end = {line: nlines-1, ch: last_line.length};
286 this.code_mirror.setSelection(start, end);
300 this.code_mirror.setSelection(start, end);
287 };
301 };
288
302
289
303
290 CodeCell.prototype.collapse = function () {
304 CodeCell.prototype.collapse = function () {
291 this.collapsed = true;
305 this.collapsed = true;
292 this.output_area.collapse();
306 this.output_area.collapse();
293 };
307 };
294
308
295
309
296 CodeCell.prototype.expand = function () {
310 CodeCell.prototype.expand = function () {
297 this.collapsed = false;
311 this.collapsed = false;
298 this.output_area.expand();
312 this.output_area.expand();
299 };
313 };
300
314
301
315
302 CodeCell.prototype.toggle_output = function () {
316 CodeCell.prototype.toggle_output = function () {
303 this.collapsed = Boolean(1 - this.collapsed);
317 this.collapsed = Boolean(1 - this.collapsed);
304 this.output_area.toggle_output();
318 this.output_area.toggle_output();
305 };
319 };
306
320
307
321
308 CodeCell.prototype.toggle_output_scroll = function () {
322 CodeCell.prototype.toggle_output_scroll = function () {
309 this.output_area.toggle_scroll();
323 this.output_area.toggle_scroll();
310 };
324 };
311
325
312
326
313 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
327 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
314 var ns = prompt_value || "&nbsp;";
328 var ns = prompt_value || "&nbsp;";
315 return 'In&nbsp;[' + ns + ']:'
329 return 'In&nbsp;[' + ns + ']:'
316 };
330 };
317
331
318 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
332 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
319 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
333 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
320 for(var i=1; i < lines_number; i++){html.push(['...:'])};
334 for(var i=1; i < lines_number; i++){html.push(['...:'])};
321 return html.join('</br>')
335 return html.join('</br>')
322 };
336 };
323
337
324 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
338 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
325
339
326
340
327 CodeCell.prototype.set_input_prompt = function (number) {
341 CodeCell.prototype.set_input_prompt = function (number) {
328 var nline = 1
342 var nline = 1
329 if( this.code_mirror != undefined) {
343 if( this.code_mirror != undefined) {
330 nline = this.code_mirror.lineCount();
344 nline = this.code_mirror.lineCount();
331 }
345 }
332 this.input_prompt_number = number;
346 this.input_prompt_number = number;
333 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
347 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
334 this.element.find('div.input_prompt').html(prompt_html);
348 this.element.find('div.input_prompt').html(prompt_html);
335 };
349 };
336
350
337
351
338 CodeCell.prototype.clear_input = function () {
352 CodeCell.prototype.clear_input = function () {
339 this.code_mirror.setValue('');
353 this.code_mirror.setValue('');
340 };
354 };
341
355
342
356
343 CodeCell.prototype.get_text = function () {
357 CodeCell.prototype.get_text = function () {
344 return this.code_mirror.getValue();
358 return this.code_mirror.getValue();
345 };
359 };
346
360
347
361
348 CodeCell.prototype.set_text = function (code) {
362 CodeCell.prototype.set_text = function (code) {
349 return this.code_mirror.setValue(code);
363 return this.code_mirror.setValue(code);
350 };
364 };
351
365
352
366
353 CodeCell.prototype.at_top = function () {
367 CodeCell.prototype.at_top = function () {
354 var cursor = this.code_mirror.getCursor();
368 var cursor = this.code_mirror.getCursor();
355 if (cursor.line === 0 && cursor.ch === 0) {
369 if (cursor.line === 0 && cursor.ch === 0) {
356 return true;
370 return true;
357 } else {
371 } else {
358 return false;
372 return false;
359 }
373 }
360 };
374 };
361
375
362
376
363 CodeCell.prototype.at_bottom = function () {
377 CodeCell.prototype.at_bottom = function () {
364 var cursor = this.code_mirror.getCursor();
378 var cursor = this.code_mirror.getCursor();
365 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
379 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
366 return true;
380 return true;
367 } else {
381 } else {
368 return false;
382 return false;
369 }
383 }
370 };
384 };
371
385
372
386
373 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
387 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
374 this.output_area.clear_output(stdout, stderr, other);
388 this.output_area.clear_output(stdout, stderr, other);
375 };
389 };
376
390
377
391
378 // JSON serialization
392 // JSON serialization
379
393
380 CodeCell.prototype.fromJSON = function (data) {
394 CodeCell.prototype.fromJSON = function (data) {
381 IPython.Cell.prototype.fromJSON.apply(this, arguments);
395 IPython.Cell.prototype.fromJSON.apply(this, arguments);
382 if (data.cell_type === 'code') {
396 if (data.cell_type === 'code') {
383 if (data.input !== undefined) {
397 if (data.input !== undefined) {
384 this.set_text(data.input);
398 this.set_text(data.input);
385 // make this value the starting point, so that we can only undo
399 // make this value the starting point, so that we can only undo
386 // to this state, instead of a blank cell
400 // to this state, instead of a blank cell
387 this.code_mirror.clearHistory();
401 this.code_mirror.clearHistory();
388 this.auto_highlight();
402 this.auto_highlight();
389 }
403 }
390 if (data.prompt_number !== undefined) {
404 if (data.prompt_number !== undefined) {
391 this.set_input_prompt(data.prompt_number);
405 this.set_input_prompt(data.prompt_number);
392 } else {
406 } else {
393 this.set_input_prompt();
407 this.set_input_prompt();
394 };
408 };
395 this.output_area.fromJSON(data.outputs);
409 this.output_area.fromJSON(data.outputs);
396 if (data.collapsed !== undefined) {
410 if (data.collapsed !== undefined) {
397 if (data.collapsed) {
411 if (data.collapsed) {
398 this.collapse();
412 this.collapse();
399 } else {
413 } else {
400 this.expand();
414 this.expand();
401 };
415 };
402 };
416 };
403 };
417 };
404 };
418 };
405
419
406
420
407 CodeCell.prototype.toJSON = function () {
421 CodeCell.prototype.toJSON = function () {
408 var data = IPython.Cell.prototype.toJSON.apply(this);
422 var data = IPython.Cell.prototype.toJSON.apply(this);
409 data.input = this.get_text();
423 data.input = this.get_text();
410 data.cell_type = 'code';
424 data.cell_type = 'code';
411 if (this.input_prompt_number) {
425 if (this.input_prompt_number) {
412 data.prompt_number = this.input_prompt_number;
426 data.prompt_number = this.input_prompt_number;
413 };
427 };
414 var outputs = this.output_area.toJSON();
428 var outputs = this.output_area.toJSON();
415 data.outputs = outputs;
429 data.outputs = outputs;
416 data.language = 'python';
430 data.language = 'python';
417 data.collapsed = this.collapsed;
431 data.collapsed = this.collapsed;
418 return data;
432 return data;
419 };
433 };
420
434
421
435
422 IPython.CodeCell = CodeCell;
436 IPython.CodeCell = CodeCell;
423
437
424 return IPython;
438 return IPython;
425 }(IPython));
439 }(IPython));
@@ -1,441 +1,481 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 // Kernel
9 // Kernel
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule Kernel
15 * @submodule Kernel
16 */
16 */
17
17
18 var IPython = (function (IPython) {
18 var IPython = (function (IPython) {
19
19
20 var utils = IPython.utils;
20 var utils = IPython.utils;
21
21
22 // Initialization and connection.
22 // Initialization and connection.
23 /**
23 /**
24 * A Kernel Class to communicate with the Python kernel
24 * A Kernel Class to communicate with the Python kernel
25 * @Class Kernel
25 * @Class Kernel
26 */
26 */
27 var Kernel = function (base_url) {
27 var Kernel = function (base_url) {
28 this.kernel_id = null;
28 this.kernel_id = null;
29 this.shell_channel = null;
29 this.shell_channel = null;
30 this.iopub_channel = null;
30 this.iopub_channel = null;
31 this.stdin_channel = null;
31 this.base_url = base_url;
32 this.base_url = base_url;
32 this.running = false;
33 this.running = false;
33 this.username = "username";
34 this.username = "username";
34 this.session_id = utils.uuid();
35 this.session_id = utils.uuid();
35 this._msg_callbacks = {};
36 this._msg_callbacks = {};
36
37
37 if (typeof(WebSocket) !== 'undefined') {
38 if (typeof(WebSocket) !== 'undefined') {
38 this.WebSocket = WebSocket;
39 this.WebSocket = WebSocket;
39 } else if (typeof(MozWebSocket) !== 'undefined') {
40 } else if (typeof(MozWebSocket) !== 'undefined') {
40 this.WebSocket = MozWebSocket;
41 this.WebSocket = MozWebSocket;
41 } else {
42 } else {
42 alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox β‰₯ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
43 alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox β‰₯ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
43 };
44 };
44 };
45 };
45
46
46
47
47 Kernel.prototype._get_msg = function (msg_type, content) {
48 Kernel.prototype._get_msg = function (msg_type, content) {
48 var msg = {
49 var msg = {
49 header : {
50 header : {
50 msg_id : utils.uuid(),
51 msg_id : utils.uuid(),
51 username : this.username,
52 username : this.username,
52 session : this.session_id,
53 session : this.session_id,
53 msg_type : msg_type
54 msg_type : msg_type
54 },
55 },
55 metadata : {},
56 metadata : {},
56 content : content,
57 content : content,
57 parent_header : {}
58 parent_header : {}
58 };
59 };
59 return msg;
60 return msg;
60 };
61 };
61
62
62 /**
63 /**
63 * Start the Python kernel
64 * Start the Python kernel
64 * @method start
65 * @method start
65 */
66 */
66 Kernel.prototype.start = function (notebook_id) {
67 Kernel.prototype.start = function (notebook_id) {
67 var that = this;
68 var that = this;
68 if (!this.running) {
69 if (!this.running) {
69 var qs = $.param({notebook:notebook_id});
70 var qs = $.param({notebook:notebook_id});
70 var url = this.base_url + '?' + qs;
71 var url = this.base_url + '?' + qs;
71 $.post(url,
72 $.post(url,
72 $.proxy(that._kernel_started,that),
73 $.proxy(that._kernel_started,that),
73 'json'
74 'json'
74 );
75 );
75 };
76 };
76 };
77 };
77
78
78 /**
79 /**
79 * Restart the python kernel.
80 * Restart the python kernel.
80 *
81 *
81 * Emit a 'status_restarting.Kernel' event with
82 * Emit a 'status_restarting.Kernel' event with
82 * the current object as parameter
83 * the current object as parameter
83 *
84 *
84 * @method restart
85 * @method restart
85 */
86 */
86 Kernel.prototype.restart = function () {
87 Kernel.prototype.restart = function () {
87 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
88 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
88 var that = this;
89 var that = this;
89 if (this.running) {
90 if (this.running) {
90 this.stop_channels();
91 this.stop_channels();
91 var url = this.kernel_url + "/restart";
92 var url = this.kernel_url + "/restart";
92 $.post(url,
93 $.post(url,
93 $.proxy(that._kernel_started, that),
94 $.proxy(that._kernel_started, that),
94 'json'
95 'json'
95 );
96 );
96 };
97 };
97 };
98 };
98
99
99
100
100 Kernel.prototype._kernel_started = function (json) {
101 Kernel.prototype._kernel_started = function (json) {
101 console.log("Kernel started: ", json.kernel_id);
102 console.log("Kernel started: ", json.kernel_id);
102 this.running = true;
103 this.running = true;
103 this.kernel_id = json.kernel_id;
104 this.kernel_id = json.kernel_id;
104 this.ws_url = json.ws_url;
105 this.ws_url = json.ws_url;
105 this.kernel_url = this.base_url + "/" + this.kernel_id;
106 this.kernel_url = this.base_url + "/" + this.kernel_id;
106 this.start_channels();
107 this.start_channels();
107 $([IPython.events]).trigger('status_started.Kernel', {kernel: this});
108 $([IPython.events]).trigger('status_started.Kernel', {kernel: this});
108 };
109 };
109
110
110
111
111 Kernel.prototype._websocket_closed = function(ws_url, early) {
112 Kernel.prototype._websocket_closed = function(ws_url, early) {
112 this.stop_channels();
113 this.stop_channels();
113 $([IPython.events]).trigger('websocket_closed.Kernel',
114 $([IPython.events]).trigger('websocket_closed.Kernel',
114 {ws_url: ws_url, kernel: this, early: early}
115 {ws_url: ws_url, kernel: this, early: early}
115 );
116 );
116 };
117 };
117
118
118 /**
119 /**
119 * Start the `shell`and `iopub` channels.
120 * Start the `shell`and `iopub` channels.
120 * Will stop and restart them if they already exist.
121 * Will stop and restart them if they already exist.
121 *
122 *
122 * @method start_channels
123 * @method start_channels
123 */
124 */
124 Kernel.prototype.start_channels = function () {
125 Kernel.prototype.start_channels = function () {
125 var that = this;
126 var that = this;
126 this.stop_channels();
127 this.stop_channels();
127 var ws_url = this.ws_url + this.kernel_url;
128 var ws_url = this.ws_url + this.kernel_url;
128 console.log("Starting WebSockets:", ws_url);
129 console.log("Starting WebSockets:", ws_url);
129 this.shell_channel = new this.WebSocket(ws_url + "/shell");
130 this.shell_channel = new this.WebSocket(ws_url + "/shell");
131 this.stdin_channel = new this.WebSocket(ws_url + "/stdin");
130 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
132 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
131 send_cookie = function(){
133 send_cookie = function(){
132 this.send(document.cookie);
134 // send the session id so the Session object Python-side
135 // has the same identity
136 this.send(that.session_id + ':' + document.cookie);
133 };
137 };
134 var already_called_onclose = false; // only alert once
138 var already_called_onclose = false; // only alert once
135 var ws_closed_early = function(evt){
139 var ws_closed_early = function(evt){
136 if (already_called_onclose){
140 if (already_called_onclose){
137 return;
141 return;
138 }
142 }
139 already_called_onclose = true;
143 already_called_onclose = true;
140 if ( ! evt.wasClean ){
144 if ( ! evt.wasClean ){
141 that._websocket_closed(ws_url, true);
145 that._websocket_closed(ws_url, true);
142 }
146 }
143 };
147 };
144 var ws_closed_late = function(evt){
148 var ws_closed_late = function(evt){
145 if (already_called_onclose){
149 if (already_called_onclose){
146 return;
150 return;
147 }
151 }
148 already_called_onclose = true;
152 already_called_onclose = true;
149 if ( ! evt.wasClean ){
153 if ( ! evt.wasClean ){
150 that._websocket_closed(ws_url, false);
154 that._websocket_closed(ws_url, false);
151 }
155 }
152 };
156 };
153 this.shell_channel.onopen = send_cookie;
157 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
154 this.shell_channel.onclose = ws_closed_early;
158 for (var i=0; i < channels.length; i++) {
155 this.iopub_channel.onopen = send_cookie;
159 channels[i].onopen = send_cookie;
156 this.iopub_channel.onclose = ws_closed_early;
160 channels[i].onclose = ws_closed_early;
161 }
157 // switch from early-close to late-close message after 1s
162 // switch from early-close to late-close message after 1s
158 setTimeout(function() {
163 setTimeout(function() {
159 if (that.shell_channel !== null) {
164 for (var i=0; i < channels.length; i++) {
160 that.shell_channel.onclose = ws_closed_late;
165 if (channels[i] !== null) {
166 channels[i].onclose = ws_closed_late;
161 }
167 }
162 if (that.iopub_channel !== null) {
163 that.iopub_channel.onclose = ws_closed_late;
164 }
168 }
165 }, 1000);
169 }, 1000);
166 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this);
170 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
167 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this);
171 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply, this);
172 this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
173
174 $([IPython.events]).on('send_input_reply.Kernel', function(evt, data) {
175 that.send_input_reply(data);
176 });
168 };
177 };
169
178
170 /**
179 /**
171 * Start the `shell`and `iopub` channels.
180 * Start the `shell`and `iopub` channels.
172 * @method stop_channels
181 * @method stop_channels
173 */
182 */
174 Kernel.prototype.stop_channels = function () {
183 Kernel.prototype.stop_channels = function () {
175 if (this.shell_channel !== null) {
184 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
176 this.shell_channel.onclose = function (evt) {};
185 for (var i=0; i < channels.length; i++) {
177 this.shell_channel.close();
186 if ( channels[i] !== null ) {
178 this.shell_channel = null;
187 channels[i].onclose = function (evt) {};
179 };
188 channels[i].close();
180 if (this.iopub_channel !== null) {
189 }
181 this.iopub_channel.onclose = function (evt) {};
182 this.iopub_channel.close();
183 this.iopub_channel = null;
184 };
190 };
191 this.shell_channel = this.iopub_channel = this.stdin_channel = null;
185 };
192 };
186
193
187 // Main public methods.
194 // Main public methods.
188
195
189 /**
196 /**
190 * Get info on object asynchronoulsy
197 * Get info on object asynchronoulsy
191 *
198 *
192 * @async
199 * @async
193 * @param objname {string}
200 * @param objname {string}
194 * @param callback {dict}
201 * @param callback {dict}
195 * @method object_info_request
202 * @method object_info_request
196 *
203 *
197 * @example
204 * @example
198 *
205 *
199 * When calling this method pass a callbacks structure of the form:
206 * When calling this method pass a callbacks structure of the form:
200 *
207 *
201 * callbacks = {
208 * callbacks = {
202 * 'object_info_reply': object_info_reply_callback
209 * 'object_info_reply': object_info_reply_callback
203 * }
210 * }
204 *
211 *
205 * The `object_info_reply_callback` will be passed the content object of the
212 * The `object_info_reply_callback` will be passed the content object of the
206 *
213 *
207 * `object_into_reply` message documented in
214 * `object_into_reply` message documented in
208 * [IPython dev documentation](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
215 * [IPython dev documentation](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
209 */
216 */
210 Kernel.prototype.object_info_request = function (objname, callbacks) {
217 Kernel.prototype.object_info_request = function (objname, callbacks) {
211 if(typeof(objname)!=null && objname!=null)
218 if(typeof(objname)!=null && objname!=null)
212 {
219 {
213 var content = {
220 var content = {
214 oname : objname.toString(),
221 oname : objname.toString(),
215 };
222 };
216 var msg = this._get_msg("object_info_request", content);
223 var msg = this._get_msg("object_info_request", content);
217 this.shell_channel.send(JSON.stringify(msg));
224 this.shell_channel.send(JSON.stringify(msg));
218 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
225 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
219 return msg.header.msg_id;
226 return msg.header.msg_id;
220 }
227 }
221 return;
228 return;
222 }
229 }
223
230
224 /**
231 /**
225 * Execute given code into kernel, and pass result to callback.
232 * Execute given code into kernel, and pass result to callback.
226 *
233 *
227 * @async
234 * @async
228 * @method execute
235 * @method execute
229 * @param {string} code
236 * @param {string} code
230 * @param callback {Object} With the following keys
237 * @param callback {Object} With the following keys
231 * @param callback.'execute_reply' {function}
238 * @param callback.'execute_reply' {function}
232 * @param callback.'output' {function}
239 * @param callback.'output' {function}
233 * @param callback.'clear_output' {function}
240 * @param callback.'clear_output' {function}
234 * @param callback.'set_next_input' {function}
241 * @param callback.'set_next_input' {function}
235 * @param {object} [options]
242 * @param {object} [options]
236 * @param [options.silent=false] {Boolean}
243 * @param [options.silent=false] {Boolean}
237 * @param [options.user_expressions=empty_dict] {Dict}
244 * @param [options.user_expressions=empty_dict] {Dict}
238 * @param [options.user_variables=empty_list] {List od Strings}
245 * @param [options.user_variables=empty_list] {List od Strings}
239 * @param [options.allow_stdin=false] {Boolean} true|false
246 * @param [options.allow_stdin=false] {Boolean} true|false
240 *
247 *
241 * @example
248 * @example
242 *
249 *
243 * The options object should contain the options for the execute call. Its default
250 * The options object should contain the options for the execute call. Its default
244 * values are:
251 * values are:
245 *
252 *
246 * options = {
253 * options = {
247 * silent : true,
254 * silent : true,
248 * user_variables : [],
255 * user_variables : [],
249 * user_expressions : {},
256 * user_expressions : {},
250 * allow_stdin : false
257 * allow_stdin : false
251 * }
258 * }
252 *
259 *
253 * When calling this method pass a callbacks structure of the form:
260 * When calling this method pass a callbacks structure of the form:
254 *
261 *
255 * callbacks = {
262 * callbacks = {
256 * 'execute_reply': execute_reply_callback,
263 * 'execute_reply': execute_reply_callback,
257 * 'output': output_callback,
264 * 'output': output_callback,
258 * 'clear_output': clear_output_callback,
265 * 'clear_output': clear_output_callback,
259 * 'set_next_input': set_next_input_callback
266 * 'set_next_input': set_next_input_callback
260 * }
267 * }
261 *
268 *
262 * The `execute_reply_callback` will be passed the content and metadata
269 * The `execute_reply_callback` will be passed the content and metadata
263 * objects of the `execute_reply` message documented
270 * objects of the `execute_reply` message documented
264 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#execute)
271 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#execute)
265 *
272 *
266 * The `output_callback` will be passed `msg_type` ('stream','display_data','pyout','pyerr')
273 * The `output_callback` will be passed `msg_type` ('stream','display_data','pyout','pyerr')
267 * of the output and the content and metadata objects of the PUB/SUB channel that contains the
274 * of the output and the content and metadata objects of the PUB/SUB channel that contains the
268 * output:
275 * output:
269 *
276 *
270 * http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket
277 * http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket
271 *
278 *
272 * The `clear_output_callback` will be passed a content object that contains
279 * The `clear_output_callback` will be passed a content object that contains
273 * stdout, stderr and other fields that are booleans, as well as the metadata object.
280 * stdout, stderr and other fields that are booleans, as well as the metadata object.
274 *
281 *
275 * The `set_next_input_callback` will be passed the text that should become the next
282 * The `set_next_input_callback` will be passed the text that should become the next
276 * input cell.
283 * input cell.
277 */
284 */
278 Kernel.prototype.execute = function (code, callbacks, options) {
285 Kernel.prototype.execute = function (code, callbacks, options) {
279
286
280 var content = {
287 var content = {
281 code : code,
288 code : code,
282 silent : true,
289 silent : true,
283 user_variables : [],
290 user_variables : [],
284 user_expressions : {},
291 user_expressions : {},
285 allow_stdin : false
292 allow_stdin : false
286 };
293 };
294 if (callbacks.input_request !== undefined) {
295 content.allow_stdin = true;
296 }
287 $.extend(true, content, options)
297 $.extend(true, content, options)
288 $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
298 $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
289 var msg = this._get_msg("execute_request", content);
299 var msg = this._get_msg("execute_request", content);
290 this.shell_channel.send(JSON.stringify(msg));
300 this.shell_channel.send(JSON.stringify(msg));
291 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
301 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
292 return msg.header.msg_id;
302 return msg.header.msg_id;
293 };
303 };
294
304
295 /**
305 /**
296 * When calling this method pass a callbacks structure of the form:
306 * When calling this method pass a callbacks structure of the form:
297 *
307 *
298 * callbacks = {
308 * callbacks = {
299 * 'complete_reply': complete_reply_callback
309 * 'complete_reply': complete_reply_callback
300 * }
310 * }
301 *
311 *
302 * The `complete_reply_callback` will be passed the content object of the
312 * The `complete_reply_callback` will be passed the content object of the
303 * `complete_reply` message documented
313 * `complete_reply` message documented
304 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
314 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
305 *
315 *
306 * @method complete
316 * @method complete
307 * @param line {integer}
317 * @param line {integer}
308 * @param cursor_pos {integer}
318 * @param cursor_pos {integer}
309 * @param {dict} callbacks
319 * @param {dict} callbacks
310 * @param callbacks.complete_reply {function} `complete_reply_callback`
320 * @param callbacks.complete_reply {function} `complete_reply_callback`
311 *
321 *
312 */
322 */
313 Kernel.prototype.complete = function (line, cursor_pos, callbacks) {
323 Kernel.prototype.complete = function (line, cursor_pos, callbacks) {
314 callbacks = callbacks || {};
324 callbacks = callbacks || {};
315 var content = {
325 var content = {
316 text : '',
326 text : '',
317 line : line,
327 line : line,
318 cursor_pos : cursor_pos
328 cursor_pos : cursor_pos
319 };
329 };
320 var msg = this._get_msg("complete_request", content);
330 var msg = this._get_msg("complete_request", content);
321 this.shell_channel.send(JSON.stringify(msg));
331 this.shell_channel.send(JSON.stringify(msg));
322 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
332 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
323 return msg.header.msg_id;
333 return msg.header.msg_id;
324 };
334 };
325
335
326
336
327 Kernel.prototype.interrupt = function () {
337 Kernel.prototype.interrupt = function () {
328 if (this.running) {
338 if (this.running) {
329 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
339 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
330 $.post(this.kernel_url + "/interrupt");
340 $.post(this.kernel_url + "/interrupt");
331 };
341 };
332 };
342 };
333
343
334
344
335 Kernel.prototype.kill = function () {
345 Kernel.prototype.kill = function () {
336 if (this.running) {
346 if (this.running) {
337 this.running = false;
347 this.running = false;
338 var settings = {
348 var settings = {
339 cache : false,
349 cache : false,
340 type : "DELETE"
350 type : "DELETE"
341 };
351 };
342 $.ajax(this.kernel_url, settings);
352 $.ajax(this.kernel_url, settings);
343 };
353 };
344 };
354 };
345
355
356 Kernel.prototype.send_input_reply = function (input) {
357 var content = {
358 value : input,
359 };
360 $([IPython.events]).trigger('input_reply.Kernel', {kernel: this, content:content});
361 var msg = this._get_msg("input_reply", content);
362 this.stdin_channel.send(JSON.stringify(msg));
363 return msg.header.msg_id;
364 };
365
346
366
347 // Reply handlers.
367 // Reply handlers
348
368
349 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
369 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
350 var callbacks = this._msg_callbacks[msg_id];
370 var callbacks = this._msg_callbacks[msg_id];
351 return callbacks;
371 return callbacks;
352 };
372 };
353
373
354
374
355 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
375 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
356 this._msg_callbacks[msg_id] = callbacks || {};
376 this._msg_callbacks[msg_id] = callbacks || {};
357 }
377 }
358
378
359
379
360 Kernel.prototype._handle_shell_reply = function (e) {
380 Kernel.prototype._handle_shell_reply = function (e) {
361 var reply = $.parseJSON(e.data);
381 var reply = $.parseJSON(e.data);
362 $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
382 $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
363 var header = reply.header;
383 var header = reply.header;
364 var content = reply.content;
384 var content = reply.content;
365 var metadata = reply.metadata;
385 var metadata = reply.metadata;
366 var msg_type = header.msg_type;
386 var msg_type = header.msg_type;
367 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
387 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
368 if (callbacks !== undefined) {
388 if (callbacks !== undefined) {
369 var cb = callbacks[msg_type];
389 var cb = callbacks[msg_type];
370 if (cb !== undefined) {
390 if (cb !== undefined) {
371 cb(content, metadata);
391 cb(content, metadata);
372 }
392 }
373 };
393 };
374
394
375 if (content.payload !== undefined) {
395 if (content.payload !== undefined) {
376 var payload = content.payload || [];
396 var payload = content.payload || [];
377 this._handle_payload(callbacks, payload);
397 this._handle_payload(callbacks, payload);
378 }
398 }
379 };
399 };
380
400
381
401
382 Kernel.prototype._handle_payload = function (callbacks, payload) {
402 Kernel.prototype._handle_payload = function (callbacks, payload) {
383 var l = payload.length;
403 var l = payload.length;
384 // Payloads are handled by triggering events because we don't want the Kernel
404 // Payloads are handled by triggering events because we don't want the Kernel
385 // to depend on the Notebook or Pager classes.
405 // to depend on the Notebook or Pager classes.
386 for (var i=0; i<l; i++) {
406 for (var i=0; i<l; i++) {
387 if (payload[i].source === 'IPython.kernel.zmq.page.page') {
407 if (payload[i].source === 'IPython.kernel.zmq.page.page') {
388 var data = {'text':payload[i].text}
408 var data = {'text':payload[i].text}
389 $([IPython.events]).trigger('open_with_text.Pager', data);
409 $([IPython.events]).trigger('open_with_text.Pager', data);
390 } else if (payload[i].source === 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
410 } else if (payload[i].source === 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
391 if (callbacks.set_next_input !== undefined) {
411 if (callbacks.set_next_input !== undefined) {
392 callbacks.set_next_input(payload[i].text)
412 callbacks.set_next_input(payload[i].text)
393 }
413 }
394 }
414 }
395 };
415 };
396 };
416 };
397
417
398
418
399 Kernel.prototype._handle_iopub_reply = function (e) {
419 Kernel.prototype._handle_iopub_reply = function (e) {
400 var reply = $.parseJSON(e.data);
420 var reply = $.parseJSON(e.data);
401 var content = reply.content;
421 var content = reply.content;
402 var msg_type = reply.header.msg_type;
422 var msg_type = reply.header.msg_type;
403 var metadata = reply.metadata;
423 var metadata = reply.metadata;
404 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
424 var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
405 if (msg_type !== 'status' && callbacks === undefined) {
425 if (msg_type !== 'status' && callbacks === undefined) {
406 // Message not from one of this notebook's cells and there are no
426 // Message not from one of this notebook's cells and there are no
407 // callbacks to handle it.
427 // callbacks to handle it.
408 return;
428 return;
409 }
429 }
410 var output_types = ['stream','display_data','pyout','pyerr'];
430 var output_types = ['stream','display_data','pyout','pyerr'];
411 if (output_types.indexOf(msg_type) >= 0) {
431 if (output_types.indexOf(msg_type) >= 0) {
412 var cb = callbacks['output'];
432 var cb = callbacks['output'];
413 if (cb !== undefined) {
433 if (cb !== undefined) {
414 cb(msg_type, content, metadata);
434 cb(msg_type, content, metadata);
415 }
435 }
416 } else if (msg_type === 'status') {
436 } else if (msg_type === 'status') {
417 if (content.execution_state === 'busy') {
437 if (content.execution_state === 'busy') {
418 $([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
438 $([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
419 } else if (content.execution_state === 'idle') {
439 } else if (content.execution_state === 'idle') {
420 $([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
440 $([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
421 } else if (content.execution_state === 'restarting') {
441 } else if (content.execution_state === 'restarting') {
422 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
442 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
423 } else if (content.execution_state === 'dead') {
443 } else if (content.execution_state === 'dead') {
424 this.stop_channels();
444 this.stop_channels();
425 $([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
445 $([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
426 };
446 };
427 } else if (msg_type === 'clear_output') {
447 } else if (msg_type === 'clear_output') {
428 var cb = callbacks['clear_output'];
448 var cb = callbacks['clear_output'];
429 if (cb !== undefined) {
449 if (cb !== undefined) {
430 cb(content, metadata);
450 cb(content, metadata);
431 }
451 }
432 };
452 };
433 };
453 };
434
454
435
455
456 Kernel.prototype._handle_input_request = function (e) {
457 var request = $.parseJSON(e.data);
458 var header = request.header;
459 var content = request.content;
460 var metadata = request.metadata;
461 var msg_type = header.msg_type;
462 if (msg_type !== 'input_request') {
463 console.log("Invalid input request!", request);
464 return;
465 }
466 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
467 if (callbacks !== undefined) {
468 var cb = callbacks[msg_type];
469 if (cb !== undefined) {
470 cb(content, metadata);
471 }
472 };
473 };
474
475
436 IPython.Kernel = Kernel;
476 IPython.Kernel = Kernel;
437
477
438 return IPython;
478 return IPython;
439
479
440 }(IPython));
480 }(IPython));
441
481
@@ -1,557 +1,606 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 // OutputArea
9 // OutputArea
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 var OutputArea = function (selector, prompt_area) {
17 var OutputArea = function (selector, prompt_area) {
18 this.selector = selector;
18 this.selector = selector;
19 this.wrapper = $(selector);
19 this.wrapper = $(selector);
20 this.outputs = [];
20 this.outputs = [];
21 this.collapsed = false;
21 this.collapsed = false;
22 this.scrolled = false;
22 this.scrolled = false;
23 this.clear_out_timeout = null;
23 this.clear_out_timeout = null;
24 if (prompt_area === undefined) {
24 if (prompt_area === undefined) {
25 this.prompt_area = true;
25 this.prompt_area = true;
26 } else {
26 } else {
27 this.prompt_area = prompt_area;
27 this.prompt_area = prompt_area;
28 }
28 }
29 this.create_elements();
29 this.create_elements();
30 this.style();
30 this.style();
31 this.bind_events();
31 this.bind_events();
32 };
32 };
33
33
34 OutputArea.prototype.create_elements = function () {
34 OutputArea.prototype.create_elements = function () {
35 this.element = $("<div/>");
35 this.element = $("<div/>");
36 this.collapse_button = $("<div/>");
36 this.collapse_button = $("<div/>");
37 this.prompt_overlay = $("<div/>");
37 this.prompt_overlay = $("<div/>");
38 this.wrapper.append(this.prompt_overlay);
38 this.wrapper.append(this.prompt_overlay);
39 this.wrapper.append(this.element);
39 this.wrapper.append(this.element);
40 this.wrapper.append(this.collapse_button);
40 this.wrapper.append(this.collapse_button);
41 };
41 };
42
42
43
43
44 OutputArea.prototype.style = function () {
44 OutputArea.prototype.style = function () {
45 this.collapse_button.hide();
45 this.collapse_button.hide();
46 this.prompt_overlay.hide();
46 this.prompt_overlay.hide();
47
47
48 this.wrapper.addClass('output_wrapper');
48 this.wrapper.addClass('output_wrapper');
49 this.element.addClass('output vbox');
49 this.element.addClass('output vbox');
50
50
51 this.collapse_button.button();
51 this.collapse_button.button();
52 this.collapse_button.addClass('output_collapsed vbox');
52 this.collapse_button.addClass('output_collapsed vbox');
53 this.collapse_button.attr('title', 'click to expand output');
53 this.collapse_button.attr('title', 'click to expand output');
54 this.collapse_button.html('. . .');
54 this.collapse_button.html('. . .');
55
55
56 this.prompt_overlay.addClass('out_prompt_overlay prompt');
56 this.prompt_overlay.addClass('out_prompt_overlay prompt');
57 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
57 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
58
58
59 this.collapse();
59 this.collapse();
60 };
60 };
61
61
62
62
63 OutputArea.prototype._should_scroll = function (lines) {
63 OutputArea.prototype._should_scroll = function (lines) {
64 if (!lines) {
64 if (!lines) {
65 lines = 100;
65 lines = 100;
66 }
66 }
67 // line-height from http://stackoverflow.com/questions/1185151
67 // line-height from http://stackoverflow.com/questions/1185151
68 var fontSize = this.element.css('font-size');
68 var fontSize = this.element.css('font-size');
69 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
69 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
70
70
71 return (this.element.height() > lines * lineHeight);
71 return (this.element.height() > lines * lineHeight);
72 };
72 };
73
73
74
74
75 OutputArea.prototype.bind_events = function () {
75 OutputArea.prototype.bind_events = function () {
76 var that = this;
76 var that = this;
77 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
77 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
78 this.prompt_overlay.click(function () { that.toggle_scroll(); });
78 this.prompt_overlay.click(function () { that.toggle_scroll(); });
79
79
80 this.element.resize(function () {
80 this.element.resize(function () {
81 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
81 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
82 if ( IPython.utils.browser[0] === "Firefox" ) {
82 if ( IPython.utils.browser[0] === "Firefox" ) {
83 return;
83 return;
84 }
84 }
85 // maybe scroll output,
85 // maybe scroll output,
86 // if it's grown large enough and hasn't already been scrolled.
86 // if it's grown large enough and hasn't already been scrolled.
87 if ( !that.scrolled && that._should_scroll()) {
87 if ( !that.scrolled && that._should_scroll()) {
88 that.scroll_area();
88 that.scroll_area();
89 }
89 }
90 });
90 });
91 this.collapse_button.click(function () {
91 this.collapse_button.click(function () {
92 that.expand();
92 that.expand();
93 });
93 });
94 this.collapse_button.hover(function () {
94 this.collapse_button.hover(function () {
95 $(this).addClass("ui-state-hover");
95 $(this).addClass("ui-state-hover");
96 }, function () {
96 }, function () {
97 $(this).removeClass("ui-state-hover");
97 $(this).removeClass("ui-state-hover");
98 });
98 });
99 };
99 };
100
100
101
101
102 OutputArea.prototype.collapse = function () {
102 OutputArea.prototype.collapse = function () {
103 if (!this.collapsed) {
103 if (!this.collapsed) {
104 this.element.hide();
104 this.element.hide();
105 this.prompt_overlay.hide();
105 this.prompt_overlay.hide();
106 if (this.element.html()){
106 if (this.element.html()){
107 this.collapse_button.show();
107 this.collapse_button.show();
108 }
108 }
109 this.collapsed = true;
109 this.collapsed = true;
110 }
110 }
111 };
111 };
112
112
113
113
114 OutputArea.prototype.expand = function () {
114 OutputArea.prototype.expand = function () {
115 if (this.collapsed) {
115 if (this.collapsed) {
116 this.collapse_button.hide();
116 this.collapse_button.hide();
117 this.element.show();
117 this.element.show();
118 this.prompt_overlay.show();
118 this.prompt_overlay.show();
119 this.collapsed = false;
119 this.collapsed = false;
120 }
120 }
121 };
121 };
122
122
123
123
124 OutputArea.prototype.toggle_output = function () {
124 OutputArea.prototype.toggle_output = function () {
125 if (this.collapsed) {
125 if (this.collapsed) {
126 this.expand();
126 this.expand();
127 } else {
127 } else {
128 this.collapse();
128 this.collapse();
129 }
129 }
130 };
130 };
131
131
132
132
133 OutputArea.prototype.scroll_area = function () {
133 OutputArea.prototype.scroll_area = function () {
134 this.element.addClass('output_scroll');
134 this.element.addClass('output_scroll');
135 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
135 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
136 this.scrolled = true;
136 this.scrolled = true;
137 };
137 };
138
138
139
139
140 OutputArea.prototype.unscroll_area = function () {
140 OutputArea.prototype.unscroll_area = function () {
141 this.element.removeClass('output_scroll');
141 this.element.removeClass('output_scroll');
142 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
142 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
143 this.scrolled = false;
143 this.scrolled = false;
144 };
144 };
145
145
146
146
147 OutputArea.prototype.scroll_if_long = function (lines) {
147 OutputArea.prototype.scroll_if_long = function (lines) {
148 if (this._should_scroll(lines)) {
148 if (this._should_scroll(lines)) {
149 // only allow scrolling long-enough output
149 // only allow scrolling long-enough output
150 this.scroll_area();
150 this.scroll_area();
151 }
151 }
152 };
152 };
153
153
154
154
155 OutputArea.prototype.toggle_scroll = function () {
155 OutputArea.prototype.toggle_scroll = function () {
156 if (this.scrolled) {
156 if (this.scrolled) {
157 this.unscroll_area();
157 this.unscroll_area();
158 } else {
158 } else {
159 // only allow scrolling long-enough output
159 // only allow scrolling long-enough output
160 this.scroll_if_long(20);
160 this.scroll_if_long(20);
161 }
161 }
162 };
162 };
163
163
164
164
165 // typeset with MathJax if MathJax is available
165 // typeset with MathJax if MathJax is available
166 OutputArea.prototype.typeset = function () {
166 OutputArea.prototype.typeset = function () {
167 if (window.MathJax){
167 if (window.MathJax){
168 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
168 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
169 }
169 }
170 };
170 };
171
171
172
172
173 OutputArea.prototype.handle_output = function (msg_type, content) {
173 OutputArea.prototype.handle_output = function (msg_type, content) {
174 var json = {};
174 var json = {};
175 json.output_type = msg_type;
175 json.output_type = msg_type;
176 if (msg_type === "stream") {
176 if (msg_type === "stream") {
177 json.text = content.data;
177 json.text = content.data;
178 json.stream = content.name;
178 json.stream = content.name;
179 } else if (msg_type === "display_data") {
179 } else if (msg_type === "display_data") {
180 json = this.convert_mime_types(json, content.data);
180 json = this.convert_mime_types(json, content.data);
181 } else if (msg_type === "pyout") {
181 } else if (msg_type === "pyout") {
182 json.prompt_number = content.execution_count;
182 json.prompt_number = content.execution_count;
183 json = this.convert_mime_types(json, content.data);
183 json = this.convert_mime_types(json, content.data);
184 } else if (msg_type === "pyerr") {
184 } else if (msg_type === "pyerr") {
185 json.ename = content.ename;
185 json.ename = content.ename;
186 json.evalue = content.evalue;
186 json.evalue = content.evalue;
187 json.traceback = content.traceback;
187 json.traceback = content.traceback;
188 }
188 }
189 // append with dynamic=true
189 // append with dynamic=true
190 this.append_output(json, true);
190 this.append_output(json, true);
191 };
191 };
192
192
193
193
194 OutputArea.prototype.convert_mime_types = function (json, data) {
194 OutputArea.prototype.convert_mime_types = function (json, data) {
195 if (data['text/plain'] !== undefined) {
195 if (data['text/plain'] !== undefined) {
196 json.text = data['text/plain'];
196 json.text = data['text/plain'];
197 }
197 }
198 if (data['text/html'] !== undefined) {
198 if (data['text/html'] !== undefined) {
199 json.html = data['text/html'];
199 json.html = data['text/html'];
200 }
200 }
201 if (data['image/svg+xml'] !== undefined) {
201 if (data['image/svg+xml'] !== undefined) {
202 json.svg = data['image/svg+xml'];
202 json.svg = data['image/svg+xml'];
203 }
203 }
204 if (data['image/png'] !== undefined) {
204 if (data['image/png'] !== undefined) {
205 json.png = data['image/png'];
205 json.png = data['image/png'];
206 }
206 }
207 if (data['image/jpeg'] !== undefined) {
207 if (data['image/jpeg'] !== undefined) {
208 json.jpeg = data['image/jpeg'];
208 json.jpeg = data['image/jpeg'];
209 }
209 }
210 if (data['text/latex'] !== undefined) {
210 if (data['text/latex'] !== undefined) {
211 json.latex = data['text/latex'];
211 json.latex = data['text/latex'];
212 }
212 }
213 if (data['application/json'] !== undefined) {
213 if (data['application/json'] !== undefined) {
214 json.json = data['application/json'];
214 json.json = data['application/json'];
215 }
215 }
216 if (data['application/javascript'] !== undefined) {
216 if (data['application/javascript'] !== undefined) {
217 json.javascript = data['application/javascript'];
217 json.javascript = data['application/javascript'];
218 }
218 }
219 return json;
219 return json;
220 };
220 };
221
221
222
222
223 OutputArea.prototype.append_output = function (json, dynamic) {
223 OutputArea.prototype.append_output = function (json, dynamic) {
224 // If dynamic is true, javascript output will be eval'd.
224 // If dynamic is true, javascript output will be eval'd.
225 this.expand();
225 this.expand();
226 this.flush_clear_timeout();
226 this.flush_clear_timeout();
227 if (json.output_type === 'pyout') {
227 if (json.output_type === 'pyout') {
228 this.append_pyout(json, dynamic);
228 this.append_pyout(json, dynamic);
229 } else if (json.output_type === 'pyerr') {
229 } else if (json.output_type === 'pyerr') {
230 this.append_pyerr(json);
230 this.append_pyerr(json);
231 } else if (json.output_type === 'display_data') {
231 } else if (json.output_type === 'display_data') {
232 this.append_display_data(json, dynamic);
232 this.append_display_data(json, dynamic);
233 } else if (json.output_type === 'stream') {
233 } else if (json.output_type === 'stream') {
234 this.append_stream(json);
234 this.append_stream(json);
235 }
235 }
236 this.outputs.push(json);
236 this.outputs.push(json);
237 var that = this;
237 var that = this;
238 setTimeout(function(){that.element.trigger('resize');}, 100);
238 setTimeout(function(){that.element.trigger('resize');}, 100);
239 };
239 };
240
240
241
241
242 OutputArea.prototype.create_output_area = function () {
242 OutputArea.prototype.create_output_area = function () {
243 var oa = $("<div/>").addClass("output_area");
243 var oa = $("<div/>").addClass("output_area");
244 if (this.prompt_area) {
244 if (this.prompt_area) {
245 oa.append($('<div/>').addClass('prompt'));
245 oa.append($('<div/>').addClass('prompt'));
246 }
246 }
247 return oa;
247 return oa;
248 };
248 };
249
249
250
250
251 OutputArea.prototype.append_pyout = function (json, dynamic) {
251 OutputArea.prototype.append_pyout = function (json, dynamic) {
252 var n = json.prompt_number || ' ';
252 var n = json.prompt_number || ' ';
253 var toinsert = this.create_output_area();
253 var toinsert = this.create_output_area();
254 if (this.prompt_area) {
254 if (this.prompt_area) {
255 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
255 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
256 }
256 }
257 this.append_mime_type(json, toinsert, dynamic);
257 this.append_mime_type(json, toinsert, dynamic);
258 this.element.append(toinsert);
258 this.element.append(toinsert);
259 // If we just output latex, typeset it.
259 // If we just output latex, typeset it.
260 if ((json.latex !== undefined) || (json.html !== undefined)) {
260 if ((json.latex !== undefined) || (json.html !== undefined)) {
261 this.typeset();
261 this.typeset();
262 }
262 }
263 };
263 };
264
264
265
265
266 OutputArea.prototype.append_pyerr = function (json) {
266 OutputArea.prototype.append_pyerr = function (json) {
267 var tb = json.traceback;
267 var tb = json.traceback;
268 if (tb !== undefined && tb.length > 0) {
268 if (tb !== undefined && tb.length > 0) {
269 var s = '';
269 var s = '';
270 var len = tb.length;
270 var len = tb.length;
271 for (var i=0; i<len; i++) {
271 for (var i=0; i<len; i++) {
272 s = s + tb[i] + '\n';
272 s = s + tb[i] + '\n';
273 }
273 }
274 s = s + '\n';
274 s = s + '\n';
275 var toinsert = this.create_output_area();
275 var toinsert = this.create_output_area();
276 this.append_text(s, toinsert);
276 this.append_text(s, toinsert);
277 this.element.append(toinsert);
277 this.element.append(toinsert);
278 }
278 }
279 };
279 };
280
280
281
281
282 OutputArea.prototype.append_stream = function (json) {
282 OutputArea.prototype.append_stream = function (json) {
283 // temporary fix: if stream undefined (json file written prior to this patch),
283 // temporary fix: if stream undefined (json file written prior to this patch),
284 // default to most likely stdout:
284 // default to most likely stdout:
285 if (json.stream == undefined){
285 if (json.stream == undefined){
286 json.stream = 'stdout';
286 json.stream = 'stdout';
287 }
287 }
288 var text = json.text;
288 var text = json.text;
289 var subclass = "output_"+json.stream;
289 var subclass = "output_"+json.stream;
290 if (this.outputs.length > 0){
290 if (this.outputs.length > 0){
291 // have at least one output to consider
291 // have at least one output to consider
292 var last = this.outputs[this.outputs.length-1];
292 var last = this.outputs[this.outputs.length-1];
293 if (last.output_type == 'stream' && json.stream == last.stream){
293 if (last.output_type == 'stream' && json.stream == last.stream){
294 // latest output was in the same stream,
294 // latest output was in the same stream,
295 // so append directly into its pre tag
295 // so append directly into its pre tag
296 // escape ANSI & HTML specials:
296 // escape ANSI & HTML specials:
297 var pre = this.element.find('div.'+subclass).last().find('pre');
297 var pre = this.element.find('div.'+subclass).last().find('pre');
298 var html = utils.fixCarriageReturn(
298 var html = utils.fixCarriageReturn(
299 pre.html() + utils.fixConsole(text));
299 pre.html() + utils.fixConsole(text));
300 pre.html(html);
300 pre.html(html);
301 return;
301 return;
302 }
302 }
303 }
303 }
304
304
305 if (!text.replace("\r", "")) {
305 if (!text.replace("\r", "")) {
306 // text is nothing (empty string, \r, etc.)
306 // text is nothing (empty string, \r, etc.)
307 // so don't append any elements, which might add undesirable space
307 // so don't append any elements, which might add undesirable space
308 return;
308 return;
309 }
309 }
310
310
311 // If we got here, attach a new div
311 // If we got here, attach a new div
312 var toinsert = this.create_output_area();
312 var toinsert = this.create_output_area();
313 this.append_text(text, toinsert, "output_stream "+subclass);
313 this.append_text(text, toinsert, "output_stream "+subclass);
314 this.element.append(toinsert);
314 this.element.append(toinsert);
315 };
315 };
316
316
317
317
318 OutputArea.prototype.append_display_data = function (json, dynamic) {
318 OutputArea.prototype.append_display_data = function (json, dynamic) {
319 var toinsert = this.create_output_area();
319 var toinsert = this.create_output_area();
320 this.append_mime_type(json, toinsert, dynamic);
320 this.append_mime_type(json, toinsert, dynamic);
321 this.element.append(toinsert);
321 this.element.append(toinsert);
322 // If we just output latex, typeset it.
322 // If we just output latex, typeset it.
323 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
323 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
324 this.typeset();
324 this.typeset();
325 }
325 }
326 };
326 };
327
327
328 OutputArea.display_order = ['javascript','latex','svg','png','jpeg','text'];
328 OutputArea.display_order = ['javascript','latex','svg','png','jpeg','text'];
329
329
330 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
330 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
331 for(var type_i in OutputArea.display_order){
331 for(var type_i in OutputArea.display_order){
332 var type = OutputArea.display_order[type_i];
332 var type = OutputArea.display_order[type_i];
333 if(json[type] != undefined ){
333 if(json[type] != undefined ){
334 if(type == 'javascript'){
334 if(type == 'javascript'){
335 if (dynamic) {
335 if (dynamic) {
336 this.append_javascript(json.javascript, element, dynamic);
336 this.append_javascript(json.javascript, element, dynamic);
337 }
337 }
338 } else {
338 } else {
339 this['append_'+type](json[type], element);
339 this['append_'+type](json[type], element);
340 }
340 }
341 return;
341 return;
342 }
342 }
343 }
343 }
344 };
344 };
345
345
346
346
347 OutputArea.prototype.append_html = function (html, element) {
347 OutputArea.prototype.append_html = function (html, element) {
348 var toinsert = $("<div/>").addClass("output_subarea output_html rendered_html");
348 var toinsert = $("<div/>").addClass("output_subarea output_html rendered_html");
349 toinsert.append(html);
349 toinsert.append(html);
350 element.append(toinsert);
350 element.append(toinsert);
351 };
351 };
352
352
353
353
354 OutputArea.prototype.append_javascript = function (js, container) {
354 OutputArea.prototype.append_javascript = function (js, container) {
355 // We just eval the JS code, element appears in the local scope.
355 // We just eval the JS code, element appears in the local scope.
356 var element = $("<div/>").addClass("output_subarea");
356 var element = $("<div/>").addClass("output_subarea");
357 container.append(element);
357 container.append(element);
358 // Div for js shouldn't be drawn, as it will add empty height to the area.
358 // Div for js shouldn't be drawn, as it will add empty height to the area.
359 container.hide();
359 container.hide();
360 // If the Javascript appends content to `element` that should be drawn, then
360 // If the Javascript appends content to `element` that should be drawn, then
361 // it must also call `container.show()`.
361 // it must also call `container.show()`.
362 try {
362 try {
363 eval(js);
363 eval(js);
364 } catch(err) {
364 } catch(err) {
365 console.log('Error in Javascript!');
365 console.log('Error in Javascript!');
366 console.log(err);
366 console.log(err);
367 container.show();
367 container.show();
368 element.append($('<div/>')
368 element.append($('<div/>')
369 .html("Error in Javascript !<br/>"+
369 .html("Error in Javascript !<br/>"+
370 err.toString()+
370 err.toString()+
371 '<br/>See your browser Javascript console for more details.')
371 '<br/>See your browser Javascript console for more details.')
372 .addClass('js-error')
372 .addClass('js-error')
373 );
373 );
374 }
374 }
375 };
375 };
376
376
377
377
378 OutputArea.prototype.append_text = function (data, element, extra_class) {
378 OutputArea.prototype.append_text = function (data, element, extra_class) {
379 var toinsert = $("<div/>").addClass("output_subarea output_text");
379 var toinsert = $("<div/>").addClass("output_subarea output_text");
380 // escape ANSI & HTML specials in plaintext:
380 // escape ANSI & HTML specials in plaintext:
381 data = utils.fixConsole(data);
381 data = utils.fixConsole(data);
382 data = utils.fixCarriageReturn(data);
382 data = utils.fixCarriageReturn(data);
383 data = utils.autoLinkUrls(data);
383 data = utils.autoLinkUrls(data);
384 if (extra_class){
384 if (extra_class){
385 toinsert.addClass(extra_class);
385 toinsert.addClass(extra_class);
386 }
386 }
387 toinsert.append($("<pre/>").html(data));
387 toinsert.append($("<pre/>").html(data));
388 element.append(toinsert);
388 element.append(toinsert);
389 };
389 };
390
390
391
391
392 OutputArea.prototype.append_svg = function (svg, element) {
392 OutputArea.prototype.append_svg = function (svg, element) {
393 var toinsert = $("<div/>").addClass("output_subarea output_svg");
393 var toinsert = $("<div/>").addClass("output_subarea output_svg");
394 toinsert.append(svg);
394 toinsert.append(svg);
395 element.append(toinsert);
395 element.append(toinsert);
396 };
396 };
397
397
398
398
399 OutputArea.prototype._dblclick_to_reset_size = function (img) {
399 OutputArea.prototype._dblclick_to_reset_size = function (img) {
400 // schedule wrapping image in resizable after a delay,
400 // schedule wrapping image in resizable after a delay,
401 // so we don't end up calling resize on a zero-size object
401 // so we don't end up calling resize on a zero-size object
402 var that = this;
402 var that = this;
403 setTimeout(function () {
403 setTimeout(function () {
404 var h0 = img.height();
404 var h0 = img.height();
405 var w0 = img.width();
405 var w0 = img.width();
406 if (!(h0 && w0)) {
406 if (!(h0 && w0)) {
407 // zero size, schedule another timeout
407 // zero size, schedule another timeout
408 that._dblclick_to_reset_size(img);
408 that._dblclick_to_reset_size(img);
409 return;
409 return;
410 }
410 }
411 img.resizable({
411 img.resizable({
412 aspectRatio: true,
412 aspectRatio: true,
413 autoHide: true
413 autoHide: true
414 });
414 });
415 img.dblclick(function () {
415 img.dblclick(function () {
416 // resize wrapper & image together for some reason:
416 // resize wrapper & image together for some reason:
417 img.parent().height(h0);
417 img.parent().height(h0);
418 img.height(h0);
418 img.height(h0);
419 img.parent().width(w0);
419 img.parent().width(w0);
420 img.width(w0);
420 img.width(w0);
421 });
421 });
422 }, 250);
422 }, 250);
423 };
423 };
424
424
425
425
426 OutputArea.prototype.append_png = function (png, element) {
426 OutputArea.prototype.append_png = function (png, element) {
427 var toinsert = $("<div/>").addClass("output_subarea output_png");
427 var toinsert = $("<div/>").addClass("output_subarea output_png");
428 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
428 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
429 this._dblclick_to_reset_size(img);
429 this._dblclick_to_reset_size(img);
430 toinsert.append(img);
430 toinsert.append(img);
431 element.append(toinsert);
431 element.append(toinsert);
432 };
432 };
433
433
434
434
435 OutputArea.prototype.append_jpeg = function (jpeg, element) {
435 OutputArea.prototype.append_jpeg = function (jpeg, element) {
436 var toinsert = $("<div/>").addClass("output_subarea output_jpeg");
436 var toinsert = $("<div/>").addClass("output_subarea output_jpeg");
437 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
437 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
438 this._dblclick_to_reset_size(img);
438 this._dblclick_to_reset_size(img);
439 toinsert.append(img);
439 toinsert.append(img);
440 element.append(toinsert);
440 element.append(toinsert);
441 };
441 };
442
442
443
443
444 OutputArea.prototype.append_latex = function (latex, element) {
444 OutputArea.prototype.append_latex = function (latex, element) {
445 // This method cannot do the typesetting because the latex first has to
445 // This method cannot do the typesetting because the latex first has to
446 // be on the page.
446 // be on the page.
447 var toinsert = $("<div/>").addClass("output_subarea output_latex");
447 var toinsert = $("<div/>").addClass("output_subarea output_latex");
448 toinsert.append(latex);
448 toinsert.append(latex);
449 element.append(toinsert);
449 element.append(toinsert);
450 };
450 };
451
451
452 OutputArea.prototype.append_raw_input = function (content) {
453 var that = this;
454 this.expand();
455 this.flush_clear_timeout();
456 var area = this.create_output_area();
457
458 area.append(
459 $("<div/>")
460 .addClass("box-flex1 output_subarea raw_input")
461 .append(
462 $("<span/>")
463 .addClass("input_prompt")
464 .text(content.prompt)
465 )
466 .append(
467 $("<input/>")
468 .addClass("raw_input")
469 .attr('type', 'text')
470 .attr("size", 80)
471 .keydown(function (event, ui) {
472 // make sure we submit on enter,
473 // and don't re-execute the *cell* on shift-enter
474 if (event.which === utils.keycodes.ENTER) {
475 that._submit_raw_input();
476 return false;
477 }
478 })
479 )
480 );
481 this.element.append(area);
482 area.find("input.raw_input").focus();
483 }
484 OutputArea.prototype._submit_raw_input = function (evt) {
485 var container = this.element.find("div.raw_input");
486 var theprompt = container.find("span.input_prompt");
487 var theinput = container.find("input.raw_input");
488 var value = theinput.attr("value");
489 var content = {
490 output_type : 'stream',
491 name : 'stdout',
492 text : theprompt.text() + value + '\n'
493 }
494 // remove form container
495 container.parent().remove();
496 // replace with plaintext version in stdout
497 this.append_output(content, false);
498 $([IPython.events]).trigger('send_input_reply.Kernel', value);
499 }
500
452
501
453 OutputArea.prototype.handle_clear_output = function (content) {
502 OutputArea.prototype.handle_clear_output = function (content) {
454 this.clear_output(content.stdout, content.stderr, content.other);
503 this.clear_output(content.stdout, content.stderr, content.other);
455 };
504 };
456
505
457
506
458 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
507 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
459 var that = this;
508 var that = this;
460 if (this.clear_out_timeout != null){
509 if (this.clear_out_timeout != null){
461 // fire previous pending clear *immediately*
510 // fire previous pending clear *immediately*
462 clearTimeout(this.clear_out_timeout);
511 clearTimeout(this.clear_out_timeout);
463 this.clear_out_timeout = null;
512 this.clear_out_timeout = null;
464 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
513 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
465 }
514 }
466 // store flags for flushing the timeout
515 // store flags for flushing the timeout
467 this._clear_stdout = stdout;
516 this._clear_stdout = stdout;
468 this._clear_stderr = stderr;
517 this._clear_stderr = stderr;
469 this._clear_other = other;
518 this._clear_other = other;
470 this.clear_out_timeout = setTimeout(function() {
519 this.clear_out_timeout = setTimeout(function() {
471 // really clear timeout only after a short delay
520 // really clear timeout only after a short delay
472 // this reduces flicker in 'clear_output; print' cases
521 // this reduces flicker in 'clear_output; print' cases
473 that.clear_out_timeout = null;
522 that.clear_out_timeout = null;
474 that._clear_stdout = that._clear_stderr = that._clear_other = null;
523 that._clear_stdout = that._clear_stderr = that._clear_other = null;
475 that.clear_output_callback(stdout, stderr, other);
524 that.clear_output_callback(stdout, stderr, other);
476 }, 500
525 }, 500
477 );
526 );
478 };
527 };
479
528
480
529
481 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
530 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
482 var output_div = this.element;
531 var output_div = this.element;
483
532
484 if (stdout && stderr && other){
533 if (stdout && stderr && other){
485 // clear all, no need for logic
534 // clear all, no need for logic
486 output_div.html("");
535 output_div.html("");
487 this.outputs = [];
536 this.outputs = [];
488 this.unscroll_area();
537 this.unscroll_area();
489 return;
538 return;
490 }
539 }
491 // remove html output
540 // remove html output
492 // each output_subarea that has an identifying class is in an output_area
541 // each output_subarea that has an identifying class is in an output_area
493 // which is the element to be removed.
542 // which is the element to be removed.
494 if (stdout) {
543 if (stdout) {
495 output_div.find("div.output_stdout").parent().remove();
544 output_div.find("div.output_stdout").parent().remove();
496 }
545 }
497 if (stderr) {
546 if (stderr) {
498 output_div.find("div.output_stderr").parent().remove();
547 output_div.find("div.output_stderr").parent().remove();
499 }
548 }
500 if (other) {
549 if (other) {
501 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
550 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
502 }
551 }
503 this.unscroll_area();
552 this.unscroll_area();
504
553
505 // remove cleared outputs from JSON list:
554 // remove cleared outputs from JSON list:
506 for (var i = this.outputs.length - 1; i >= 0; i--) {
555 for (var i = this.outputs.length - 1; i >= 0; i--) {
507 var out = this.outputs[i];
556 var out = this.outputs[i];
508 var output_type = out.output_type;
557 var output_type = out.output_type;
509 if (output_type == "display_data" && other) {
558 if (output_type == "display_data" && other) {
510 this.outputs.splice(i,1);
559 this.outputs.splice(i,1);
511 } else if (output_type == "stream") {
560 } else if (output_type == "stream") {
512 if (stdout && out.stream == "stdout") {
561 if (stdout && out.stream == "stdout") {
513 this.outputs.splice(i,1);
562 this.outputs.splice(i,1);
514 } else if (stderr && out.stream == "stderr") {
563 } else if (stderr && out.stream == "stderr") {
515 this.outputs.splice(i,1);
564 this.outputs.splice(i,1);
516 }
565 }
517 }
566 }
518 }
567 }
519 };
568 };
520
569
521
570
522 OutputArea.prototype.flush_clear_timeout = function() {
571 OutputArea.prototype.flush_clear_timeout = function() {
523 var output_div = this.element;
572 var output_div = this.element;
524 if (this.clear_out_timeout){
573 if (this.clear_out_timeout){
525 clearTimeout(this.clear_out_timeout);
574 clearTimeout(this.clear_out_timeout);
526 this.clear_out_timeout = null;
575 this.clear_out_timeout = null;
527 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
576 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
528 }
577 }
529 };
578 };
530
579
531
580
532 // JSON serialization
581 // JSON serialization
533
582
534 OutputArea.prototype.fromJSON = function (outputs) {
583 OutputArea.prototype.fromJSON = function (outputs) {
535 var len = outputs.length;
584 var len = outputs.length;
536 for (var i=0; i<len; i++) {
585 for (var i=0; i<len; i++) {
537 // append with dynamic=false.
586 // append with dynamic=false.
538 this.append_output(outputs[i], false);
587 this.append_output(outputs[i], false);
539 }
588 }
540 };
589 };
541
590
542
591
543 OutputArea.prototype.toJSON = function () {
592 OutputArea.prototype.toJSON = function () {
544 var outputs = [];
593 var outputs = [];
545 var len = this.outputs.length;
594 var len = this.outputs.length;
546 for (var i=0; i<len; i++) {
595 for (var i=0; i<len; i++) {
547 outputs[i] = this.outputs[i];
596 outputs[i] = this.outputs[i];
548 }
597 }
549 return outputs;
598 return outputs;
550 };
599 };
551
600
552
601
553 IPython.OutputArea = OutputArea;
602 IPython.OutputArea = OutputArea;
554
603
555 return IPython;
604 return IPython;
556
605
557 }(IPython));
606 }(IPython));
@@ -1,479 +1,502 b''
1 /**
1 /**
2 * Primary styles
2 * Primary styles
3 *
3 *
4 * Author: IPython Development Team
4 * Author: IPython Development Team
5 */
5 */
6
6
7 @import "variables.less";
7 @import "variables.less";
8
8
9
9
10 body {
10 body {
11 background-color:@notebook_background;
11 background-color:@notebook_background;
12 }
12 }
13
13
14 body.notebook_app {
14 body.notebook_app {
15 overflow: hidden;
15 overflow: hidden;
16 }
16 }
17
17
18 blockquote {
18 blockquote {
19 border-left: 4px solid #DDD;
19 border-left: 4px solid #DDD;
20 padding: 0 15px;
20 padding: 0 15px;
21 color: #777;
21 color: #777;
22 }
22 }
23
23
24 span#save_widget {
24 span#save_widget {
25 padding: 5px;
25 padding: 5px;
26 margin: 0px 0px 0px 300px;
26 margin: 0px 0px 0px 300px;
27 display:inline-block;
27 display:inline-block;
28 }
28 }
29
29
30 span#notebook_name {
30 span#notebook_name {
31 height: 1em;
31 height: 1em;
32 line-height: 1em;
32 line-height: 1em;
33 padding: 3px;
33 padding: 3px;
34 border: none;
34 border: none;
35 font-size: 146.5%;
35 font-size: 146.5%;
36 }
36 }
37
37
38
38
39 .ui-menubar-item .ui-button .ui-button-text {
39 .ui-menubar-item .ui-button .ui-button-text {
40 padding: 0.4em 1.0em;
40 padding: 0.4em 1.0em;
41 font-size: 100%;
41 font-size: 100%;
42 }
42 }
43
43
44 .ui-menu {
44 .ui-menu {
45 -moz-box-shadow: 0px 6px 10px -1px #adadad;
45 -moz-box-shadow: 0px 6px 10px -1px #adadad;
46 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
46 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
47 box-shadow: 0px 6px 10px -1px #adadad;
47 box-shadow: 0px 6px 10px -1px #adadad;
48 }
48 }
49
49
50 .ui-menu .ui-menu-item a {
50 .ui-menu .ui-menu-item a {
51 border: 1px solid transparent;
51 border: 1px solid transparent;
52 padding: 2px 1.6em;
52 padding: 2px 1.6em;
53 }
53 }
54
54
55 .ui-menu .ui-menu-item a.ui-state-focus {
55 .ui-menu .ui-menu-item a.ui-state-focus {
56 margin: 0;
56 margin: 0;
57 }
57 }
58
58
59 .ui-menu hr {
59 .ui-menu hr {
60 margin: 0.3em 0;
60 margin: 0.3em 0;
61 }
61 }
62
62
63 #menubar_container {
63 #menubar_container {
64 position: relative;
64 position: relative;
65 }
65 }
66
66
67 #notification_area {
67 #notification_area {
68 position: absolute;
68 position: absolute;
69 right: 0px;
69 right: 0px;
70 top: 0px;
70 top: 0px;
71 height: 25px;
71 height: 25px;
72 padding: 3px 0px;
72 padding: 3px 0px;
73 padding-right: 3px;
73 padding-right: 3px;
74 z-index: 10;
74 z-index: 10;
75 }
75 }
76
76
77 .notification_widget{
77 .notification_widget{
78 float : right;
78 float : right;
79 right: 0px;
79 right: 0px;
80 top: 1px;
80 top: 1px;
81 height: 25px;
81 height: 25px;
82 padding: 3px 6px;
82 padding: 3px 6px;
83 z-index: 10;
83 z-index: 10;
84 }
84 }
85
85
86 .toolbar {
86 .toolbar {
87 padding: 3px 15px;
87 padding: 3px 15px;
88 border-bottom: @borderwidth @border_color solid;
88 border-bottom: @borderwidth @border_color solid;
89
89
90 button {
90 button {
91 margin-top:2px;
91 margin-top:2px;
92 margin-bottom:2px;
92 margin-bottom:2px;
93 }
93 }
94
94
95
95
96 select, label {
96 select, label {
97 height : 19px;
97 height : 19px;
98 vertical-align:middle;
98 vertical-align:middle;
99 margin-right:2px;
99 margin-right:2px;
100 margin-bottom:0;
100 margin-bottom:0;
101 display: inline;
101 display: inline;
102 font-size: 92%;
102 font-size: 92%;
103 margin-left:0.3em;
103 margin-left:0.3em;
104 margin-right:0.3em;
104 margin-right:0.3em;
105 padding: 0px;
105 padding: 0px;
106 }
106 }
107 }
107 }
108
108
109 .toolbar select{
109 .toolbar select{
110 width:auto;
110 width:auto;
111 }
111 }
112
112
113
113
114 #ipython-main-app {
114 #ipython-main-app {
115 width: 100%;
115 width: 100%;
116 position: relative;
116 position: relative;
117 font-size: 110%;
117 font-size: 110%;
118 }
118 }
119
119
120 span#quick_help_area {
120 span#quick_help_area {
121 position: static;
121 position: static;
122 padding: 5px 0px;
122 padding: 5px 0px;
123 margin: 0px 0px 0px 0px;
123 margin: 0px 0px 0px 0px;
124 }
124 }
125
125
126 .help_string {
126 .help_string {
127 float: right;
127 float: right;
128 width: 170px;
128 width: 170px;
129 padding: 0px 5px;
129 padding: 0px 5px;
130 text-align: left;
130 text-align: left;
131 font-size: 85%;
131 font-size: 85%;
132 }
132 }
133
133
134 .help_string_label {
134 .help_string_label {
135 float: right;
135 float: right;
136 font-size: 85%;
136 font-size: 85%;
137 }
137 }
138
138
139 div#notebook_panel {
139 div#notebook_panel {
140 margin: 0px 0px 0px 0px;
140 margin: 0px 0px 0px 0px;
141 padding: 0px;
141 padding: 0px;
142 }
142 }
143
143
144 div#notebook {
144 div#notebook {
145 overflow-y: scroll;
145 overflow-y: scroll;
146 overflow-x: auto;
146 overflow-x: auto;
147 width: 100%;
147 width: 100%;
148 /* This spaces the cell away from the edge of the notebook area */
148 /* This spaces the cell away from the edge of the notebook area */
149 padding: 5px 5px 15px 5px;
149 padding: 5px 5px 15px 5px;
150 margin: 0px;
150 margin: 0px;
151 }
151 }
152
152
153 div#pager_splitter {
153 div#pager_splitter {
154 height: 8px;
154 height: 8px;
155 }
155 }
156
156
157 #pager_container {
157 #pager_container {
158 position : relative;
158 position : relative;
159 }
159 }
160
160
161 div#pager {
161 div#pager {
162 padding: 15px;
162 padding: 15px;
163 overflow: auto;
163 overflow: auto;
164 display: none;
164 display: none;
165 }
165 }
166
166
167 div.ui-widget-content {
167 div.ui-widget-content {
168 border: 1px solid @border_color;
168 border: 1px solid @border_color;
169 outline: none;
169 outline: none;
170 }
170 }
171
171
172 .cell {
172 .cell {
173 border: 1px solid transparent;
173 border: 1px solid transparent;
174 .vbox();
174 .vbox();
175
175
176 &.selected {
176 &.selected {
177 .corner-all;
177 .corner-all;
178 border : thin @border_color solid;
178 border : thin @border_color solid;
179 }
179 }
180 }
180 }
181
181
182 div.cell {
182 div.cell {
183 width: 100%;
183 width: 100%;
184 padding: 5px 5px 5px 0px;
184 padding: 5px 5px 5px 0px;
185 /* This acts as a spacer between cells, that is outside the border */
185 /* This acts as a spacer between cells, that is outside the border */
186 margin: 2px 0px 2px 0px;
186 margin: 2px 0px 2px 0px;
187 outline: none;
187 outline: none;
188 }
188 }
189
189
190 div.code_cell {
190 div.code_cell {
191 }
191 }
192
192
193 /* any special styling for code cells that are currently running goes here */
193 /* any special styling for code cells that are currently running goes here */
194 div.code_cell.running {
194 div.code_cell.running {
195 }
195 }
196
196
197 div.prompt {
197 div.prompt {
198 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
198 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
199 width: 11ex;
199 width: 11ex;
200 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
200 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
201 padding: 0.4em;
201 padding: 0.4em;
202 margin: 0px;
202 margin: 0px;
203 font-family: monospace;
203 font-family: monospace;
204 text-align: right;
204 text-align: right;
205 /* This has to match that of the the CodeMirror class line-height below */
205 /* This has to match that of the the CodeMirror class line-height below */
206 line-height: 1.231;
206 line-height: 1.231;
207 }
207 }
208
208
209 div.input {
209 div.input {
210 page-break-inside: avoid;
210 page-break-inside: avoid;
211 .hbox();
211 .hbox();
212 }
212 }
213
213
214 /* input_area and input_prompt must match in top border and margin for alignment */
214 /* input_area and input_prompt must match in top border and margin for alignment */
215 div.input_area {
215 div.input_area {
216 /*color: @fontBaseColor;*/
216 /*color: @fontBaseColor;*/
217 border: 1px solid @light_border_color;
217 border: 1px solid @light_border_color;
218 .corner-all;
218 .corner-all;
219 background: @cell_background;
219 background: @cell_background;
220 }
220 }
221
221
222 div.input_prompt {
222 div.input_prompt {
223 color: navy;
223 color: navy;
224 border-top: 1px solid transparent;
224 border-top: 1px solid transparent;
225 }
225 }
226
226
227 div.output_wrapper {
227 div.output_wrapper {
228 /* This is a spacer between the input and output of each cell */
228 /* This is a spacer between the input and output of each cell */
229 margin-top: 5px;
229 margin-top: 5px;
230 margin-left: 5px;
230 margin-left: 5px;
231 /* FF needs explicit width to stretch */
231 /* FF needs explicit width to stretch */
232 width: 100%;
232 width: 100%;
233 /* this position must be relative to enable descendents to be absolute within it */
233 /* this position must be relative to enable descendents to be absolute within it */
234 position: relative;
234 position: relative;
235 }
235 }
236
236
237 /* class for the output area when it should be height-limited */
237 /* class for the output area when it should be height-limited */
238 div.output_scroll {
238 div.output_scroll {
239 /* ideally, this would be max-height, but FF barfs all over that */
239 /* ideally, this would be max-height, but FF barfs all over that */
240 height: 24em;
240 height: 24em;
241 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
241 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
242 width: 100%;
242 width: 100%;
243
243
244 overflow: auto;
244 overflow: auto;
245 .corner-all;
245 .corner-all;
246 box-shadow: inset 0 2px 8px rgba(0, 0, 0, .8);
246 box-shadow: inset 0 2px 8px rgba(0, 0, 0, .8);
247 }
247 }
248
248
249 /* output div while it is collapsed */
249 /* output div while it is collapsed */
250 div.output_collapsed {
250 div.output_collapsed {
251 margin-right: 5px;
251 margin-right: 5px;
252 }
252 }
253
253
254 div.out_prompt_overlay {
254 div.out_prompt_overlay {
255 height: 100%;
255 height: 100%;
256 padding: 0px;
256 padding: 0px;
257 position: absolute;
257 position: absolute;
258 .corner-all;
258 .corner-all;
259 }
259 }
260
260
261 div.out_prompt_overlay:hover {
261 div.out_prompt_overlay:hover {
262 /* use inner shadow to get border that is computed the same on WebKit/FF */
262 /* use inner shadow to get border that is computed the same on WebKit/FF */
263 box-shadow: inset 0 0 1px #000;
263 box-shadow: inset 0 0 1px #000;
264 background: rgba(240, 240, 240, 0.5);
264 background: rgba(240, 240, 240, 0.5);
265 }
265 }
266
266
267 div.output_prompt {
267 div.output_prompt {
268 color: darkred;
268 color: darkred;
269 /* 5px right shift to account for margin in parent container */
269 /* 5px right shift to account for margin in parent container */
270 margin: 0 5px 0 -5px;
270 margin: 0 5px 0 -5px;
271 }
271 }
272
272
273 /* This class is the outer container of all output sections. */
273 /* This class is the outer container of all output sections. */
274 div.output_area {
274 div.output_area {
275 padding: 0px;
275 padding: 0px;
276 page-break-inside: avoid;
276 page-break-inside: avoid;
277 .hbox();
277 .hbox();
278 }
278 }
279
279
280
280
281 /* This is needed to protect the pre formating from global settings such
281 /* This is needed to protect the pre formating from global settings such
282 as that of bootstrap */
282 as that of bootstrap */
283 div.output_area pre {
283 div.output_area pre {
284 font-family: monospace;
284 font-family: monospace;
285 margin: 0;
285 margin: 0;
286 padding: 0;
286 padding: 0;
287 border: 0;
287 border: 0;
288 font-size: 100%;
288 font-size: 100%;
289 vertical-align: baseline;
289 vertical-align: baseline;
290 color: black;
290 color: black;
291 }
291 }
292
292
293 /* This class is for the output subarea inside the output_area and after
293 /* This class is for the output subarea inside the output_area and after
294 the prompt div. */
294 the prompt div. */
295 div.output_subarea {
295 div.output_subarea {
296 padding: 0.44em 0.4em 0.4em 1px;
296 padding: 0.44em 0.4em 0.4em 1px;
297 .box-flex1();
297 .box-flex1();
298 }
298 }
299
299
300 /* The rest of the output_* classes are for special styling of the different
300 /* The rest of the output_* classes are for special styling of the different
301 output types */
301 output types */
302
302
303 /* all text output has this class: */
303 /* all text output has this class: */
304 div.output_text {
304 div.output_text {
305 text-align: left;
305 text-align: left;
306 color: @fontBaseColor;
306 color: @fontBaseColor;
307 font-family: monospace;
307 font-family: monospace;
308 /* This has to match that of the the CodeMirror class line-height below */
308 /* This has to match that of the the CodeMirror class line-height below */
309 line-height: 1.231;
309 line-height: 1.231;
310 }
310 }
311
311
312 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
312 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
313 div.output_stream {
313 div.output_stream {
314 padding-top: 0.0em;
314 padding-top: 0.0em;
315 padding-bottom: 0.0em;
315 padding-bottom: 0.0em;
316 }
316 }
317 div.output_stdout {
317 div.output_stdout {
318 }
318 }
319 div.output_stderr {
319 div.output_stderr {
320 background: #fdd; /* very light red background for stderr */
320 background: #fdd; /* very light red background for stderr */
321 }
321 }
322
322
323 div.output_latex {
323 div.output_latex {
324 text-align: left;
324 text-align: left;
325 }
325 }
326
326
327 div.output_html {
327 div.output_html {
328 }
328 }
329
329
330 div.output_png {
330 div.output_png {
331 }
331 }
332
332
333 div.output_jpeg {
333 div.output_jpeg {
334 }
334 }
335
335
336 div.text_cell {
336 div.text_cell {
337 padding: 5px 5px 5px 5px;
337 padding: 5px 5px 5px 5px;
338 }
338 }
339
339
340 div.text_cell_input {
340 div.text_cell_input {
341 color: @fontBaseColor;
341 color: @fontBaseColor;
342 border: 1px solid @light_border_color;
342 border: 1px solid @light_border_color;
343 .corner-all;
343 .corner-all;
344 background: @cell_background;
344 background: @cell_background;
345 }
345 }
346
346
347 div.text_cell_render {
347 div.text_cell_render {
348 /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
348 /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
349 outline: none;
349 outline: none;
350 resize: none;
350 resize: none;
351 width: inherit;
351 width: inherit;
352 border-style: none;
352 border-style: none;
353 padding: 5px;
353 padding: 5px;
354 color: @fontBaseColor;
354 color: @fontBaseColor;
355 }
355 }
356
356
357 /* The following gets added to the <head> if it is detected that the user has a
357 /* The following gets added to the <head> if it is detected that the user has a
358 * monospace font with inconsistent normal/bold/italic height. See
358 * monospace font with inconsistent normal/bold/italic height. See
359 * notebookmain.js. Such fonts will have keywords vertically offset with
359 * notebookmain.js. Such fonts will have keywords vertically offset with
360 * respect to the rest of the text. The user should select a better font.
360 * respect to the rest of the text. The user should select a better font.
361 * See: https://github.com/ipython/ipython/issues/1503
361 * See: https://github.com/ipython/ipython/issues/1503
362 *
362 *
363 * .CodeMirror span {
363 * .CodeMirror span {
364 * vertical-align: bottom;
364 * vertical-align: bottom;
365 * }
365 * }
366 */
366 */
367
367
368 .CodeMirror {
368 .CodeMirror {
369 line-height: 1.231; /* Changed from 1em to our global default */
369 line-height: 1.231; /* Changed from 1em to our global default */
370 }
370 }
371
371
372 .CodeMirror-scroll {
372 .CodeMirror-scroll {
373 height: auto; /* Changed to auto to autogrow */
373 height: auto; /* Changed to auto to autogrow */
374 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
374 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
375 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
375 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
376 overflow-y: hidden;
376 overflow-y: hidden;
377 overflow-x: auto; /* Changed from auto to remove scrollbar */
377 overflow-x: auto; /* Changed from auto to remove scrollbar */
378 }
378 }
379
379
380 /* CSS font colors for translated ANSI colors. */
380 /* CSS font colors for translated ANSI colors. */
381
381
382
382
383 .ansiblack {color: @fontBaseColor;}
383 .ansiblack {color: @fontBaseColor;}
384 .ansired {color: darkred;}
384 .ansired {color: darkred;}
385 .ansigreen {color: darkgreen;}
385 .ansigreen {color: darkgreen;}
386 .ansiyellow {color: brown;}
386 .ansiyellow {color: brown;}
387 .ansiblue {color: darkblue;}
387 .ansiblue {color: darkblue;}
388 .ansipurple {color: darkviolet;}
388 .ansipurple {color: darkviolet;}
389 .ansicyan {color: steelblue;}
389 .ansicyan {color: steelblue;}
390 .ansigrey {color: grey;}
390 .ansigrey {color: grey;}
391 .ansibold {font-weight: bold;}
391 .ansibold {font-weight: bold;}
392
392
393 .completions {
393 .completions {
394 position: absolute;
394 position: absolute;
395 z-index: 10;
395 z-index: 10;
396 overflow: hidden;
396 overflow: hidden;
397 border: 1px solid @border_color;
397 border: 1px solid @border_color;
398 }
398 }
399
399
400 .completions select {
400 .completions select {
401 background: white;
401 background: white;
402 outline: none;
402 outline: none;
403 border: none;
403 border: none;
404 padding: 0px;
404 padding: 0px;
405 margin: 0px;
405 margin: 0px;
406 overflow: auto;
406 overflow: auto;
407 font-family: monospace;
407 font-family: monospace;
408 }
408 }
409
409
410 option.context {
410 option.context {
411 background-color: #DEF7FF;
411 background-color: #DEF7FF;
412 }
412 }
413 option.introspection {
413 option.introspection {
414 background-color: #EBF4EB;
414 background-color: #EBF4EB;
415 }
415 }
416
416
417 /*fixed part of the completion*/
417 /*fixed part of the completion*/
418 .completions p b {
418 .completions p b {
419 font-weight:bold;
419 font-weight:bold;
420 }
420 }
421
421
422 .completions p {
422 .completions p {
423 background: #DDF;
423 background: #DDF;
424 /*outline: none;
424 /*outline: none;
425 padding: 0px;*/
425 padding: 0px;*/
426 border-bottom: black solid 1px;
426 border-bottom: black solid 1px;
427 padding: 1px;
427 padding: 1px;
428 font-family: monospace;
428 font-family: monospace;
429 }
429 }
430
430
431 pre.dialog {
431 pre.dialog {
432 background-color: @cell_background;
432 background-color: @cell_background;
433 border: 1px solid #ddd;
433 border: 1px solid #ddd;
434 .corner-all;
434 .corner-all;
435 padding: 0.4em;
435 padding: 0.4em;
436 padding-left: 2em;
436 padding-left: 2em;
437 }
437 }
438
438
439 p.dialog {
439 p.dialog {
440 padding : 0.2em;
440 padding : 0.2em;
441 }
441 }
442
442
443 .shortcut_key {
443 .shortcut_key {
444 display: inline-block;
444 display: inline-block;
445 width: 15ex;
445 width: 15ex;
446 text-align: right;
446 text-align: right;
447 font-family: monospace;
447 font-family: monospace;
448 }
448 }
449
449
450 .shortcut_descr {
450 .shortcut_descr {
451 }
451 }
452
452
453 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
453 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
454 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
454 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
455 */
455 */
456 pre, code, kbd, samp { white-space: pre-wrap; }
456 pre, code, kbd, samp { white-space: pre-wrap; }
457
457
458 #fonttest {
458 #fonttest {
459 font-family: monospace;
459 font-family: monospace;
460 }
460 }
461
461
462 .js-error {
462 .js-error {
463 color: darkred;
463 color: darkred;
464 }
464 }
465
465
466 a {
466 a {
467 text-decoration: underline;
467 text-decoration: underline;
468 }
468 }
469
469
470 p {
470 p {
471
471
472 margin-bottom:0;
472 margin-bottom:0;
473
473
474 }
474 }
475
475
476 a.heading-anchor:link, a.heading-anchor:visited {
476 a.heading-anchor:link, a.heading-anchor:visited {
477 text-decoration: none;
477 text-decoration: none;
478 color: inherit;
478 color: inherit;
479 }
479 }
480
481 /* raw_input styles */
482
483 div.raw_input {
484 padding-top: 0px;
485 padding-bottom: 0px;
486 height: 1em;
487 line-height: 1em;
488 font-family: monospace;
489 }
490 span.input_prompt {
491 font-family: inherit;
492 }
493 input.raw_input {
494 font-family: inherit;
495 font-size: inherit;
496 color: inherit;
497 width: auto;
498 margin: -2px 0px 0px 1px;
499 padding-left: 1px;
500 padding-top: 2px;
501 height: 1em;
502 }
@@ -1,795 +1,804 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports
18 # Standard library imports
19 import __builtin__
19 import __builtin__
20 import sys
20 import sys
21 import time
21 import time
22 import traceback
22 import traceback
23 import logging
23 import logging
24 import uuid
24 import uuid
25
25
26 from datetime import datetime
26 from datetime import datetime
27 from signal import (
27 from signal import (
28 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
28 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
29 )
29 )
30
30
31 # System library imports
31 # System library imports
32 import zmq
32 import zmq
33 from zmq.eventloop import ioloop
33 from zmq.eventloop import ioloop
34 from zmq.eventloop.zmqstream import ZMQStream
34 from zmq.eventloop.zmqstream import ZMQStream
35
35
36 # Local imports
36 # Local imports
37 from IPython.config.configurable import Configurable
37 from IPython.config.configurable import Configurable
38 from IPython.core.error import StdinNotImplementedError
38 from IPython.core.error import StdinNotImplementedError
39 from IPython.core import release
39 from IPython.core import release
40 from IPython.utils import io
40 from IPython.utils import io
41 from IPython.utils import py3compat
41 from IPython.utils import py3compat
42 from IPython.utils.jsonutil import json_clean
42 from IPython.utils.jsonutil import json_clean
43 from IPython.utils.traitlets import (
43 from IPython.utils.traitlets import (
44 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode,
44 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode,
45 Type
45 Type
46 )
46 )
47
47
48 from serialize import serialize_object, unpack_apply_message
48 from serialize import serialize_object, unpack_apply_message
49 from session import Session
49 from session import Session
50 from zmqshell import ZMQInteractiveShell
50 from zmqshell import ZMQInteractiveShell
51
51
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Main kernel class
54 # Main kernel class
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 protocol_version = list(release.kernel_protocol_version_info)
57 protocol_version = list(release.kernel_protocol_version_info)
58 ipython_version = list(release.version_info)
58 ipython_version = list(release.version_info)
59 language_version = list(sys.version_info[:3])
59 language_version = list(sys.version_info[:3])
60
60
61
61
62 class Kernel(Configurable):
62 class Kernel(Configurable):
63
63
64 #---------------------------------------------------------------------------
64 #---------------------------------------------------------------------------
65 # Kernel interface
65 # Kernel interface
66 #---------------------------------------------------------------------------
66 #---------------------------------------------------------------------------
67
67
68 # attribute to override with a GUI
68 # attribute to override with a GUI
69 eventloop = Any(None)
69 eventloop = Any(None)
70 def _eventloop_changed(self, name, old, new):
70 def _eventloop_changed(self, name, old, new):
71 """schedule call to eventloop from IOLoop"""
71 """schedule call to eventloop from IOLoop"""
72 loop = ioloop.IOLoop.instance()
72 loop = ioloop.IOLoop.instance()
73 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
73 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
74
74
75 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
75 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
76 shell_class = Type(ZMQInteractiveShell)
76 shell_class = Type(ZMQInteractiveShell)
77
77
78 session = Instance(Session)
78 session = Instance(Session)
79 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
79 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
80 shell_streams = List()
80 shell_streams = List()
81 control_stream = Instance(ZMQStream)
81 control_stream = Instance(ZMQStream)
82 iopub_socket = Instance(zmq.Socket)
82 iopub_socket = Instance(zmq.Socket)
83 stdin_socket = Instance(zmq.Socket)
83 stdin_socket = Instance(zmq.Socket)
84 log = Instance(logging.Logger)
84 log = Instance(logging.Logger)
85
85
86 user_module = Any()
86 user_module = Any()
87 def _user_module_changed(self, name, old, new):
87 def _user_module_changed(self, name, old, new):
88 if self.shell is not None:
88 if self.shell is not None:
89 self.shell.user_module = new
89 self.shell.user_module = new
90
90
91 user_ns = Dict(default_value=None)
91 user_ns = Dict(default_value=None)
92 def _user_ns_changed(self, name, old, new):
92 def _user_ns_changed(self, name, old, new):
93 if self.shell is not None:
93 if self.shell is not None:
94 self.shell.user_ns = new
94 self.shell.user_ns = new
95 self.shell.init_user_ns()
95 self.shell.init_user_ns()
96
96
97 # identities:
97 # identities:
98 int_id = Integer(-1)
98 int_id = Integer(-1)
99 ident = Unicode()
99 ident = Unicode()
100
100
101 def _ident_default(self):
101 def _ident_default(self):
102 return unicode(uuid.uuid4())
102 return unicode(uuid.uuid4())
103
103
104
104
105 # Private interface
105 # Private interface
106
106
107 # Time to sleep after flushing the stdout/err buffers in each execute
107 # Time to sleep after flushing the stdout/err buffers in each execute
108 # cycle. While this introduces a hard limit on the minimal latency of the
108 # cycle. While this introduces a hard limit on the minimal latency of the
109 # execute cycle, it helps prevent output synchronization problems for
109 # execute cycle, it helps prevent output synchronization problems for
110 # clients.
110 # clients.
111 # Units are in seconds. The minimum zmq latency on local host is probably
111 # Units are in seconds. The minimum zmq latency on local host is probably
112 # ~150 microseconds, set this to 500us for now. We may need to increase it
112 # ~150 microseconds, set this to 500us for now. We may need to increase it
113 # a little if it's not enough after more interactive testing.
113 # a little if it's not enough after more interactive testing.
114 _execute_sleep = Float(0.0005, config=True)
114 _execute_sleep = Float(0.0005, config=True)
115
115
116 # Frequency of the kernel's event loop.
116 # Frequency of the kernel's event loop.
117 # Units are in seconds, kernel subclasses for GUI toolkits may need to
117 # Units are in seconds, kernel subclasses for GUI toolkits may need to
118 # adapt to milliseconds.
118 # adapt to milliseconds.
119 _poll_interval = Float(0.05, config=True)
119 _poll_interval = Float(0.05, config=True)
120
120
121 # If the shutdown was requested over the network, we leave here the
121 # If the shutdown was requested over the network, we leave here the
122 # necessary reply message so it can be sent by our registered atexit
122 # necessary reply message so it can be sent by our registered atexit
123 # handler. This ensures that the reply is only sent to clients truly at
123 # handler. This ensures that the reply is only sent to clients truly at
124 # the end of our shutdown process (which happens after the underlying
124 # the end of our shutdown process (which happens after the underlying
125 # IPython shell's own shutdown).
125 # IPython shell's own shutdown).
126 _shutdown_message = None
126 _shutdown_message = None
127
127
128 # This is a dict of port number that the kernel is listening on. It is set
128 # This is a dict of port number that the kernel is listening on. It is set
129 # by record_ports and used by connect_request.
129 # by record_ports and used by connect_request.
130 _recorded_ports = Dict()
130 _recorded_ports = Dict()
131
131
132 # A reference to the Python builtin 'raw_input' function.
132 # A reference to the Python builtin 'raw_input' function.
133 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
133 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
134 _sys_raw_input = Any()
134 _sys_raw_input = Any()
135
135
136 # set of aborted msg_ids
136 # set of aborted msg_ids
137 aborted = Set()
137 aborted = Set()
138
138
139
139
140 def __init__(self, **kwargs):
140 def __init__(self, **kwargs):
141 super(Kernel, self).__init__(**kwargs)
141 super(Kernel, self).__init__(**kwargs)
142
142
143 # Initialize the InteractiveShell subclass
143 # Initialize the InteractiveShell subclass
144 self.shell = self.shell_class.instance(config=self.config,
144 self.shell = self.shell_class.instance(config=self.config,
145 profile_dir = self.profile_dir,
145 profile_dir = self.profile_dir,
146 user_module = self.user_module,
146 user_module = self.user_module,
147 user_ns = self.user_ns,
147 user_ns = self.user_ns,
148 )
148 )
149 self.shell.displayhook.session = self.session
149 self.shell.displayhook.session = self.session
150 self.shell.displayhook.pub_socket = self.iopub_socket
150 self.shell.displayhook.pub_socket = self.iopub_socket
151 self.shell.displayhook.topic = self._topic('pyout')
151 self.shell.displayhook.topic = self._topic('pyout')
152 self.shell.display_pub.session = self.session
152 self.shell.display_pub.session = self.session
153 self.shell.display_pub.pub_socket = self.iopub_socket
153 self.shell.display_pub.pub_socket = self.iopub_socket
154 self.shell.data_pub.session = self.session
154 self.shell.data_pub.session = self.session
155 self.shell.data_pub.pub_socket = self.iopub_socket
155 self.shell.data_pub.pub_socket = self.iopub_socket
156
156
157 # TMP - hack while developing
157 # TMP - hack while developing
158 self.shell._reply_content = None
158 self.shell._reply_content = None
159
159
160 # Build dict of handlers for message types
160 # Build dict of handlers for message types
161 msg_types = [ 'execute_request', 'complete_request',
161 msg_types = [ 'execute_request', 'complete_request',
162 'object_info_request', 'history_request',
162 'object_info_request', 'history_request',
163 'kernel_info_request',
163 'kernel_info_request',
164 'connect_request', 'shutdown_request',
164 'connect_request', 'shutdown_request',
165 'apply_request',
165 'apply_request',
166 ]
166 ]
167 self.shell_handlers = {}
167 self.shell_handlers = {}
168 for msg_type in msg_types:
168 for msg_type in msg_types:
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
169 self.shell_handlers[msg_type] = getattr(self, msg_type)
170
170
171 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
171 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
172 self.control_handlers = {}
172 self.control_handlers = {}
173 for msg_type in control_msg_types:
173 for msg_type in control_msg_types:
174 self.control_handlers[msg_type] = getattr(self, msg_type)
174 self.control_handlers[msg_type] = getattr(self, msg_type)
175
175
176 def dispatch_control(self, msg):
176 def dispatch_control(self, msg):
177 """dispatch control requests"""
177 """dispatch control requests"""
178 idents,msg = self.session.feed_identities(msg, copy=False)
178 idents,msg = self.session.feed_identities(msg, copy=False)
179 try:
179 try:
180 msg = self.session.unserialize(msg, content=True, copy=False)
180 msg = self.session.unserialize(msg, content=True, copy=False)
181 except:
181 except:
182 self.log.error("Invalid Control Message", exc_info=True)
182 self.log.error("Invalid Control Message", exc_info=True)
183 return
183 return
184
184
185 self.log.debug("Control received: %s", msg)
185 self.log.debug("Control received: %s", msg)
186
186
187 header = msg['header']
187 header = msg['header']
188 msg_id = header['msg_id']
188 msg_id = header['msg_id']
189 msg_type = header['msg_type']
189 msg_type = header['msg_type']
190
190
191 handler = self.control_handlers.get(msg_type, None)
191 handler = self.control_handlers.get(msg_type, None)
192 if handler is None:
192 if handler is None:
193 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
193 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
194 else:
194 else:
195 try:
195 try:
196 handler(self.control_stream, idents, msg)
196 handler(self.control_stream, idents, msg)
197 except Exception:
197 except Exception:
198 self.log.error("Exception in control handler:", exc_info=True)
198 self.log.error("Exception in control handler:", exc_info=True)
199
199
200 def dispatch_shell(self, stream, msg):
200 def dispatch_shell(self, stream, msg):
201 """dispatch shell requests"""
201 """dispatch shell requests"""
202 # flush control requests first
202 # flush control requests first
203 if self.control_stream:
203 if self.control_stream:
204 self.control_stream.flush()
204 self.control_stream.flush()
205
205
206 idents,msg = self.session.feed_identities(msg, copy=False)
206 idents,msg = self.session.feed_identities(msg, copy=False)
207 try:
207 try:
208 msg = self.session.unserialize(msg, content=True, copy=False)
208 msg = self.session.unserialize(msg, content=True, copy=False)
209 except:
209 except:
210 self.log.error("Invalid Message", exc_info=True)
210 self.log.error("Invalid Message", exc_info=True)
211 return
211 return
212
212
213 header = msg['header']
213 header = msg['header']
214 msg_id = header['msg_id']
214 msg_id = header['msg_id']
215 msg_type = msg['header']['msg_type']
215 msg_type = msg['header']['msg_type']
216
216
217 # Print some info about this message and leave a '--->' marker, so it's
217 # Print some info about this message and leave a '--->' marker, so it's
218 # easier to trace visually the message chain when debugging. Each
218 # easier to trace visually the message chain when debugging. Each
219 # handler prints its message at the end.
219 # handler prints its message at the end.
220 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
220 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
221 self.log.debug(' Content: %s\n --->\n ', msg['content'])
221 self.log.debug(' Content: %s\n --->\n ', msg['content'])
222
222
223 if msg_id in self.aborted:
223 if msg_id in self.aborted:
224 self.aborted.remove(msg_id)
224 self.aborted.remove(msg_id)
225 # is it safe to assume a msg_id will not be resubmitted?
225 # is it safe to assume a msg_id will not be resubmitted?
226 reply_type = msg_type.split('_')[0] + '_reply'
226 reply_type = msg_type.split('_')[0] + '_reply'
227 status = {'status' : 'aborted'}
227 status = {'status' : 'aborted'}
228 md = {'engine' : self.ident}
228 md = {'engine' : self.ident}
229 md.update(status)
229 md.update(status)
230 reply_msg = self.session.send(stream, reply_type, metadata=md,
230 reply_msg = self.session.send(stream, reply_type, metadata=md,
231 content=status, parent=msg, ident=idents)
231 content=status, parent=msg, ident=idents)
232 return
232 return
233
233
234 handler = self.shell_handlers.get(msg_type, None)
234 handler = self.shell_handlers.get(msg_type, None)
235 if handler is None:
235 if handler is None:
236 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
236 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
237 else:
237 else:
238 # ensure default_int_handler during handler call
238 # ensure default_int_handler during handler call
239 sig = signal(SIGINT, default_int_handler)
239 sig = signal(SIGINT, default_int_handler)
240 try:
240 try:
241 handler(stream, idents, msg)
241 handler(stream, idents, msg)
242 except Exception:
242 except Exception:
243 self.log.error("Exception in message handler:", exc_info=True)
243 self.log.error("Exception in message handler:", exc_info=True)
244 finally:
244 finally:
245 signal(SIGINT, sig)
245 signal(SIGINT, sig)
246
246
247 def enter_eventloop(self):
247 def enter_eventloop(self):
248 """enter eventloop"""
248 """enter eventloop"""
249 self.log.info("entering eventloop")
249 self.log.info("entering eventloop")
250 # restore default_int_handler
250 # restore default_int_handler
251 signal(SIGINT, default_int_handler)
251 signal(SIGINT, default_int_handler)
252 while self.eventloop is not None:
252 while self.eventloop is not None:
253 try:
253 try:
254 self.eventloop(self)
254 self.eventloop(self)
255 except KeyboardInterrupt:
255 except KeyboardInterrupt:
256 # Ctrl-C shouldn't crash the kernel
256 # Ctrl-C shouldn't crash the kernel
257 self.log.error("KeyboardInterrupt caught in kernel")
257 self.log.error("KeyboardInterrupt caught in kernel")
258 continue
258 continue
259 else:
259 else:
260 # eventloop exited cleanly, this means we should stop (right?)
260 # eventloop exited cleanly, this means we should stop (right?)
261 self.eventloop = None
261 self.eventloop = None
262 break
262 break
263 self.log.info("exiting eventloop")
263 self.log.info("exiting eventloop")
264
264
265 def start(self):
265 def start(self):
266 """register dispatchers for streams"""
266 """register dispatchers for streams"""
267 self.shell.exit_now = False
267 self.shell.exit_now = False
268 if self.control_stream:
268 if self.control_stream:
269 self.control_stream.on_recv(self.dispatch_control, copy=False)
269 self.control_stream.on_recv(self.dispatch_control, copy=False)
270
270
271 def make_dispatcher(stream):
271 def make_dispatcher(stream):
272 def dispatcher(msg):
272 def dispatcher(msg):
273 return self.dispatch_shell(stream, msg)
273 return self.dispatch_shell(stream, msg)
274 return dispatcher
274 return dispatcher
275
275
276 for s in self.shell_streams:
276 for s in self.shell_streams:
277 s.on_recv(make_dispatcher(s), copy=False)
277 s.on_recv(make_dispatcher(s), copy=False)
278
278
279 # publish idle status
279 # publish idle status
280 self._publish_status('starting')
280 self._publish_status('starting')
281
281
282 def do_one_iteration(self):
282 def do_one_iteration(self):
283 """step eventloop just once"""
283 """step eventloop just once"""
284 if self.control_stream:
284 if self.control_stream:
285 self.control_stream.flush()
285 self.control_stream.flush()
286 for stream in self.shell_streams:
286 for stream in self.shell_streams:
287 # handle at most one request per iteration
287 # handle at most one request per iteration
288 stream.flush(zmq.POLLIN, 1)
288 stream.flush(zmq.POLLIN, 1)
289 stream.flush(zmq.POLLOUT)
289 stream.flush(zmq.POLLOUT)
290
290
291
291
292 def record_ports(self, ports):
292 def record_ports(self, ports):
293 """Record the ports that this kernel is using.
293 """Record the ports that this kernel is using.
294
294
295 The creator of the Kernel instance must call this methods if they
295 The creator of the Kernel instance must call this methods if they
296 want the :meth:`connect_request` method to return the port numbers.
296 want the :meth:`connect_request` method to return the port numbers.
297 """
297 """
298 self._recorded_ports = ports
298 self._recorded_ports = ports
299
299
300 #---------------------------------------------------------------------------
300 #---------------------------------------------------------------------------
301 # Kernel request handlers
301 # Kernel request handlers
302 #---------------------------------------------------------------------------
302 #---------------------------------------------------------------------------
303
303
304 def _make_metadata(self, other=None):
304 def _make_metadata(self, other=None):
305 """init metadata dict, for execute/apply_reply"""
305 """init metadata dict, for execute/apply_reply"""
306 new_md = {
306 new_md = {
307 'dependencies_met' : True,
307 'dependencies_met' : True,
308 'engine' : self.ident,
308 'engine' : self.ident,
309 'started': datetime.now(),
309 'started': datetime.now(),
310 }
310 }
311 if other:
311 if other:
312 new_md.update(other)
312 new_md.update(other)
313 return new_md
313 return new_md
314
314
315 def _publish_pyin(self, code, parent, execution_count):
315 def _publish_pyin(self, code, parent, execution_count):
316 """Publish the code request on the pyin stream."""
316 """Publish the code request on the pyin stream."""
317
317
318 self.session.send(self.iopub_socket, u'pyin',
318 self.session.send(self.iopub_socket, u'pyin',
319 {u'code':code, u'execution_count': execution_count},
319 {u'code':code, u'execution_count': execution_count},
320 parent=parent, ident=self._topic('pyin')
320 parent=parent, ident=self._topic('pyin')
321 )
321 )
322
322
323 def _publish_status(self, status, parent=None):
323 def _publish_status(self, status, parent=None):
324 """send status (busy/idle) on IOPub"""
324 """send status (busy/idle) on IOPub"""
325 self.session.send(self.iopub_socket,
325 self.session.send(self.iopub_socket,
326 u'status',
326 u'status',
327 {u'execution_state': status},
327 {u'execution_state': status},
328 parent=parent,
328 parent=parent,
329 ident=self._topic('status'),
329 ident=self._topic('status'),
330 )
330 )
331
331
332
332
333 def execute_request(self, stream, ident, parent):
333 def execute_request(self, stream, ident, parent):
334 """handle an execute_request"""
334 """handle an execute_request"""
335
335
336 self._publish_status(u'busy', parent)
336 self._publish_status(u'busy', parent)
337
337
338 try:
338 try:
339 content = parent[u'content']
339 content = parent[u'content']
340 code = content[u'code']
340 code = content[u'code']
341 silent = content[u'silent']
341 silent = content[u'silent']
342 store_history = content.get(u'store_history', not silent)
342 store_history = content.get(u'store_history', not silent)
343 except:
343 except:
344 self.log.error("Got bad msg: ")
344 self.log.error("Got bad msg: ")
345 self.log.error("%s", parent)
345 self.log.error("%s", parent)
346 return
346 return
347
347
348 md = self._make_metadata(parent['metadata'])
348 md = self._make_metadata(parent['metadata'])
349
349
350 shell = self.shell # we'll need this a lot here
350 shell = self.shell # we'll need this a lot here
351
351
352 # Replace raw_input. Note that is not sufficient to replace
352 # Replace raw_input. Note that is not sufficient to replace
353 # raw_input in the user namespace.
353 # raw_input in the user namespace.
354 if content.get('allow_stdin', False):
354 if content.get('allow_stdin', False):
355 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
355 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
356 else:
356 else:
357 raw_input = lambda prompt='' : self._no_raw_input()
357 raw_input = lambda prompt='' : self._no_raw_input()
358
358
359 if py3compat.PY3:
359 if py3compat.PY3:
360 self._sys_raw_input = __builtin__.input
360 self._sys_raw_input = __builtin__.input
361 __builtin__.input = raw_input
361 __builtin__.input = raw_input
362 else:
362 else:
363 self._sys_raw_input = __builtin__.raw_input
363 self._sys_raw_input = __builtin__.raw_input
364 __builtin__.raw_input = raw_input
364 __builtin__.raw_input = raw_input
365
365
366 # Set the parent message of the display hook and out streams.
366 # Set the parent message of the display hook and out streams.
367 shell.displayhook.set_parent(parent)
367 shell.displayhook.set_parent(parent)
368 shell.display_pub.set_parent(parent)
368 shell.display_pub.set_parent(parent)
369 shell.data_pub.set_parent(parent)
369 shell.data_pub.set_parent(parent)
370 try:
370 try:
371 sys.stdout.set_parent(parent)
371 sys.stdout.set_parent(parent)
372 except AttributeError:
372 except AttributeError:
373 pass
373 pass
374 try:
374 try:
375 sys.stderr.set_parent(parent)
375 sys.stderr.set_parent(parent)
376 except AttributeError:
376 except AttributeError:
377 pass
377 pass
378
378
379 # Re-broadcast our input for the benefit of listening clients, and
379 # Re-broadcast our input for the benefit of listening clients, and
380 # start computing output
380 # start computing output
381 if not silent:
381 if not silent:
382 self._publish_pyin(code, parent, shell.execution_count)
382 self._publish_pyin(code, parent, shell.execution_count)
383
383
384 reply_content = {}
384 reply_content = {}
385 try:
385 try:
386 # FIXME: the shell calls the exception handler itself.
386 # FIXME: the shell calls the exception handler itself.
387 shell.run_cell(code, store_history=store_history, silent=silent)
387 shell.run_cell(code, store_history=store_history, silent=silent)
388 except:
388 except:
389 status = u'error'
389 status = u'error'
390 # FIXME: this code right now isn't being used yet by default,
390 # FIXME: this code right now isn't being used yet by default,
391 # because the run_cell() call above directly fires off exception
391 # because the run_cell() call above directly fires off exception
392 # reporting. This code, therefore, is only active in the scenario
392 # reporting. This code, therefore, is only active in the scenario
393 # where runlines itself has an unhandled exception. We need to
393 # where runlines itself has an unhandled exception. We need to
394 # uniformize this, for all exception construction to come from a
394 # uniformize this, for all exception construction to come from a
395 # single location in the codbase.
395 # single location in the codbase.
396 etype, evalue, tb = sys.exc_info()
396 etype, evalue, tb = sys.exc_info()
397 tb_list = traceback.format_exception(etype, evalue, tb)
397 tb_list = traceback.format_exception(etype, evalue, tb)
398 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
398 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
399 else:
399 else:
400 status = u'ok'
400 status = u'ok'
401 finally:
401 finally:
402 # Restore raw_input.
402 # Restore raw_input.
403 if py3compat.PY3:
403 if py3compat.PY3:
404 __builtin__.input = self._sys_raw_input
404 __builtin__.input = self._sys_raw_input
405 else:
405 else:
406 __builtin__.raw_input = self._sys_raw_input
406 __builtin__.raw_input = self._sys_raw_input
407
407
408 reply_content[u'status'] = status
408 reply_content[u'status'] = status
409
409
410 # Return the execution counter so clients can display prompts
410 # Return the execution counter so clients can display prompts
411 reply_content['execution_count'] = shell.execution_count - 1
411 reply_content['execution_count'] = shell.execution_count - 1
412
412
413 # FIXME - fish exception info out of shell, possibly left there by
413 # FIXME - fish exception info out of shell, possibly left there by
414 # runlines. We'll need to clean up this logic later.
414 # runlines. We'll need to clean up this logic later.
415 if shell._reply_content is not None:
415 if shell._reply_content is not None:
416 reply_content.update(shell._reply_content)
416 reply_content.update(shell._reply_content)
417 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
417 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
418 reply_content['engine_info'] = e_info
418 reply_content['engine_info'] = e_info
419 # reset after use
419 # reset after use
420 shell._reply_content = None
420 shell._reply_content = None
421
421
422 if 'traceback' in reply_content:
422 if 'traceback' in reply_content:
423 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
423 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
424
424
425
425
426 # At this point, we can tell whether the main code execution succeeded
426 # At this point, we can tell whether the main code execution succeeded
427 # or not. If it did, we proceed to evaluate user_variables/expressions
427 # or not. If it did, we proceed to evaluate user_variables/expressions
428 if reply_content['status'] == 'ok':
428 if reply_content['status'] == 'ok':
429 reply_content[u'user_variables'] = \
429 reply_content[u'user_variables'] = \
430 shell.user_variables(content.get(u'user_variables', []))
430 shell.user_variables(content.get(u'user_variables', []))
431 reply_content[u'user_expressions'] = \
431 reply_content[u'user_expressions'] = \
432 shell.user_expressions(content.get(u'user_expressions', {}))
432 shell.user_expressions(content.get(u'user_expressions', {}))
433 else:
433 else:
434 # If there was an error, don't even try to compute variables or
434 # If there was an error, don't even try to compute variables or
435 # expressions
435 # expressions
436 reply_content[u'user_variables'] = {}
436 reply_content[u'user_variables'] = {}
437 reply_content[u'user_expressions'] = {}
437 reply_content[u'user_expressions'] = {}
438
438
439 # Payloads should be retrieved regardless of outcome, so we can both
439 # Payloads should be retrieved regardless of outcome, so we can both
440 # recover partial output (that could have been generated early in a
440 # recover partial output (that could have been generated early in a
441 # block, before an error) and clear the payload system always.
441 # block, before an error) and clear the payload system always.
442 reply_content[u'payload'] = shell.payload_manager.read_payload()
442 reply_content[u'payload'] = shell.payload_manager.read_payload()
443 # Be agressive about clearing the payload because we don't want
443 # Be agressive about clearing the payload because we don't want
444 # it to sit in memory until the next execute_request comes in.
444 # it to sit in memory until the next execute_request comes in.
445 shell.payload_manager.clear_payload()
445 shell.payload_manager.clear_payload()
446
446
447 # Flush output before sending the reply.
447 # Flush output before sending the reply.
448 sys.stdout.flush()
448 sys.stdout.flush()
449 sys.stderr.flush()
449 sys.stderr.flush()
450 # FIXME: on rare occasions, the flush doesn't seem to make it to the
450 # FIXME: on rare occasions, the flush doesn't seem to make it to the
451 # clients... This seems to mitigate the problem, but we definitely need
451 # clients... This seems to mitigate the problem, but we definitely need
452 # to better understand what's going on.
452 # to better understand what's going on.
453 if self._execute_sleep:
453 if self._execute_sleep:
454 time.sleep(self._execute_sleep)
454 time.sleep(self._execute_sleep)
455
455
456 # Send the reply.
456 # Send the reply.
457 reply_content = json_clean(reply_content)
457 reply_content = json_clean(reply_content)
458
458
459 md['status'] = reply_content['status']
459 md['status'] = reply_content['status']
460 if reply_content['status'] == 'error' and \
460 if reply_content['status'] == 'error' and \
461 reply_content['ename'] == 'UnmetDependency':
461 reply_content['ename'] == 'UnmetDependency':
462 md['dependencies_met'] = False
462 md['dependencies_met'] = False
463
463
464 reply_msg = self.session.send(stream, u'execute_reply',
464 reply_msg = self.session.send(stream, u'execute_reply',
465 reply_content, parent, metadata=md,
465 reply_content, parent, metadata=md,
466 ident=ident)
466 ident=ident)
467
467
468 self.log.debug("%s", reply_msg)
468 self.log.debug("%s", reply_msg)
469
469
470 if not silent and reply_msg['content']['status'] == u'error':
470 if not silent and reply_msg['content']['status'] == u'error':
471 self._abort_queues()
471 self._abort_queues()
472
472
473 self._publish_status(u'idle', parent)
473 self._publish_status(u'idle', parent)
474
474
475 def complete_request(self, stream, ident, parent):
475 def complete_request(self, stream, ident, parent):
476 txt, matches = self._complete(parent)
476 txt, matches = self._complete(parent)
477 matches = {'matches' : matches,
477 matches = {'matches' : matches,
478 'matched_text' : txt,
478 'matched_text' : txt,
479 'status' : 'ok'}
479 'status' : 'ok'}
480 matches = json_clean(matches)
480 matches = json_clean(matches)
481 completion_msg = self.session.send(stream, 'complete_reply',
481 completion_msg = self.session.send(stream, 'complete_reply',
482 matches, parent, ident)
482 matches, parent, ident)
483 self.log.debug("%s", completion_msg)
483 self.log.debug("%s", completion_msg)
484
484
485 def object_info_request(self, stream, ident, parent):
485 def object_info_request(self, stream, ident, parent):
486 content = parent['content']
486 content = parent['content']
487 object_info = self.shell.object_inspect(content['oname'],
487 object_info = self.shell.object_inspect(content['oname'],
488 detail_level = content.get('detail_level', 0)
488 detail_level = content.get('detail_level', 0)
489 )
489 )
490 # Before we send this object over, we scrub it for JSON usage
490 # Before we send this object over, we scrub it for JSON usage
491 oinfo = json_clean(object_info)
491 oinfo = json_clean(object_info)
492 msg = self.session.send(stream, 'object_info_reply',
492 msg = self.session.send(stream, 'object_info_reply',
493 oinfo, parent, ident)
493 oinfo, parent, ident)
494 self.log.debug("%s", msg)
494 self.log.debug("%s", msg)
495
495
496 def history_request(self, stream, ident, parent):
496 def history_request(self, stream, ident, parent):
497 # We need to pull these out, as passing **kwargs doesn't work with
497 # We need to pull these out, as passing **kwargs doesn't work with
498 # unicode keys before Python 2.6.5.
498 # unicode keys before Python 2.6.5.
499 hist_access_type = parent['content']['hist_access_type']
499 hist_access_type = parent['content']['hist_access_type']
500 raw = parent['content']['raw']
500 raw = parent['content']['raw']
501 output = parent['content']['output']
501 output = parent['content']['output']
502 if hist_access_type == 'tail':
502 if hist_access_type == 'tail':
503 n = parent['content']['n']
503 n = parent['content']['n']
504 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
504 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
505 include_latest=True)
505 include_latest=True)
506
506
507 elif hist_access_type == 'range':
507 elif hist_access_type == 'range':
508 session = parent['content']['session']
508 session = parent['content']['session']
509 start = parent['content']['start']
509 start = parent['content']['start']
510 stop = parent['content']['stop']
510 stop = parent['content']['stop']
511 hist = self.shell.history_manager.get_range(session, start, stop,
511 hist = self.shell.history_manager.get_range(session, start, stop,
512 raw=raw, output=output)
512 raw=raw, output=output)
513
513
514 elif hist_access_type == 'search':
514 elif hist_access_type == 'search':
515 n = parent['content'].get('n')
515 n = parent['content'].get('n')
516 unique = parent['content'].get('unique', False)
516 unique = parent['content'].get('unique', False)
517 pattern = parent['content']['pattern']
517 pattern = parent['content']['pattern']
518 hist = self.shell.history_manager.search(
518 hist = self.shell.history_manager.search(
519 pattern, raw=raw, output=output, n=n, unique=unique)
519 pattern, raw=raw, output=output, n=n, unique=unique)
520
520
521 else:
521 else:
522 hist = []
522 hist = []
523 hist = list(hist)
523 hist = list(hist)
524 content = {'history' : hist}
524 content = {'history' : hist}
525 content = json_clean(content)
525 content = json_clean(content)
526 msg = self.session.send(stream, 'history_reply',
526 msg = self.session.send(stream, 'history_reply',
527 content, parent, ident)
527 content, parent, ident)
528 self.log.debug("Sending history reply with %i entries", len(hist))
528 self.log.debug("Sending history reply with %i entries", len(hist))
529
529
530 def connect_request(self, stream, ident, parent):
530 def connect_request(self, stream, ident, parent):
531 if self._recorded_ports is not None:
531 if self._recorded_ports is not None:
532 content = self._recorded_ports.copy()
532 content = self._recorded_ports.copy()
533 else:
533 else:
534 content = {}
534 content = {}
535 msg = self.session.send(stream, 'connect_reply',
535 msg = self.session.send(stream, 'connect_reply',
536 content, parent, ident)
536 content, parent, ident)
537 self.log.debug("%s", msg)
537 self.log.debug("%s", msg)
538
538
539 def kernel_info_request(self, stream, ident, parent):
539 def kernel_info_request(self, stream, ident, parent):
540 vinfo = {
540 vinfo = {
541 'protocol_version': protocol_version,
541 'protocol_version': protocol_version,
542 'ipython_version': ipython_version,
542 'ipython_version': ipython_version,
543 'language_version': language_version,
543 'language_version': language_version,
544 'language': 'python',
544 'language': 'python',
545 }
545 }
546 msg = self.session.send(stream, 'kernel_info_reply',
546 msg = self.session.send(stream, 'kernel_info_reply',
547 vinfo, parent, ident)
547 vinfo, parent, ident)
548 self.log.debug("%s", msg)
548 self.log.debug("%s", msg)
549
549
550 def shutdown_request(self, stream, ident, parent):
550 def shutdown_request(self, stream, ident, parent):
551 self.shell.exit_now = True
551 self.shell.exit_now = True
552 content = dict(status='ok')
552 content = dict(status='ok')
553 content.update(parent['content'])
553 content.update(parent['content'])
554 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
554 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
555 # same content, but different msg_id for broadcasting on IOPub
555 # same content, but different msg_id for broadcasting on IOPub
556 self._shutdown_message = self.session.msg(u'shutdown_reply',
556 self._shutdown_message = self.session.msg(u'shutdown_reply',
557 content, parent
557 content, parent
558 )
558 )
559
559
560 self._at_shutdown()
560 self._at_shutdown()
561 # call sys.exit after a short delay
561 # call sys.exit after a short delay
562 loop = ioloop.IOLoop.instance()
562 loop = ioloop.IOLoop.instance()
563 loop.add_timeout(time.time()+0.1, loop.stop)
563 loop.add_timeout(time.time()+0.1, loop.stop)
564
564
565 #---------------------------------------------------------------------------
565 #---------------------------------------------------------------------------
566 # Engine methods
566 # Engine methods
567 #---------------------------------------------------------------------------
567 #---------------------------------------------------------------------------
568
568
569 def apply_request(self, stream, ident, parent):
569 def apply_request(self, stream, ident, parent):
570 try:
570 try:
571 content = parent[u'content']
571 content = parent[u'content']
572 bufs = parent[u'buffers']
572 bufs = parent[u'buffers']
573 msg_id = parent['header']['msg_id']
573 msg_id = parent['header']['msg_id']
574 except:
574 except:
575 self.log.error("Got bad msg: %s", parent, exc_info=True)
575 self.log.error("Got bad msg: %s", parent, exc_info=True)
576 return
576 return
577
577
578 self._publish_status(u'busy', parent)
578 self._publish_status(u'busy', parent)
579
579
580 # Set the parent message of the display hook and out streams.
580 # Set the parent message of the display hook and out streams.
581 shell = self.shell
581 shell = self.shell
582 shell.displayhook.set_parent(parent)
582 shell.displayhook.set_parent(parent)
583 shell.display_pub.set_parent(parent)
583 shell.display_pub.set_parent(parent)
584 shell.data_pub.set_parent(parent)
584 shell.data_pub.set_parent(parent)
585 try:
585 try:
586 sys.stdout.set_parent(parent)
586 sys.stdout.set_parent(parent)
587 except AttributeError:
587 except AttributeError:
588 pass
588 pass
589 try:
589 try:
590 sys.stderr.set_parent(parent)
590 sys.stderr.set_parent(parent)
591 except AttributeError:
591 except AttributeError:
592 pass
592 pass
593
593
594 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
594 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
595 # self.iopub_socket.send(pyin_msg)
595 # self.iopub_socket.send(pyin_msg)
596 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
596 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
597 md = self._make_metadata(parent['metadata'])
597 md = self._make_metadata(parent['metadata'])
598 try:
598 try:
599 working = shell.user_ns
599 working = shell.user_ns
600
600
601 prefix = "_"+str(msg_id).replace("-","")+"_"
601 prefix = "_"+str(msg_id).replace("-","")+"_"
602
602
603 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
603 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
604
604
605 fname = getattr(f, '__name__', 'f')
605 fname = getattr(f, '__name__', 'f')
606
606
607 fname = prefix+"f"
607 fname = prefix+"f"
608 argname = prefix+"args"
608 argname = prefix+"args"
609 kwargname = prefix+"kwargs"
609 kwargname = prefix+"kwargs"
610 resultname = prefix+"result"
610 resultname = prefix+"result"
611
611
612 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
612 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
613 # print ns
613 # print ns
614 working.update(ns)
614 working.update(ns)
615 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
615 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
616 try:
616 try:
617 exec code in shell.user_global_ns, shell.user_ns
617 exec code in shell.user_global_ns, shell.user_ns
618 result = working.get(resultname)
618 result = working.get(resultname)
619 finally:
619 finally:
620 for key in ns.iterkeys():
620 for key in ns.iterkeys():
621 working.pop(key)
621 working.pop(key)
622
622
623 result_buf = serialize_object(result,
623 result_buf = serialize_object(result,
624 buffer_threshold=self.session.buffer_threshold,
624 buffer_threshold=self.session.buffer_threshold,
625 item_threshold=self.session.item_threshold,
625 item_threshold=self.session.item_threshold,
626 )
626 )
627
627
628 except:
628 except:
629 # invoke IPython traceback formatting
629 # invoke IPython traceback formatting
630 shell.showtraceback()
630 shell.showtraceback()
631 # FIXME - fish exception info out of shell, possibly left there by
631 # FIXME - fish exception info out of shell, possibly left there by
632 # run_code. We'll need to clean up this logic later.
632 # run_code. We'll need to clean up this logic later.
633 reply_content = {}
633 reply_content = {}
634 if shell._reply_content is not None:
634 if shell._reply_content is not None:
635 reply_content.update(shell._reply_content)
635 reply_content.update(shell._reply_content)
636 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
636 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
637 reply_content['engine_info'] = e_info
637 reply_content['engine_info'] = e_info
638 # reset after use
638 # reset after use
639 shell._reply_content = None
639 shell._reply_content = None
640
640
641 self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
641 self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
642 ident=self._topic('pyerr'))
642 ident=self._topic('pyerr'))
643 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
643 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
644 result_buf = []
644 result_buf = []
645
645
646 if reply_content['ename'] == 'UnmetDependency':
646 if reply_content['ename'] == 'UnmetDependency':
647 md['dependencies_met'] = False
647 md['dependencies_met'] = False
648 else:
648 else:
649 reply_content = {'status' : 'ok'}
649 reply_content = {'status' : 'ok'}
650
650
651 # put 'ok'/'error' status in header, for scheduler introspection:
651 # put 'ok'/'error' status in header, for scheduler introspection:
652 md['status'] = reply_content['status']
652 md['status'] = reply_content['status']
653
653
654 # flush i/o
654 # flush i/o
655 sys.stdout.flush()
655 sys.stdout.flush()
656 sys.stderr.flush()
656 sys.stderr.flush()
657
657
658 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
658 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
659 parent=parent, ident=ident,buffers=result_buf, metadata=md)
659 parent=parent, ident=ident,buffers=result_buf, metadata=md)
660
660
661 self._publish_status(u'idle', parent)
661 self._publish_status(u'idle', parent)
662
662
663 #---------------------------------------------------------------------------
663 #---------------------------------------------------------------------------
664 # Control messages
664 # Control messages
665 #---------------------------------------------------------------------------
665 #---------------------------------------------------------------------------
666
666
667 def abort_request(self, stream, ident, parent):
667 def abort_request(self, stream, ident, parent):
668 """abort a specifig msg by id"""
668 """abort a specifig msg by id"""
669 msg_ids = parent['content'].get('msg_ids', None)
669 msg_ids = parent['content'].get('msg_ids', None)
670 if isinstance(msg_ids, basestring):
670 if isinstance(msg_ids, basestring):
671 msg_ids = [msg_ids]
671 msg_ids = [msg_ids]
672 if not msg_ids:
672 if not msg_ids:
673 self.abort_queues()
673 self.abort_queues()
674 for mid in msg_ids:
674 for mid in msg_ids:
675 self.aborted.add(str(mid))
675 self.aborted.add(str(mid))
676
676
677 content = dict(status='ok')
677 content = dict(status='ok')
678 reply_msg = self.session.send(stream, 'abort_reply', content=content,
678 reply_msg = self.session.send(stream, 'abort_reply', content=content,
679 parent=parent, ident=ident)
679 parent=parent, ident=ident)
680 self.log.debug("%s", reply_msg)
680 self.log.debug("%s", reply_msg)
681
681
682 def clear_request(self, stream, idents, parent):
682 def clear_request(self, stream, idents, parent):
683 """Clear our namespace."""
683 """Clear our namespace."""
684 self.shell.reset(False)
684 self.shell.reset(False)
685 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
685 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
686 content = dict(status='ok'))
686 content = dict(status='ok'))
687
687
688
688
689 #---------------------------------------------------------------------------
689 #---------------------------------------------------------------------------
690 # Protected interface
690 # Protected interface
691 #---------------------------------------------------------------------------
691 #---------------------------------------------------------------------------
692
692
693 def _wrap_exception(self, method=None):
693 def _wrap_exception(self, method=None):
694 # import here, because _wrap_exception is only used in parallel,
694 # import here, because _wrap_exception is only used in parallel,
695 # and parallel has higher min pyzmq version
695 # and parallel has higher min pyzmq version
696 from IPython.parallel.error import wrap_exception
696 from IPython.parallel.error import wrap_exception
697 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
697 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
698 content = wrap_exception(e_info)
698 content = wrap_exception(e_info)
699 return content
699 return content
700
700
701 def _topic(self, topic):
701 def _topic(self, topic):
702 """prefixed topic for IOPub messages"""
702 """prefixed topic for IOPub messages"""
703 if self.int_id >= 0:
703 if self.int_id >= 0:
704 base = "engine.%i" % self.int_id
704 base = "engine.%i" % self.int_id
705 else:
705 else:
706 base = "kernel.%s" % self.ident
706 base = "kernel.%s" % self.ident
707
707
708 return py3compat.cast_bytes("%s.%s" % (base, topic))
708 return py3compat.cast_bytes("%s.%s" % (base, topic))
709
709
710 def _abort_queues(self):
710 def _abort_queues(self):
711 for stream in self.shell_streams:
711 for stream in self.shell_streams:
712 if stream:
712 if stream:
713 self._abort_queue(stream)
713 self._abort_queue(stream)
714
714
715 def _abort_queue(self, stream):
715 def _abort_queue(self, stream):
716 poller = zmq.Poller()
716 poller = zmq.Poller()
717 poller.register(stream.socket, zmq.POLLIN)
717 poller.register(stream.socket, zmq.POLLIN)
718 while True:
718 while True:
719 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
719 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
720 if msg is None:
720 if msg is None:
721 return
721 return
722
722
723 self.log.info("Aborting:")
723 self.log.info("Aborting:")
724 self.log.info("%s", msg)
724 self.log.info("%s", msg)
725 msg_type = msg['header']['msg_type']
725 msg_type = msg['header']['msg_type']
726 reply_type = msg_type.split('_')[0] + '_reply'
726 reply_type = msg_type.split('_')[0] + '_reply'
727
727
728 status = {'status' : 'aborted'}
728 status = {'status' : 'aborted'}
729 md = {'engine' : self.ident}
729 md = {'engine' : self.ident}
730 md.update(status)
730 md.update(status)
731 reply_msg = self.session.send(stream, reply_type, metadata=md,
731 reply_msg = self.session.send(stream, reply_type, metadata=md,
732 content=status, parent=msg, ident=idents)
732 content=status, parent=msg, ident=idents)
733 self.log.debug("%s", reply_msg)
733 self.log.debug("%s", reply_msg)
734 # We need to wait a bit for requests to come in. This can probably
734 # We need to wait a bit for requests to come in. This can probably
735 # be set shorter for true asynchronous clients.
735 # be set shorter for true asynchronous clients.
736 poller.poll(50)
736 poller.poll(50)
737
737
738
738
739 def _no_raw_input(self):
739 def _no_raw_input(self):
740 """Raise StdinNotImplentedError if active frontend doesn't support
740 """Raise StdinNotImplentedError if active frontend doesn't support
741 stdin."""
741 stdin."""
742 raise StdinNotImplementedError("raw_input was called, but this "
742 raise StdinNotImplementedError("raw_input was called, but this "
743 "frontend does not support stdin.")
743 "frontend does not support stdin.")
744
744
745 def _raw_input(self, prompt, ident, parent):
745 def _raw_input(self, prompt, ident, parent):
746 # Flush output before making the request.
746 # Flush output before making the request.
747 sys.stderr.flush()
747 sys.stderr.flush()
748 sys.stdout.flush()
748 sys.stdout.flush()
749 # flush the stdin socket, to purge stale replies
750 while True:
751 try:
752 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
753 except zmq.ZMQError as e:
754 if e.errno == zmq.EAGAIN:
755 break
756 else:
757 raise
749
758
750 # Send the input request.
759 # Send the input request.
751 content = json_clean(dict(prompt=prompt))
760 content = json_clean(dict(prompt=prompt))
752 self.session.send(self.stdin_socket, u'input_request', content, parent,
761 self.session.send(self.stdin_socket, u'input_request', content, parent,
753 ident=ident)
762 ident=ident)
754
763
755 # Await a response.
764 # Await a response.
756 while True:
765 while True:
757 try:
766 try:
758 ident, reply = self.session.recv(self.stdin_socket, 0)
767 ident, reply = self.session.recv(self.stdin_socket, 0)
759 except Exception:
768 except Exception:
760 self.log.warn("Invalid Message:", exc_info=True)
769 self.log.warn("Invalid Message:", exc_info=True)
761 else:
770 else:
762 break
771 break
763 try:
772 try:
764 value = reply['content']['value']
773 value = reply['content']['value']
765 except:
774 except:
766 self.log.error("Got bad raw_input reply: ")
775 self.log.error("Got bad raw_input reply: ")
767 self.log.error("%s", parent)
776 self.log.error("%s", parent)
768 value = ''
777 value = ''
769 if value == '\x04':
778 if value == '\x04':
770 # EOF
779 # EOF
771 raise EOFError
780 raise EOFError
772 return value
781 return value
773
782
774 def _complete(self, msg):
783 def _complete(self, msg):
775 c = msg['content']
784 c = msg['content']
776 try:
785 try:
777 cpos = int(c['cursor_pos'])
786 cpos = int(c['cursor_pos'])
778 except:
787 except:
779 # If we don't get something that we can convert to an integer, at
788 # If we don't get something that we can convert to an integer, at
780 # least attempt the completion guessing the cursor is at the end of
789 # least attempt the completion guessing the cursor is at the end of
781 # the text, if there's any, and otherwise of the line
790 # the text, if there's any, and otherwise of the line
782 cpos = len(c['text'])
791 cpos = len(c['text'])
783 if cpos==0:
792 if cpos==0:
784 cpos = len(c['line'])
793 cpos = len(c['line'])
785 return self.shell.complete(c['text'], c['line'], cpos)
794 return self.shell.complete(c['text'], c['line'], cpos)
786
795
787 def _at_shutdown(self):
796 def _at_shutdown(self):
788 """Actions taken at shutdown by the kernel, called by python's atexit.
797 """Actions taken at shutdown by the kernel, called by python's atexit.
789 """
798 """
790 # io.rprint("Kernel at_shutdown") # dbg
799 # io.rprint("Kernel at_shutdown") # dbg
791 if self._shutdown_message is not None:
800 if self._shutdown_message is not None:
792 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
801 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
793 self.log.debug("%s", self._shutdown_message)
802 self.log.debug("%s", self._shutdown_message)
794 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
803 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
795
804
General Comments 0
You need to be logged in to leave comments. Login now