##// END OF EJS Templates
Merge remote-tracking branch 'upstream/master'
Doug Blank -
r15247:13bba28f merge
parent child Browse files
Show More
@@ -0,0 +1,102 b''
1 {
2 "metadata": {
3 "name": "",
4 "signature": "sha256:16dbf1191870d235be65800e4146b76c77118bb66575109c250a0cbce0e8e1ac"
5 },
6 "nbformat": 3,
7 "nbformat_minor": 0,
8 "worksheets": [
9 {
10 "cells": [
11 {
12 "cell_type": "code",
13 "collapsed": false,
14 "input": [
15 "# Should pop up a GUI window\n",
16 "%matplotlib\n",
17 "import matplotlib.pyplot as plt\n",
18 "plt.plot([1,2,3])"
19 ],
20 "language": "python",
21 "metadata": {},
22 "outputs": [
23 {
24 "output_type": "stream",
25 "stream": "stdout",
26 "text": [
27 "Using matplotlib backend: MacOSX\n"
28 ]
29 },
30 {
31 "metadata": {},
32 "output_type": "pyout",
33 "prompt_number": 1,
34 "text": [
35 "[<matplotlib.lines.Line2D at 0x10ce05350>]"
36 ]
37 }
38 ],
39 "prompt_number": 1
40 },
41 {
42 "cell_type": "code",
43 "collapsed": false,
44 "input": [
45 "# Should make an inline figure\n",
46 "%matplotlib inline\n",
47 "plt.plot([1,2,3])"
48 ],
49 "language": "python",
50 "metadata": {},
51 "outputs": [
52 {
53 "metadata": {},
54 "output_type": "pyout",
55 "prompt_number": 2,
56 "text": [
57 "[<matplotlib.lines.Line2D at 0x10cd5dfd0>]"
58 ]
59 },
60 {
61 "metadata": {
62 "png": {
63 "height": 379,
64 "width": 600
65 }
66 },
67 "output_type": "display_data",
68 "png": "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\n",
69 "text": [
70 "<matplotlib.figure.Figure at 0x10cdeea50>"
71 ]
72 }
73 ],
74 "prompt_number": 2
75 },
76 {
77 "cell_type": "code",
78 "collapsed": false,
79 "input": [
80 "# New GUI window--should *NOT* have the visual settings of inline\n",
81 "%matplotlib qt\n",
82 "plt.plot([1,2,3])"
83 ],
84 "language": "python",
85 "metadata": {},
86 "outputs": [
87 {
88 "metadata": {},
89 "output_type": "pyout",
90 "prompt_number": 3,
91 "text": [
92 "[<matplotlib.lines.Line2D at 0x10cd9cb10>]"
93 ]
94 }
95 ],
96 "prompt_number": 3
97 }
98 ],
99 "metadata": {}
100 }
101 ]
102 } No newline at end of file
@@ -1,701 +1,772 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats.
2 """Top-level display functions for displaying object in different formats.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2013 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from __future__ import print_function
20 from __future__ import print_function
21
21
22 import os
22 import os
23 import struct
23 import struct
24
24
25 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
25 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
26 unicode_type)
26 unicode_type)
27
27 from IPython.testing.skipdoctest import skip_doctest
28 from .displaypub import publish_display_data
28 from .displaypub import publish_display_data
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # utility functions
31 # utility functions
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 def _safe_exists(path):
34 def _safe_exists(path):
35 """Check path, but don't let exceptions raise"""
35 """Check path, but don't let exceptions raise"""
36 try:
36 try:
37 return os.path.exists(path)
37 return os.path.exists(path)
38 except Exception:
38 except Exception:
39 return False
39 return False
40
40
41 def _merge(d1, d2):
41 def _merge(d1, d2):
42 """Like update, but merges sub-dicts instead of clobbering at the top level.
42 """Like update, but merges sub-dicts instead of clobbering at the top level.
43
43
44 Updates d1 in-place
44 Updates d1 in-place
45 """
45 """
46
46
47 if not isinstance(d2, dict) or not isinstance(d1, dict):
47 if not isinstance(d2, dict) or not isinstance(d1, dict):
48 return d2
48 return d2
49 for key, value in d2.items():
49 for key, value in d2.items():
50 d1[key] = _merge(d1.get(key), value)
50 d1[key] = _merge(d1.get(key), value)
51 return d1
51 return d1
52
52
53 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
53 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
54 """internal implementation of all display_foo methods
54 """internal implementation of all display_foo methods
55
55
56 Parameters
56 Parameters
57 ----------
57 ----------
58 mimetype : str
58 mimetype : str
59 The mimetype to be published (e.g. 'image/png')
59 The mimetype to be published (e.g. 'image/png')
60 objs : tuple of objects
60 objs : tuple of objects
61 The Python objects to display, or if raw=True raw text data to
61 The Python objects to display, or if raw=True raw text data to
62 display.
62 display.
63 raw : bool
63 raw : bool
64 Are the data objects raw data or Python objects that need to be
64 Are the data objects raw data or Python objects that need to be
65 formatted before display? [default: False]
65 formatted before display? [default: False]
66 metadata : dict (optional)
66 metadata : dict (optional)
67 Metadata to be associated with the specific mimetype output.
67 Metadata to be associated with the specific mimetype output.
68 """
68 """
69 if metadata:
69 if metadata:
70 metadata = {mimetype: metadata}
70 metadata = {mimetype: metadata}
71 if raw:
71 if raw:
72 # turn list of pngdata into list of { 'image/png': pngdata }
72 # turn list of pngdata into list of { 'image/png': pngdata }
73 objs = [ {mimetype: obj} for obj in objs ]
73 objs = [ {mimetype: obj} for obj in objs ]
74 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
74 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
75
75
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77 # Main functions
77 # Main functions
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79
79
80 def display(*objs, **kwargs):
80 def display(*objs, **kwargs):
81 """Display a Python object in all frontends.
81 """Display a Python object in all frontends.
82
82
83 By default all representations will be computed and sent to the frontends.
83 By default all representations will be computed and sent to the frontends.
84 Frontends can decide which representation is used and how.
84 Frontends can decide which representation is used and how.
85
85
86 Parameters
86 Parameters
87 ----------
87 ----------
88 objs : tuple of objects
88 objs : tuple of objects
89 The Python objects to display.
89 The Python objects to display.
90 raw : bool, optional
90 raw : bool, optional
91 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
91 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
92 or Python objects that need to be formatted before display? [default: False]
92 or Python objects that need to be formatted before display? [default: False]
93 include : list or tuple, optional
93 include : list or tuple, optional
94 A list of format type strings (MIME types) to include in the
94 A list of format type strings (MIME types) to include in the
95 format data dict. If this is set *only* the format types included
95 format data dict. If this is set *only* the format types included
96 in this list will be computed.
96 in this list will be computed.
97 exclude : list or tuple, optional
97 exclude : list or tuple, optional
98 A list of format type strings (MIME types) to exclude in the format
98 A list of format type strings (MIME types) to exclude in the format
99 data dict. If this is set all format types will be computed,
99 data dict. If this is set all format types will be computed,
100 except for those included in this argument.
100 except for those included in this argument.
101 metadata : dict, optional
101 metadata : dict, optional
102 A dictionary of metadata to associate with the output.
102 A dictionary of metadata to associate with the output.
103 mime-type keys in this dictionary will be associated with the individual
103 mime-type keys in this dictionary will be associated with the individual
104 representation formats, if they exist.
104 representation formats, if they exist.
105 """
105 """
106 raw = kwargs.get('raw', False)
106 raw = kwargs.get('raw', False)
107 include = kwargs.get('include')
107 include = kwargs.get('include')
108 exclude = kwargs.get('exclude')
108 exclude = kwargs.get('exclude')
109 metadata = kwargs.get('metadata')
109 metadata = kwargs.get('metadata')
110
110
111 from IPython.core.interactiveshell import InteractiveShell
111 from IPython.core.interactiveshell import InteractiveShell
112
112
113 if not raw:
113 if not raw:
114 format = InteractiveShell.instance().display_formatter.format
114 format = InteractiveShell.instance().display_formatter.format
115
115
116 for obj in objs:
116 for obj in objs:
117
117
118 # If _ipython_display_ is defined, use that to display this object.
118 # If _ipython_display_ is defined, use that to display this object.
119 display_method = getattr(obj, '_ipython_display_', None)
119 display_method = getattr(obj, '_ipython_display_', None)
120 if display_method is not None:
120 if display_method is not None:
121 try:
121 try:
122 display_method(**kwargs)
122 display_method(**kwargs)
123 except NotImplementedError:
123 except NotImplementedError:
124 pass
124 pass
125 else:
125 else:
126 continue
126 continue
127 if raw:
127 if raw:
128 publish_display_data('display', obj, metadata)
128 publish_display_data('display', obj, metadata)
129 else:
129 else:
130 format_dict, md_dict = format(obj, include=include, exclude=exclude)
130 format_dict, md_dict = format(obj, include=include, exclude=exclude)
131 if metadata:
131 if metadata:
132 # kwarg-specified metadata gets precedence
132 # kwarg-specified metadata gets precedence
133 _merge(md_dict, metadata)
133 _merge(md_dict, metadata)
134 publish_display_data('display', format_dict, md_dict)
134 publish_display_data('display', format_dict, md_dict)
135
135
136
136
137 def display_pretty(*objs, **kwargs):
137 def display_pretty(*objs, **kwargs):
138 """Display the pretty (default) representation of an object.
138 """Display the pretty (default) representation of an object.
139
139
140 Parameters
140 Parameters
141 ----------
141 ----------
142 objs : tuple of objects
142 objs : tuple of objects
143 The Python objects to display, or if raw=True raw text data to
143 The Python objects to display, or if raw=True raw text data to
144 display.
144 display.
145 raw : bool
145 raw : bool
146 Are the data objects raw data or Python objects that need to be
146 Are the data objects raw data or Python objects that need to be
147 formatted before display? [default: False]
147 formatted before display? [default: False]
148 metadata : dict (optional)
148 metadata : dict (optional)
149 Metadata to be associated with the specific mimetype output.
149 Metadata to be associated with the specific mimetype output.
150 """
150 """
151 _display_mimetype('text/plain', objs, **kwargs)
151 _display_mimetype('text/plain', objs, **kwargs)
152
152
153
153
154 def display_html(*objs, **kwargs):
154 def display_html(*objs, **kwargs):
155 """Display the HTML representation of an object.
155 """Display the HTML representation of an object.
156
156
157 Parameters
157 Parameters
158 ----------
158 ----------
159 objs : tuple of objects
159 objs : tuple of objects
160 The Python objects to display, or if raw=True raw HTML data to
160 The Python objects to display, or if raw=True raw HTML data to
161 display.
161 display.
162 raw : bool
162 raw : bool
163 Are the data objects raw data or Python objects that need to be
163 Are the data objects raw data or Python objects that need to be
164 formatted before display? [default: False]
164 formatted before display? [default: False]
165 metadata : dict (optional)
165 metadata : dict (optional)
166 Metadata to be associated with the specific mimetype output.
166 Metadata to be associated with the specific mimetype output.
167 """
167 """
168 _display_mimetype('text/html', objs, **kwargs)
168 _display_mimetype('text/html', objs, **kwargs)
169
169
170
170
171 def display_svg(*objs, **kwargs):
171 def display_svg(*objs, **kwargs):
172 """Display the SVG representation of an object.
172 """Display the SVG representation of an object.
173
173
174 Parameters
174 Parameters
175 ----------
175 ----------
176 objs : tuple of objects
176 objs : tuple of objects
177 The Python objects to display, or if raw=True raw svg data to
177 The Python objects to display, or if raw=True raw svg data to
178 display.
178 display.
179 raw : bool
179 raw : bool
180 Are the data objects raw data or Python objects that need to be
180 Are the data objects raw data or Python objects that need to be
181 formatted before display? [default: False]
181 formatted before display? [default: False]
182 metadata : dict (optional)
182 metadata : dict (optional)
183 Metadata to be associated with the specific mimetype output.
183 Metadata to be associated with the specific mimetype output.
184 """
184 """
185 _display_mimetype('image/svg+xml', objs, **kwargs)
185 _display_mimetype('image/svg+xml', objs, **kwargs)
186
186
187
187
188 def display_png(*objs, **kwargs):
188 def display_png(*objs, **kwargs):
189 """Display the PNG representation of an object.
189 """Display the PNG representation of an object.
190
190
191 Parameters
191 Parameters
192 ----------
192 ----------
193 objs : tuple of objects
193 objs : tuple of objects
194 The Python objects to display, or if raw=True raw png data to
194 The Python objects to display, or if raw=True raw png data to
195 display.
195 display.
196 raw : bool
196 raw : bool
197 Are the data objects raw data or Python objects that need to be
197 Are the data objects raw data or Python objects that need to be
198 formatted before display? [default: False]
198 formatted before display? [default: False]
199 metadata : dict (optional)
199 metadata : dict (optional)
200 Metadata to be associated with the specific mimetype output.
200 Metadata to be associated with the specific mimetype output.
201 """
201 """
202 _display_mimetype('image/png', objs, **kwargs)
202 _display_mimetype('image/png', objs, **kwargs)
203
203
204
204
205 def display_jpeg(*objs, **kwargs):
205 def display_jpeg(*objs, **kwargs):
206 """Display the JPEG representation of an object.
206 """Display the JPEG representation of an object.
207
207
208 Parameters
208 Parameters
209 ----------
209 ----------
210 objs : tuple of objects
210 objs : tuple of objects
211 The Python objects to display, or if raw=True raw JPEG data to
211 The Python objects to display, or if raw=True raw JPEG data to
212 display.
212 display.
213 raw : bool
213 raw : bool
214 Are the data objects raw data or Python objects that need to be
214 Are the data objects raw data or Python objects that need to be
215 formatted before display? [default: False]
215 formatted before display? [default: False]
216 metadata : dict (optional)
216 metadata : dict (optional)
217 Metadata to be associated with the specific mimetype output.
217 Metadata to be associated with the specific mimetype output.
218 """
218 """
219 _display_mimetype('image/jpeg', objs, **kwargs)
219 _display_mimetype('image/jpeg', objs, **kwargs)
220
220
221
221
222 def display_latex(*objs, **kwargs):
222 def display_latex(*objs, **kwargs):
223 """Display the LaTeX representation of an object.
223 """Display the LaTeX representation of an object.
224
224
225 Parameters
225 Parameters
226 ----------
226 ----------
227 objs : tuple of objects
227 objs : tuple of objects
228 The Python objects to display, or if raw=True raw latex data to
228 The Python objects to display, or if raw=True raw latex data to
229 display.
229 display.
230 raw : bool
230 raw : bool
231 Are the data objects raw data or Python objects that need to be
231 Are the data objects raw data or Python objects that need to be
232 formatted before display? [default: False]
232 formatted before display? [default: False]
233 metadata : dict (optional)
233 metadata : dict (optional)
234 Metadata to be associated with the specific mimetype output.
234 Metadata to be associated with the specific mimetype output.
235 """
235 """
236 _display_mimetype('text/latex', objs, **kwargs)
236 _display_mimetype('text/latex', objs, **kwargs)
237
237
238
238
239 def display_json(*objs, **kwargs):
239 def display_json(*objs, **kwargs):
240 """Display the JSON representation of an object.
240 """Display the JSON representation of an object.
241
241
242 Note that not many frontends support displaying JSON.
242 Note that not many frontends support displaying JSON.
243
243
244 Parameters
244 Parameters
245 ----------
245 ----------
246 objs : tuple of objects
246 objs : tuple of objects
247 The Python objects to display, or if raw=True raw json data to
247 The Python objects to display, or if raw=True raw json data to
248 display.
248 display.
249 raw : bool
249 raw : bool
250 Are the data objects raw data or Python objects that need to be
250 Are the data objects raw data or Python objects that need to be
251 formatted before display? [default: False]
251 formatted before display? [default: False]
252 metadata : dict (optional)
252 metadata : dict (optional)
253 Metadata to be associated with the specific mimetype output.
253 Metadata to be associated with the specific mimetype output.
254 """
254 """
255 _display_mimetype('application/json', objs, **kwargs)
255 _display_mimetype('application/json', objs, **kwargs)
256
256
257
257
258 def display_javascript(*objs, **kwargs):
258 def display_javascript(*objs, **kwargs):
259 """Display the Javascript representation of an object.
259 """Display the Javascript representation of an object.
260
260
261 Parameters
261 Parameters
262 ----------
262 ----------
263 objs : tuple of objects
263 objs : tuple of objects
264 The Python objects to display, or if raw=True raw javascript data to
264 The Python objects to display, or if raw=True raw javascript data to
265 display.
265 display.
266 raw : bool
266 raw : bool
267 Are the data objects raw data or Python objects that need to be
267 Are the data objects raw data or Python objects that need to be
268 formatted before display? [default: False]
268 formatted before display? [default: False]
269 metadata : dict (optional)
269 metadata : dict (optional)
270 Metadata to be associated with the specific mimetype output.
270 Metadata to be associated with the specific mimetype output.
271 """
271 """
272 _display_mimetype('application/javascript', objs, **kwargs)
272 _display_mimetype('application/javascript', objs, **kwargs)
273
273
274
275 def display_pdf(*objs, **kwargs):
276 """Display the PDF representation of an object.
277
278 Parameters
279 ----------
280 objs : tuple of objects
281 The Python objects to display, or if raw=True raw javascript data to
282 display.
283 raw : bool
284 Are the data objects raw data or Python objects that need to be
285 formatted before display? [default: False]
286 metadata : dict (optional)
287 Metadata to be associated with the specific mimetype output.
288 """
289 _display_mimetype('application/pdf', objs, **kwargs)
290
291
274 #-----------------------------------------------------------------------------
292 #-----------------------------------------------------------------------------
275 # Smart classes
293 # Smart classes
276 #-----------------------------------------------------------------------------
294 #-----------------------------------------------------------------------------
277
295
278
296
279 class DisplayObject(object):
297 class DisplayObject(object):
280 """An object that wraps data to be displayed."""
298 """An object that wraps data to be displayed."""
281
299
282 _read_flags = 'r'
300 _read_flags = 'r'
283
301
284 def __init__(self, data=None, url=None, filename=None):
302 def __init__(self, data=None, url=None, filename=None):
285 """Create a display object given raw data.
303 """Create a display object given raw data.
286
304
287 When this object is returned by an expression or passed to the
305 When this object is returned by an expression or passed to the
288 display function, it will result in the data being displayed
306 display function, it will result in the data being displayed
289 in the frontend. The MIME type of the data should match the
307 in the frontend. The MIME type of the data should match the
290 subclasses used, so the Png subclass should be used for 'image/png'
308 subclasses used, so the Png subclass should be used for 'image/png'
291 data. If the data is a URL, the data will first be downloaded
309 data. If the data is a URL, the data will first be downloaded
292 and then displayed. If
310 and then displayed. If
293
311
294 Parameters
312 Parameters
295 ----------
313 ----------
296 data : unicode, str or bytes
314 data : unicode, str or bytes
297 The raw data or a URL or file to load the data from
315 The raw data or a URL or file to load the data from
298 url : unicode
316 url : unicode
299 A URL to download the data from.
317 A URL to download the data from.
300 filename : unicode
318 filename : unicode
301 Path to a local file to load the data from.
319 Path to a local file to load the data from.
302 """
320 """
303 if data is not None and isinstance(data, string_types):
321 if data is not None and isinstance(data, string_types):
304 if data.startswith('http') and url is None:
322 if data.startswith('http') and url is None:
305 url = data
323 url = data
306 filename = None
324 filename = None
307 data = None
325 data = None
308 elif _safe_exists(data) and filename is None:
326 elif _safe_exists(data) and filename is None:
309 url = None
327 url = None
310 filename = data
328 filename = data
311 data = None
329 data = None
312
330
313 self.data = data
331 self.data = data
314 self.url = url
332 self.url = url
315 self.filename = None if filename is None else unicode_type(filename)
333 self.filename = None if filename is None else unicode_type(filename)
316
334
317 self.reload()
335 self.reload()
318 self._check_data()
336 self._check_data()
319
337
320 def _check_data(self):
338 def _check_data(self):
321 """Override in subclasses if there's something to check."""
339 """Override in subclasses if there's something to check."""
322 pass
340 pass
323
341
324 def reload(self):
342 def reload(self):
325 """Reload the raw data from file or URL."""
343 """Reload the raw data from file or URL."""
326 if self.filename is not None:
344 if self.filename is not None:
327 with open(self.filename, self._read_flags) as f:
345 with open(self.filename, self._read_flags) as f:
328 self.data = f.read()
346 self.data = f.read()
329 elif self.url is not None:
347 elif self.url is not None:
330 try:
348 try:
331 try:
349 try:
332 from urllib.request import urlopen # Py3
350 from urllib.request import urlopen # Py3
333 except ImportError:
351 except ImportError:
334 from urllib2 import urlopen
352 from urllib2 import urlopen
335 response = urlopen(self.url)
353 response = urlopen(self.url)
336 self.data = response.read()
354 self.data = response.read()
337 # extract encoding from header, if there is one:
355 # extract encoding from header, if there is one:
338 encoding = None
356 encoding = None
339 for sub in response.headers['content-type'].split(';'):
357 for sub in response.headers['content-type'].split(';'):
340 sub = sub.strip()
358 sub = sub.strip()
341 if sub.startswith('charset'):
359 if sub.startswith('charset'):
342 encoding = sub.split('=')[-1].strip()
360 encoding = sub.split('=')[-1].strip()
343 break
361 break
344 # decode data, if an encoding was specified
362 # decode data, if an encoding was specified
345 if encoding:
363 if encoding:
346 self.data = self.data.decode(encoding, 'replace')
364 self.data = self.data.decode(encoding, 'replace')
347 except:
365 except:
348 self.data = None
366 self.data = None
349
367
350 class TextDisplayObject(DisplayObject):
368 class TextDisplayObject(DisplayObject):
351 """Validate that display data is text"""
369 """Validate that display data is text"""
352 def _check_data(self):
370 def _check_data(self):
353 if self.data is not None and not isinstance(self.data, string_types):
371 if self.data is not None and not isinstance(self.data, string_types):
354 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
372 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
355
373
356 class Pretty(TextDisplayObject):
374 class Pretty(TextDisplayObject):
357
375
358 def _repr_pretty_(self):
376 def _repr_pretty_(self):
359 return self.data
377 return self.data
360
378
361
379
362 class HTML(TextDisplayObject):
380 class HTML(TextDisplayObject):
363
381
364 def _repr_html_(self):
382 def _repr_html_(self):
365 return self.data
383 return self.data
366
384
367 def __html__(self):
385 def __html__(self):
368 """
386 """
369 This method exists to inform other HTML-using modules (e.g. Markupsafe,
387 This method exists to inform other HTML-using modules (e.g. Markupsafe,
370 htmltag, etc) that this object is HTML and does not need things like
388 htmltag, etc) that this object is HTML and does not need things like
371 special characters (<>&) escaped.
389 special characters (<>&) escaped.
372 """
390 """
373 return self._repr_html_()
391 return self._repr_html_()
374
392
375
393
376 class Math(TextDisplayObject):
394 class Math(TextDisplayObject):
377
395
378 def _repr_latex_(self):
396 def _repr_latex_(self):
379 s = self.data.strip('$')
397 s = self.data.strip('$')
380 return "$$%s$$" % s
398 return "$$%s$$" % s
381
399
382
400
383 class Latex(TextDisplayObject):
401 class Latex(TextDisplayObject):
384
402
385 def _repr_latex_(self):
403 def _repr_latex_(self):
386 return self.data
404 return self.data
387
405
388
406
389 class SVG(DisplayObject):
407 class SVG(DisplayObject):
390
408
391 # wrap data in a property, which extracts the <svg> tag, discarding
409 # wrap data in a property, which extracts the <svg> tag, discarding
392 # document headers
410 # document headers
393 _data = None
411 _data = None
394
412
395 @property
413 @property
396 def data(self):
414 def data(self):
397 return self._data
415 return self._data
398
416
399 @data.setter
417 @data.setter
400 def data(self, svg):
418 def data(self, svg):
401 if svg is None:
419 if svg is None:
402 self._data = None
420 self._data = None
403 return
421 return
404 # parse into dom object
422 # parse into dom object
405 from xml.dom import minidom
423 from xml.dom import minidom
406 svg = cast_bytes_py2(svg)
424 svg = cast_bytes_py2(svg)
407 x = minidom.parseString(svg)
425 x = minidom.parseString(svg)
408 # get svg tag (should be 1)
426 # get svg tag (should be 1)
409 found_svg = x.getElementsByTagName('svg')
427 found_svg = x.getElementsByTagName('svg')
410 if found_svg:
428 if found_svg:
411 svg = found_svg[0].toxml()
429 svg = found_svg[0].toxml()
412 else:
430 else:
413 # fallback on the input, trust the user
431 # fallback on the input, trust the user
414 # but this is probably an error.
432 # but this is probably an error.
415 pass
433 pass
416 svg = cast_unicode(svg)
434 svg = cast_unicode(svg)
417 self._data = svg
435 self._data = svg
418
436
419 def _repr_svg_(self):
437 def _repr_svg_(self):
420 return self.data
438 return self.data
421
439
422
440
423 class JSON(TextDisplayObject):
441 class JSON(TextDisplayObject):
424
442
425 def _repr_json_(self):
443 def _repr_json_(self):
426 return self.data
444 return self.data
427
445
428 css_t = """$("head").append($("<link/>").attr({
446 css_t = """$("head").append($("<link/>").attr({
429 rel: "stylesheet",
447 rel: "stylesheet",
430 type: "text/css",
448 type: "text/css",
431 href: "%s"
449 href: "%s"
432 }));
450 }));
433 """
451 """
434
452
435 lib_t1 = """$.getScript("%s", function () {
453 lib_t1 = """$.getScript("%s", function () {
436 """
454 """
437 lib_t2 = """});
455 lib_t2 = """});
438 """
456 """
439
457
440 class Javascript(TextDisplayObject):
458 class Javascript(TextDisplayObject):
441
459
442 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
460 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
443 """Create a Javascript display object given raw data.
461 """Create a Javascript display object given raw data.
444
462
445 When this object is returned by an expression or passed to the
463 When this object is returned by an expression or passed to the
446 display function, it will result in the data being displayed
464 display function, it will result in the data being displayed
447 in the frontend. If the data is a URL, the data will first be
465 in the frontend. If the data is a URL, the data will first be
448 downloaded and then displayed.
466 downloaded and then displayed.
449
467
450 In the Notebook, the containing element will be available as `element`,
468 In the Notebook, the containing element will be available as `element`,
451 and jQuery will be available. The output area starts hidden, so if
469 and jQuery will be available. The output area starts hidden, so if
452 the js appends content to `element` that should be visible, then
470 the js appends content to `element` that should be visible, then
453 it must call `container.show()` to unhide the area.
471 it must call `container.show()` to unhide the area.
454
472
455 Parameters
473 Parameters
456 ----------
474 ----------
457 data : unicode, str or bytes
475 data : unicode, str or bytes
458 The Javascript source code or a URL to download it from.
476 The Javascript source code or a URL to download it from.
459 url : unicode
477 url : unicode
460 A URL to download the data from.
478 A URL to download the data from.
461 filename : unicode
479 filename : unicode
462 Path to a local file to load the data from.
480 Path to a local file to load the data from.
463 lib : list or str
481 lib : list or str
464 A sequence of Javascript library URLs to load asynchronously before
482 A sequence of Javascript library URLs to load asynchronously before
465 running the source code. The full URLs of the libraries should
483 running the source code. The full URLs of the libraries should
466 be given. A single Javascript library URL can also be given as a
484 be given. A single Javascript library URL can also be given as a
467 string.
485 string.
468 css: : list or str
486 css: : list or str
469 A sequence of css files to load before running the source code.
487 A sequence of css files to load before running the source code.
470 The full URLs of the css files should be given. A single css URL
488 The full URLs of the css files should be given. A single css URL
471 can also be given as a string.
489 can also be given as a string.
472 """
490 """
473 if isinstance(lib, string_types):
491 if isinstance(lib, string_types):
474 lib = [lib]
492 lib = [lib]
475 elif lib is None:
493 elif lib is None:
476 lib = []
494 lib = []
477 if isinstance(css, string_types):
495 if isinstance(css, string_types):
478 css = [css]
496 css = [css]
479 elif css is None:
497 elif css is None:
480 css = []
498 css = []
481 if not isinstance(lib, (list,tuple)):
499 if not isinstance(lib, (list,tuple)):
482 raise TypeError('expected sequence, got: %r' % lib)
500 raise TypeError('expected sequence, got: %r' % lib)
483 if not isinstance(css, (list,tuple)):
501 if not isinstance(css, (list,tuple)):
484 raise TypeError('expected sequence, got: %r' % css)
502 raise TypeError('expected sequence, got: %r' % css)
485 self.lib = lib
503 self.lib = lib
486 self.css = css
504 self.css = css
487 super(Javascript, self).__init__(data=data, url=url, filename=filename)
505 super(Javascript, self).__init__(data=data, url=url, filename=filename)
488
506
489 def _repr_javascript_(self):
507 def _repr_javascript_(self):
490 r = ''
508 r = ''
491 for c in self.css:
509 for c in self.css:
492 r += css_t % c
510 r += css_t % c
493 for l in self.lib:
511 for l in self.lib:
494 r += lib_t1 % l
512 r += lib_t1 % l
495 r += self.data
513 r += self.data
496 r += lib_t2*len(self.lib)
514 r += lib_t2*len(self.lib)
497 return r
515 return r
498
516
499 # constants for identifying png/jpeg data
517 # constants for identifying png/jpeg data
500 _PNG = b'\x89PNG\r\n\x1a\n'
518 _PNG = b'\x89PNG\r\n\x1a\n'
501 _JPEG = b'\xff\xd8'
519 _JPEG = b'\xff\xd8'
502
520
503 def _pngxy(data):
521 def _pngxy(data):
504 """read the (width, height) from a PNG header"""
522 """read the (width, height) from a PNG header"""
505 ihdr = data.index(b'IHDR')
523 ihdr = data.index(b'IHDR')
506 # next 8 bytes are width/height
524 # next 8 bytes are width/height
507 w4h4 = data[ihdr+4:ihdr+12]
525 w4h4 = data[ihdr+4:ihdr+12]
508 return struct.unpack('>ii', w4h4)
526 return struct.unpack('>ii', w4h4)
509
527
510 def _jpegxy(data):
528 def _jpegxy(data):
511 """read the (width, height) from a JPEG header"""
529 """read the (width, height) from a JPEG header"""
512 # adapted from http://www.64lines.com/jpeg-width-height
530 # adapted from http://www.64lines.com/jpeg-width-height
513
531
514 idx = 4
532 idx = 4
515 while True:
533 while True:
516 block_size = struct.unpack('>H', data[idx:idx+2])[0]
534 block_size = struct.unpack('>H', data[idx:idx+2])[0]
517 idx = idx + block_size
535 idx = idx + block_size
518 if data[idx:idx+2] == b'\xFF\xC0':
536 if data[idx:idx+2] == b'\xFF\xC0':
519 # found Start of Frame
537 # found Start of Frame
520 iSOF = idx
538 iSOF = idx
521 break
539 break
522 else:
540 else:
523 # read another block
541 # read another block
524 idx += 2
542 idx += 2
525
543
526 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
544 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
527 return w, h
545 return w, h
528
546
529 class Image(DisplayObject):
547 class Image(DisplayObject):
530
548
531 _read_flags = 'rb'
549 _read_flags = 'rb'
532 _FMT_JPEG = u'jpeg'
550 _FMT_JPEG = u'jpeg'
533 _FMT_PNG = u'png'
551 _FMT_PNG = u'png'
534 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
552 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
535
553
536 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
554 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
537 """Create a PNG/JPEG image object given raw data.
555 """Create a PNG/JPEG image object given raw data.
538
556
539 When this object is returned by an input cell or passed to the
557 When this object is returned by an input cell or passed to the
540 display function, it will result in the image being displayed
558 display function, it will result in the image being displayed
541 in the frontend.
559 in the frontend.
542
560
543 Parameters
561 Parameters
544 ----------
562 ----------
545 data : unicode, str or bytes
563 data : unicode, str or bytes
546 The raw image data or a URL or filename to load the data from.
564 The raw image data or a URL or filename to load the data from.
547 This always results in embedded image data.
565 This always results in embedded image data.
548 url : unicode
566 url : unicode
549 A URL to download the data from. If you specify `url=`,
567 A URL to download the data from. If you specify `url=`,
550 the image data will not be embedded unless you also specify `embed=True`.
568 the image data will not be embedded unless you also specify `embed=True`.
551 filename : unicode
569 filename : unicode
552 Path to a local file to load the data from.
570 Path to a local file to load the data from.
553 Images from a file are always embedded.
571 Images from a file are always embedded.
554 format : unicode
572 format : unicode
555 The format of the image data (png/jpeg/jpg). If a filename or URL is given
573 The format of the image data (png/jpeg/jpg). If a filename or URL is given
556 for format will be inferred from the filename extension.
574 for format will be inferred from the filename extension.
557 embed : bool
575 embed : bool
558 Should the image data be embedded using a data URI (True) or be
576 Should the image data be embedded using a data URI (True) or be
559 loaded using an <img> tag. Set this to True if you want the image
577 loaded using an <img> tag. Set this to True if you want the image
560 to be viewable later with no internet connection in the notebook.
578 to be viewable later with no internet connection in the notebook.
561
579
562 Default is `True`, unless the keyword argument `url` is set, then
580 Default is `True`, unless the keyword argument `url` is set, then
563 default value is `False`.
581 default value is `False`.
564
582
565 Note that QtConsole is not able to display images if `embed` is set to `False`
583 Note that QtConsole is not able to display images if `embed` is set to `False`
566 width : int
584 width : int
567 Width to which to constrain the image in html
585 Width to which to constrain the image in html
568 height : int
586 height : int
569 Height to which to constrain the image in html
587 Height to which to constrain the image in html
570 retina : bool
588 retina : bool
571 Automatically set the width and height to half of the measured
589 Automatically set the width and height to half of the measured
572 width and height.
590 width and height.
573 This only works for embedded images because it reads the width/height
591 This only works for embedded images because it reads the width/height
574 from image data.
592 from image data.
575 For non-embedded images, you can just set the desired display width
593 For non-embedded images, you can just set the desired display width
576 and height directly.
594 and height directly.
577
595
578 Examples
596 Examples
579 --------
597 --------
580 # embedded image data, works in qtconsole and notebook
598 # embedded image data, works in qtconsole and notebook
581 # when passed positionally, the first arg can be any of raw image data,
599 # when passed positionally, the first arg can be any of raw image data,
582 # a URL, or a filename from which to load image data.
600 # a URL, or a filename from which to load image data.
583 # The result is always embedding image data for inline images.
601 # The result is always embedding image data for inline images.
584 Image('http://www.google.fr/images/srpr/logo3w.png')
602 Image('http://www.google.fr/images/srpr/logo3w.png')
585 Image('/path/to/image.jpg')
603 Image('/path/to/image.jpg')
586 Image(b'RAW_PNG_DATA...')
604 Image(b'RAW_PNG_DATA...')
587
605
588 # Specifying Image(url=...) does not embed the image data,
606 # Specifying Image(url=...) does not embed the image data,
589 # it only generates `<img>` tag with a link to the source.
607 # it only generates `<img>` tag with a link to the source.
590 # This will not work in the qtconsole or offline.
608 # This will not work in the qtconsole or offline.
591 Image(url='http://www.google.fr/images/srpr/logo3w.png')
609 Image(url='http://www.google.fr/images/srpr/logo3w.png')
592
610
593 """
611 """
594 if filename is not None:
612 if filename is not None:
595 ext = self._find_ext(filename)
613 ext = self._find_ext(filename)
596 elif url is not None:
614 elif url is not None:
597 ext = self._find_ext(url)
615 ext = self._find_ext(url)
598 elif data is None:
616 elif data is None:
599 raise ValueError("No image data found. Expecting filename, url, or data.")
617 raise ValueError("No image data found. Expecting filename, url, or data.")
600 elif isinstance(data, string_types) and (
618 elif isinstance(data, string_types) and (
601 data.startswith('http') or _safe_exists(data)
619 data.startswith('http') or _safe_exists(data)
602 ):
620 ):
603 ext = self._find_ext(data)
621 ext = self._find_ext(data)
604 else:
622 else:
605 ext = None
623 ext = None
606
624
607 if ext is not None:
625 if ext is not None:
608 format = ext.lower()
626 format = ext.lower()
609 if ext == u'jpg' or ext == u'jpeg':
627 if ext == u'jpg' or ext == u'jpeg':
610 format = self._FMT_JPEG
628 format = self._FMT_JPEG
611 if ext == u'png':
629 if ext == u'png':
612 format = self._FMT_PNG
630 format = self._FMT_PNG
613 elif isinstance(data, bytes) and format == 'png':
631 elif isinstance(data, bytes) and format == 'png':
614 # infer image type from image data header,
632 # infer image type from image data header,
615 # only if format might not have been specified.
633 # only if format might not have been specified.
616 if data[:2] == _JPEG:
634 if data[:2] == _JPEG:
617 format = 'jpeg'
635 format = 'jpeg'
618
636
619 self.format = unicode_type(format).lower()
637 self.format = unicode_type(format).lower()
620 self.embed = embed if embed is not None else (url is None)
638 self.embed = embed if embed is not None else (url is None)
621
639
622 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
640 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
623 raise ValueError("Cannot embed the '%s' image format" % (self.format))
641 raise ValueError("Cannot embed the '%s' image format" % (self.format))
624 self.width = width
642 self.width = width
625 self.height = height
643 self.height = height
626 self.retina = retina
644 self.retina = retina
627 super(Image, self).__init__(data=data, url=url, filename=filename)
645 super(Image, self).__init__(data=data, url=url, filename=filename)
628
646
629 if retina:
647 if retina:
630 self._retina_shape()
648 self._retina_shape()
631
649
632 def _retina_shape(self):
650 def _retina_shape(self):
633 """load pixel-doubled width and height from image data"""
651 """load pixel-doubled width and height from image data"""
634 if not self.embed:
652 if not self.embed:
635 return
653 return
636 if self.format == 'png':
654 if self.format == 'png':
637 w, h = _pngxy(self.data)
655 w, h = _pngxy(self.data)
638 elif self.format == 'jpeg':
656 elif self.format == 'jpeg':
639 w, h = _jpegxy(self.data)
657 w, h = _jpegxy(self.data)
640 else:
658 else:
641 # retina only supports png
659 # retina only supports png
642 return
660 return
643 self.width = w // 2
661 self.width = w // 2
644 self.height = h // 2
662 self.height = h // 2
645
663
646 def reload(self):
664 def reload(self):
647 """Reload the raw data from file or URL."""
665 """Reload the raw data from file or URL."""
648 if self.embed:
666 if self.embed:
649 super(Image,self).reload()
667 super(Image,self).reload()
650 if self.retina:
668 if self.retina:
651 self._retina_shape()
669 self._retina_shape()
652
670
653 def _repr_html_(self):
671 def _repr_html_(self):
654 if not self.embed:
672 if not self.embed:
655 width = height = ''
673 width = height = ''
656 if self.width:
674 if self.width:
657 width = ' width="%d"' % self.width
675 width = ' width="%d"' % self.width
658 if self.height:
676 if self.height:
659 height = ' height="%d"' % self.height
677 height = ' height="%d"' % self.height
660 return u'<img src="%s"%s%s/>' % (self.url, width, height)
678 return u'<img src="%s"%s%s/>' % (self.url, width, height)
661
679
662 def _data_and_metadata(self):
680 def _data_and_metadata(self):
663 """shortcut for returning metadata with shape information, if defined"""
681 """shortcut for returning metadata with shape information, if defined"""
664 md = {}
682 md = {}
665 if self.width:
683 if self.width:
666 md['width'] = self.width
684 md['width'] = self.width
667 if self.height:
685 if self.height:
668 md['height'] = self.height
686 md['height'] = self.height
669 if md:
687 if md:
670 return self.data, md
688 return self.data, md
671 else:
689 else:
672 return self.data
690 return self.data
673
691
674 def _repr_png_(self):
692 def _repr_png_(self):
675 if self.embed and self.format == u'png':
693 if self.embed and self.format == u'png':
676 return self._data_and_metadata()
694 return self._data_and_metadata()
677
695
678 def _repr_jpeg_(self):
696 def _repr_jpeg_(self):
679 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
697 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
680 return self._data_and_metadata()
698 return self._data_and_metadata()
681
699
682 def _find_ext(self, s):
700 def _find_ext(self, s):
683 return unicode_type(s.split('.')[-1].lower())
701 return unicode_type(s.split('.')[-1].lower())
684
702
685
703
686 def clear_output(wait=False):
704 def clear_output(wait=False):
687 """Clear the output of the current cell receiving output.
705 """Clear the output of the current cell receiving output.
688
706
689 Parameters
707 Parameters
690 ----------
708 ----------
691 wait : bool [default: false]
709 wait : bool [default: false]
692 Wait to clear the output until new output is available to replace it."""
710 Wait to clear the output until new output is available to replace it."""
693 from IPython.core.interactiveshell import InteractiveShell
711 from IPython.core.interactiveshell import InteractiveShell
694 if InteractiveShell.initialized():
712 if InteractiveShell.initialized():
695 InteractiveShell.instance().display_pub.clear_output(wait)
713 InteractiveShell.instance().display_pub.clear_output(wait)
696 else:
714 else:
697 from IPython.utils import io
715 from IPython.utils import io
698 print('\033[2K\r', file=io.stdout, end='')
716 print('\033[2K\r', file=io.stdout, end='')
699 io.stdout.flush()
717 io.stdout.flush()
700 print('\033[2K\r', file=io.stderr, end='')
718 print('\033[2K\r', file=io.stderr, end='')
701 io.stderr.flush()
719 io.stderr.flush()
720
721
722 @skip_doctest
723 def set_matplotlib_formats(*formats, **kwargs):
724 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
725
726 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
727
728 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
729
730 To set this in your config files use the following::
731
732 c.InlineBackend.figure_formats = {'pdf', 'png', 'svg'}
733 c.InlineBackend.quality = 90
734
735 Parameters
736 ----------
737 *formats : list, tuple
738 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
739 quality : int
740 A percentage for the quality of JPEG figures. Defaults to 90.
741 """
742 from IPython.core.interactiveshell import InteractiveShell
743 from IPython.core.pylabtools import select_figure_formats
744 shell = InteractiveShell.instance()
745 select_figure_formats(shell, formats, quality=90)
746
747 @skip_doctest
748 def set_matplotlib_close(close):
749 """Set whether the inline backend closes all figures automatically or not.
750
751 By default, the inline backend used in the IPython Notebook will close all
752 matplotlib figures automatically after each cell is run. This means that
753 plots in different cells won't interfere. Sometimes, you may want to make
754 a plot in one cell and then refine it in later cells. This can be accomplished
755 by::
756
757 In [1]: set_matplotlib_close(False)
758
759 To set this in your config files use the following::
760
761 c.InlineBackend.close_figures = False
762
763 Parameters
764 ----------
765 close : bool
766 Should all matplotlib figures be automatically closed after each cell is
767 run?
768 """
769 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
770 ilbe = InlineBackend.instance()
771 ilbe.close_figures = close
772
@@ -1,825 +1,846 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Display formatters.
2 """Display formatters.
3
3
4 Inheritance diagram:
4 Inheritance diagram:
5
5
6 .. inheritance-diagram:: IPython.core.formatters
6 .. inheritance-diagram:: IPython.core.formatters
7 :parts: 3
7 :parts: 3
8
8
9 Authors:
9 Authors:
10
10
11 * Robert Kern
11 * Robert Kern
12 * Brian Granger
12 * Brian Granger
13 """
13 """
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2010-2011, IPython Development Team.
15 # Copyright (C) 2010-2011, IPython Development Team.
16 #
16 #
17 # Distributed under the terms of the Modified BSD License.
17 # Distributed under the terms of the Modified BSD License.
18 #
18 #
19 # The full license is in the file COPYING.txt, distributed with this software.
19 # The full license is in the file COPYING.txt, distributed with this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 # Stdlib imports
26 # Stdlib imports
27 import abc
27 import abc
28 import sys
28 import sys
29 import warnings
29 import warnings
30
30
31 from IPython.external.decorator import decorator
31 from IPython.external.decorator import decorator
32
32
33 # Our own imports
33 # Our own imports
34 from IPython.config.configurable import Configurable
34 from IPython.config.configurable import Configurable
35 from IPython.lib import pretty
35 from IPython.lib import pretty
36 from IPython.utils import io
36 from IPython.utils import io
37 from IPython.utils.traitlets import (
37 from IPython.utils.traitlets import (
38 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
38 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
39 )
39 )
40 from IPython.utils.warn import warn
40 from IPython.utils.warn import warn
41 from IPython.utils.py3compat import (
41 from IPython.utils.py3compat import (
42 unicode_to_str, with_metaclass, PY3, string_types, unicode_type,
42 unicode_to_str, with_metaclass, PY3, string_types, unicode_type,
43 )
43 )
44
44
45 if PY3:
45 if PY3:
46 from io import StringIO
46 from io import StringIO
47 else:
47 else:
48 from StringIO import StringIO
48 from StringIO import StringIO
49
49
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # The main DisplayFormatter class
52 # The main DisplayFormatter class
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54
54
55 class DisplayFormatter(Configurable):
55 class DisplayFormatter(Configurable):
56
56
57 # When set to true only the default plain text formatter will be used.
57 # When set to true only the default plain text formatter will be used.
58 plain_text_only = Bool(False, config=True)
58 plain_text_only = Bool(False, config=True)
59 def _plain_text_only_changed(self, name, old, new):
59 def _plain_text_only_changed(self, name, old, new):
60 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
60 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
61
61
62 Use DisplayFormatter.active_types = ['text/plain']
62 Use DisplayFormatter.active_types = ['text/plain']
63 for the same effect.
63 for the same effect.
64 """, DeprecationWarning)
64 """, DeprecationWarning)
65 if new:
65 if new:
66 self.active_types = ['text/plain']
66 self.active_types = ['text/plain']
67 else:
67 else:
68 self.active_types = self.format_types
68 self.active_types = self.format_types
69
69
70 active_types = List(Unicode, config=True,
70 active_types = List(Unicode, config=True,
71 help="""List of currently active mime-types to display.
71 help="""List of currently active mime-types to display.
72 You can use this to set a white-list for formats to display.
72 You can use this to set a white-list for formats to display.
73
73
74 Most users will not need to change this value.
74 Most users will not need to change this value.
75 """)
75 """)
76 def _active_types_default(self):
76 def _active_types_default(self):
77 return self.format_types
77 return self.format_types
78
78
79 def _active_types_changed(self, name, old, new):
79 def _active_types_changed(self, name, old, new):
80 for key, formatter in self.formatters.items():
80 for key, formatter in self.formatters.items():
81 if key in new:
81 if key in new:
82 formatter.enabled = True
82 formatter.enabled = True
83 else:
83 else:
84 formatter.enabled = False
84 formatter.enabled = False
85
85
86 # A dict of formatter whose keys are format types (MIME types) and whose
86 # A dict of formatter whose keys are format types (MIME types) and whose
87 # values are subclasses of BaseFormatter.
87 # values are subclasses of BaseFormatter.
88 formatters = Dict()
88 formatters = Dict()
89 def _formatters_default(self):
89 def _formatters_default(self):
90 """Activate the default formatters."""
90 """Activate the default formatters."""
91 formatter_classes = [
91 formatter_classes = [
92 PlainTextFormatter,
92 PlainTextFormatter,
93 HTMLFormatter,
93 HTMLFormatter,
94 SVGFormatter,
94 SVGFormatter,
95 PNGFormatter,
95 PNGFormatter,
96 PDFFormatter,
96 JPEGFormatter,
97 JPEGFormatter,
97 LatexFormatter,
98 LatexFormatter,
98 JSONFormatter,
99 JSONFormatter,
99 JavascriptFormatter
100 JavascriptFormatter
100 ]
101 ]
101 d = {}
102 d = {}
102 for cls in formatter_classes:
103 for cls in formatter_classes:
103 f = cls(parent=self)
104 f = cls(parent=self)
104 d[f.format_type] = f
105 d[f.format_type] = f
105 return d
106 return d
106
107
107 def format(self, obj, include=None, exclude=None):
108 def format(self, obj, include=None, exclude=None):
108 """Return a format data dict for an object.
109 """Return a format data dict for an object.
109
110
110 By default all format types will be computed.
111 By default all format types will be computed.
111
112
112 The following MIME types are currently implemented:
113 The following MIME types are currently implemented:
113
114
114 * text/plain
115 * text/plain
115 * text/html
116 * text/html
116 * text/latex
117 * text/latex
117 * application/json
118 * application/json
118 * application/javascript
119 * application/javascript
120 * application/pdf
119 * image/png
121 * image/png
120 * image/jpeg
122 * image/jpeg
121 * image/svg+xml
123 * image/svg+xml
122
124
123 Parameters
125 Parameters
124 ----------
126 ----------
125 obj : object
127 obj : object
126 The Python object whose format data will be computed.
128 The Python object whose format data will be computed.
127 include : list or tuple, optional
129 include : list or tuple, optional
128 A list of format type strings (MIME types) to include in the
130 A list of format type strings (MIME types) to include in the
129 format data dict. If this is set *only* the format types included
131 format data dict. If this is set *only* the format types included
130 in this list will be computed.
132 in this list will be computed.
131 exclude : list or tuple, optional
133 exclude : list or tuple, optional
132 A list of format type string (MIME types) to exclude in the format
134 A list of format type string (MIME types) to exclude in the format
133 data dict. If this is set all format types will be computed,
135 data dict. If this is set all format types will be computed,
134 except for those included in this argument.
136 except for those included in this argument.
135
137
136 Returns
138 Returns
137 -------
139 -------
138 (format_dict, metadata_dict) : tuple of two dicts
140 (format_dict, metadata_dict) : tuple of two dicts
139
141
140 format_dict is a dictionary of key/value pairs, one of each format that was
142 format_dict is a dictionary of key/value pairs, one of each format that was
141 generated for the object. The keys are the format types, which
143 generated for the object. The keys are the format types, which
142 will usually be MIME type strings and the values and JSON'able
144 will usually be MIME type strings and the values and JSON'able
143 data structure containing the raw data for the representation in
145 data structure containing the raw data for the representation in
144 that format.
146 that format.
145
147
146 metadata_dict is a dictionary of metadata about each mime-type output.
148 metadata_dict is a dictionary of metadata about each mime-type output.
147 Its keys will be a strict subset of the keys in format_dict.
149 Its keys will be a strict subset of the keys in format_dict.
148 """
150 """
149 format_dict = {}
151 format_dict = {}
150 md_dict = {}
152 md_dict = {}
151
153
152 for format_type, formatter in self.formatters.items():
154 for format_type, formatter in self.formatters.items():
153 if include and format_type not in include:
155 if include and format_type not in include:
154 continue
156 continue
155 if exclude and format_type in exclude:
157 if exclude and format_type in exclude:
156 continue
158 continue
157
159
158 md = None
160 md = None
159 try:
161 try:
160 data = formatter(obj)
162 data = formatter(obj)
161 except:
163 except:
162 # FIXME: log the exception
164 # FIXME: log the exception
163 raise
165 raise
164
166
165 # formatters can return raw data or (data, metadata)
167 # formatters can return raw data or (data, metadata)
166 if isinstance(data, tuple) and len(data) == 2:
168 if isinstance(data, tuple) and len(data) == 2:
167 data, md = data
169 data, md = data
168
170
169 if data is not None:
171 if data is not None:
170 format_dict[format_type] = data
172 format_dict[format_type] = data
171 if md is not None:
173 if md is not None:
172 md_dict[format_type] = md
174 md_dict[format_type] = md
173
175
174 return format_dict, md_dict
176 return format_dict, md_dict
175
177
176 @property
178 @property
177 def format_types(self):
179 def format_types(self):
178 """Return the format types (MIME types) of the active formatters."""
180 """Return the format types (MIME types) of the active formatters."""
179 return list(self.formatters.keys())
181 return list(self.formatters.keys())
180
182
181
183
182 #-----------------------------------------------------------------------------
184 #-----------------------------------------------------------------------------
183 # Formatters for specific format types (text, html, svg, etc.)
185 # Formatters for specific format types (text, html, svg, etc.)
184 #-----------------------------------------------------------------------------
186 #-----------------------------------------------------------------------------
185
187
186 class FormatterWarning(UserWarning):
188 class FormatterWarning(UserWarning):
187 """Warning class for errors in formatters"""
189 """Warning class for errors in formatters"""
188
190
189 @decorator
191 @decorator
190 def warn_format_error(method, self, *args, **kwargs):
192 def warn_format_error(method, self, *args, **kwargs):
191 """decorator for warning on failed format call"""
193 """decorator for warning on failed format call"""
192 try:
194 try:
193 r = method(self, *args, **kwargs)
195 r = method(self, *args, **kwargs)
194 except NotImplementedError as e:
196 except NotImplementedError as e:
195 # don't warn on NotImplementedErrors
197 # don't warn on NotImplementedErrors
196 return None
198 return None
197 except Exception as e:
199 except Exception as e:
198 warnings.warn("Exception in %s formatter: %s" % (self.format_type, e),
200 warnings.warn("Exception in %s formatter: %s" % (self.format_type, e),
199 FormatterWarning,
201 FormatterWarning,
200 )
202 )
201 return None
203 return None
202 if r is None or isinstance(r, self._return_type) or \
204 if r is None or isinstance(r, self._return_type) or \
203 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
205 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
204 return r
206 return r
205 else:
207 else:
206 warnings.warn(
208 warnings.warn(
207 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
209 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
208 (self.format_type, type(r), self._return_type, pretty._safe_repr(args[0])),
210 (self.format_type, type(r), self._return_type, pretty._safe_repr(args[0])),
209 FormatterWarning
211 FormatterWarning
210 )
212 )
211
213
212
214
213 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
215 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
214 """ Abstract base class for Formatters.
216 """ Abstract base class for Formatters.
215
217
216 A formatter is a callable class that is responsible for computing the
218 A formatter is a callable class that is responsible for computing the
217 raw format data for a particular format type (MIME type). For example,
219 raw format data for a particular format type (MIME type). For example,
218 an HTML formatter would have a format type of `text/html` and would return
220 an HTML formatter would have a format type of `text/html` and would return
219 the HTML representation of the object when called.
221 the HTML representation of the object when called.
220 """
222 """
221
223
222 # The format type of the data returned, usually a MIME type.
224 # The format type of the data returned, usually a MIME type.
223 format_type = 'text/plain'
225 format_type = 'text/plain'
224
226
225 # Is the formatter enabled...
227 # Is the formatter enabled...
226 enabled = True
228 enabled = True
227
229
228 @abc.abstractmethod
230 @abc.abstractmethod
229 @warn_format_error
231 @warn_format_error
230 def __call__(self, obj):
232 def __call__(self, obj):
231 """Return a JSON'able representation of the object.
233 """Return a JSON'able representation of the object.
232
234
233 If the object cannot be formatted by this formatter,
235 If the object cannot be formatted by this formatter,
234 warn and return None.
236 warn and return None.
235 """
237 """
236 return repr(obj)
238 return repr(obj)
237
239
238
240
239 def _mod_name_key(typ):
241 def _mod_name_key(typ):
240 """Return a (__module__, __name__) tuple for a type.
242 """Return a (__module__, __name__) tuple for a type.
241
243
242 Used as key in Formatter.deferred_printers.
244 Used as key in Formatter.deferred_printers.
243 """
245 """
244 module = getattr(typ, '__module__', None)
246 module = getattr(typ, '__module__', None)
245 name = getattr(typ, '__name__', None)
247 name = getattr(typ, '__name__', None)
246 return (module, name)
248 return (module, name)
247
249
248
250
249 def _get_type(obj):
251 def _get_type(obj):
250 """Return the type of an instance (old and new-style)"""
252 """Return the type of an instance (old and new-style)"""
251 return getattr(obj, '__class__', None) or type(obj)
253 return getattr(obj, '__class__', None) or type(obj)
252
254
253 _raise_key_error = object()
255 _raise_key_error = object()
254
256
255
257
256 class BaseFormatter(Configurable):
258 class BaseFormatter(Configurable):
257 """A base formatter class that is configurable.
259 """A base formatter class that is configurable.
258
260
259 This formatter should usually be used as the base class of all formatters.
261 This formatter should usually be used as the base class of all formatters.
260 It is a traited :class:`Configurable` class and includes an extensible
262 It is a traited :class:`Configurable` class and includes an extensible
261 API for users to determine how their objects are formatted. The following
263 API for users to determine how their objects are formatted. The following
262 logic is used to find a function to format an given object.
264 logic is used to find a function to format an given object.
263
265
264 1. The object is introspected to see if it has a method with the name
266 1. The object is introspected to see if it has a method with the name
265 :attr:`print_method`. If is does, that object is passed to that method
267 :attr:`print_method`. If is does, that object is passed to that method
266 for formatting.
268 for formatting.
267 2. If no print method is found, three internal dictionaries are consulted
269 2. If no print method is found, three internal dictionaries are consulted
268 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
270 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
269 and :attr:`deferred_printers`.
271 and :attr:`deferred_printers`.
270
272
271 Users should use these dictionaries to register functions that will be
273 Users should use these dictionaries to register functions that will be
272 used to compute the format data for their objects (if those objects don't
274 used to compute the format data for their objects (if those objects don't
273 have the special print methods). The easiest way of using these
275 have the special print methods). The easiest way of using these
274 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
276 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
275 methods.
277 methods.
276
278
277 If no function/callable is found to compute the format data, ``None`` is
279 If no function/callable is found to compute the format data, ``None`` is
278 returned and this format type is not used.
280 returned and this format type is not used.
279 """
281 """
280
282
281 format_type = Unicode('text/plain')
283 format_type = Unicode('text/plain')
282 _return_type = string_types
284 _return_type = string_types
283
285
284 enabled = Bool(True, config=True)
286 enabled = Bool(True, config=True)
285
287
286 print_method = ObjectName('__repr__')
288 print_method = ObjectName('__repr__')
287
289
288 # The singleton printers.
290 # The singleton printers.
289 # Maps the IDs of the builtin singleton objects to the format functions.
291 # Maps the IDs of the builtin singleton objects to the format functions.
290 singleton_printers = Dict(config=True)
292 singleton_printers = Dict(config=True)
291
293
292 # The type-specific printers.
294 # The type-specific printers.
293 # Map type objects to the format functions.
295 # Map type objects to the format functions.
294 type_printers = Dict(config=True)
296 type_printers = Dict(config=True)
295
297
296 # The deferred-import type-specific printers.
298 # The deferred-import type-specific printers.
297 # Map (modulename, classname) pairs to the format functions.
299 # Map (modulename, classname) pairs to the format functions.
298 deferred_printers = Dict(config=True)
300 deferred_printers = Dict(config=True)
299
301
300 @warn_format_error
302 @warn_format_error
301 def __call__(self, obj):
303 def __call__(self, obj):
302 """Compute the format for an object."""
304 """Compute the format for an object."""
303 if self.enabled:
305 if self.enabled:
304 # lookup registered printer
306 # lookup registered printer
305 try:
307 try:
306 printer = self.lookup(obj)
308 printer = self.lookup(obj)
307 except KeyError:
309 except KeyError:
308 pass
310 pass
309 else:
311 else:
310 return printer(obj)
312 return printer(obj)
311 # Finally look for special method names
313 # Finally look for special method names
312 method = pretty._safe_getattr(obj, self.print_method, None)
314 method = pretty._safe_getattr(obj, self.print_method, None)
313 if method is not None:
315 if method is not None:
314 return method()
316 return method()
315 return None
317 return None
316 else:
318 else:
317 return None
319 return None
318
320
319 def __contains__(self, typ):
321 def __contains__(self, typ):
320 """map in to lookup_by_type"""
322 """map in to lookup_by_type"""
321 try:
323 try:
322 self.lookup_by_type(typ)
324 self.lookup_by_type(typ)
323 except KeyError:
325 except KeyError:
324 return False
326 return False
325 else:
327 else:
326 return True
328 return True
327
329
328 def lookup(self, obj):
330 def lookup(self, obj):
329 """Look up the formatter for a given instance.
331 """Look up the formatter for a given instance.
330
332
331 Parameters
333 Parameters
332 ----------
334 ----------
333 obj : object instance
335 obj : object instance
334
336
335 Returns
337 Returns
336 -------
338 -------
337 f : callable
339 f : callable
338 The registered formatting callable for the type.
340 The registered formatting callable for the type.
339
341
340 Raises
342 Raises
341 ------
343 ------
342 KeyError if the type has not been registered.
344 KeyError if the type has not been registered.
343 """
345 """
344 # look for singleton first
346 # look for singleton first
345 obj_id = id(obj)
347 obj_id = id(obj)
346 if obj_id in self.singleton_printers:
348 if obj_id in self.singleton_printers:
347 return self.singleton_printers[obj_id]
349 return self.singleton_printers[obj_id]
348 # then lookup by type
350 # then lookup by type
349 return self.lookup_by_type(_get_type(obj))
351 return self.lookup_by_type(_get_type(obj))
350
352
351 def lookup_by_type(self, typ):
353 def lookup_by_type(self, typ):
352 """Look up the registered formatter for a type.
354 """Look up the registered formatter for a type.
353
355
354 Parameters
356 Parameters
355 ----------
357 ----------
356 typ : type or '__module__.__name__' string for a type
358 typ : type or '__module__.__name__' string for a type
357
359
358 Returns
360 Returns
359 -------
361 -------
360 f : callable
362 f : callable
361 The registered formatting callable for the type.
363 The registered formatting callable for the type.
362
364
363 Raises
365 Raises
364 ------
366 ------
365 KeyError if the type has not been registered.
367 KeyError if the type has not been registered.
366 """
368 """
367 if isinstance(typ, string_types):
369 if isinstance(typ, string_types):
368 typ_key = tuple(typ.rsplit('.',1))
370 typ_key = tuple(typ.rsplit('.',1))
369 if typ_key not in self.deferred_printers:
371 if typ_key not in self.deferred_printers:
370 # We may have it cached in the type map. We will have to
372 # We may have it cached in the type map. We will have to
371 # iterate over all of the types to check.
373 # iterate over all of the types to check.
372 for cls in self.type_printers:
374 for cls in self.type_printers:
373 if _mod_name_key(cls) == typ_key:
375 if _mod_name_key(cls) == typ_key:
374 return self.type_printers[cls]
376 return self.type_printers[cls]
375 else:
377 else:
376 return self.deferred_printers[typ_key]
378 return self.deferred_printers[typ_key]
377 else:
379 else:
378 for cls in pretty._get_mro(typ):
380 for cls in pretty._get_mro(typ):
379 if cls in self.type_printers or self._in_deferred_types(cls):
381 if cls in self.type_printers or self._in_deferred_types(cls):
380 return self.type_printers[cls]
382 return self.type_printers[cls]
381
383
382 # If we have reached here, the lookup failed.
384 # If we have reached here, the lookup failed.
383 raise KeyError("No registered printer for {0!r}".format(typ))
385 raise KeyError("No registered printer for {0!r}".format(typ))
384
386
385 def for_type(self, typ, func=None):
387 def for_type(self, typ, func=None):
386 """Add a format function for a given type.
388 """Add a format function for a given type.
387
389
388 Parameters
390 Parameters
389 -----------
391 -----------
390 typ : type or '__module__.__name__' string for a type
392 typ : type or '__module__.__name__' string for a type
391 The class of the object that will be formatted using `func`.
393 The class of the object that will be formatted using `func`.
392 func : callable
394 func : callable
393 A callable for computing the format data.
395 A callable for computing the format data.
394 `func` will be called with the object to be formatted,
396 `func` will be called with the object to be formatted,
395 and will return the raw data in this formatter's format.
397 and will return the raw data in this formatter's format.
396 Subclasses may use a different call signature for the
398 Subclasses may use a different call signature for the
397 `func` argument.
399 `func` argument.
398
400
399 If `func` is None or not specified, there will be no change,
401 If `func` is None or not specified, there will be no change,
400 only returning the current value.
402 only returning the current value.
401
403
402 Returns
404 Returns
403 -------
405 -------
404 oldfunc : callable
406 oldfunc : callable
405 The currently registered callable.
407 The currently registered callable.
406 If you are registering a new formatter,
408 If you are registering a new formatter,
407 this will be the previous value (to enable restoring later).
409 this will be the previous value (to enable restoring later).
408 """
410 """
409 # if string given, interpret as 'pkg.module.class_name'
411 # if string given, interpret as 'pkg.module.class_name'
410 if isinstance(typ, string_types):
412 if isinstance(typ, string_types):
411 type_module, type_name = typ.rsplit('.', 1)
413 type_module, type_name = typ.rsplit('.', 1)
412 return self.for_type_by_name(type_module, type_name, func)
414 return self.for_type_by_name(type_module, type_name, func)
413
415
414 try:
416 try:
415 oldfunc = self.lookup_by_type(typ)
417 oldfunc = self.lookup_by_type(typ)
416 except KeyError:
418 except KeyError:
417 oldfunc = None
419 oldfunc = None
418
420
419 if func is not None:
421 if func is not None:
420 self.type_printers[typ] = func
422 self.type_printers[typ] = func
421
423
422 return oldfunc
424 return oldfunc
423
425
424 def for_type_by_name(self, type_module, type_name, func=None):
426 def for_type_by_name(self, type_module, type_name, func=None):
425 """Add a format function for a type specified by the full dotted
427 """Add a format function for a type specified by the full dotted
426 module and name of the type, rather than the type of the object.
428 module and name of the type, rather than the type of the object.
427
429
428 Parameters
430 Parameters
429 ----------
431 ----------
430 type_module : str
432 type_module : str
431 The full dotted name of the module the type is defined in, like
433 The full dotted name of the module the type is defined in, like
432 ``numpy``.
434 ``numpy``.
433 type_name : str
435 type_name : str
434 The name of the type (the class name), like ``dtype``
436 The name of the type (the class name), like ``dtype``
435 func : callable
437 func : callable
436 A callable for computing the format data.
438 A callable for computing the format data.
437 `func` will be called with the object to be formatted,
439 `func` will be called with the object to be formatted,
438 and will return the raw data in this formatter's format.
440 and will return the raw data in this formatter's format.
439 Subclasses may use a different call signature for the
441 Subclasses may use a different call signature for the
440 `func` argument.
442 `func` argument.
441
443
442 If `func` is None or unspecified, there will be no change,
444 If `func` is None or unspecified, there will be no change,
443 only returning the current value.
445 only returning the current value.
444
446
445 Returns
447 Returns
446 -------
448 -------
447 oldfunc : callable
449 oldfunc : callable
448 The currently registered callable.
450 The currently registered callable.
449 If you are registering a new formatter,
451 If you are registering a new formatter,
450 this will be the previous value (to enable restoring later).
452 this will be the previous value (to enable restoring later).
451 """
453 """
452 key = (type_module, type_name)
454 key = (type_module, type_name)
453
455
454 try:
456 try:
455 oldfunc = self.lookup_by_type("%s.%s" % key)
457 oldfunc = self.lookup_by_type("%s.%s" % key)
456 except KeyError:
458 except KeyError:
457 oldfunc = None
459 oldfunc = None
458
460
459 if func is not None:
461 if func is not None:
460 self.deferred_printers[key] = func
462 self.deferred_printers[key] = func
461 return oldfunc
463 return oldfunc
462
464
463 def pop(self, typ, default=_raise_key_error):
465 def pop(self, typ, default=_raise_key_error):
464 """Pop a formatter for the given type.
466 """Pop a formatter for the given type.
465
467
466 Parameters
468 Parameters
467 ----------
469 ----------
468 typ : type or '__module__.__name__' string for a type
470 typ : type or '__module__.__name__' string for a type
469 default : object
471 default : object
470 value to be returned if no formatter is registered for typ.
472 value to be returned if no formatter is registered for typ.
471
473
472 Returns
474 Returns
473 -------
475 -------
474 obj : object
476 obj : object
475 The last registered object for the type.
477 The last registered object for the type.
476
478
477 Raises
479 Raises
478 ------
480 ------
479 KeyError if the type is not registered and default is not specified.
481 KeyError if the type is not registered and default is not specified.
480 """
482 """
481
483
482 if isinstance(typ, string_types):
484 if isinstance(typ, string_types):
483 typ_key = tuple(typ.rsplit('.',1))
485 typ_key = tuple(typ.rsplit('.',1))
484 if typ_key not in self.deferred_printers:
486 if typ_key not in self.deferred_printers:
485 # We may have it cached in the type map. We will have to
487 # We may have it cached in the type map. We will have to
486 # iterate over all of the types to check.
488 # iterate over all of the types to check.
487 for cls in self.type_printers:
489 for cls in self.type_printers:
488 if _mod_name_key(cls) == typ_key:
490 if _mod_name_key(cls) == typ_key:
489 old = self.type_printers.pop(cls)
491 old = self.type_printers.pop(cls)
490 break
492 break
491 else:
493 else:
492 old = default
494 old = default
493 else:
495 else:
494 old = self.deferred_printers.pop(typ_key)
496 old = self.deferred_printers.pop(typ_key)
495 else:
497 else:
496 if typ in self.type_printers:
498 if typ in self.type_printers:
497 old = self.type_printers.pop(typ)
499 old = self.type_printers.pop(typ)
498 else:
500 else:
499 old = self.deferred_printers.pop(_mod_name_key(typ), default)
501 old = self.deferred_printers.pop(_mod_name_key(typ), default)
500 if old is _raise_key_error:
502 if old is _raise_key_error:
501 raise KeyError("No registered value for {0!r}".format(typ))
503 raise KeyError("No registered value for {0!r}".format(typ))
502 return old
504 return old
503
505
504 def _in_deferred_types(self, cls):
506 def _in_deferred_types(self, cls):
505 """
507 """
506 Check if the given class is specified in the deferred type registry.
508 Check if the given class is specified in the deferred type registry.
507
509
508 Successful matches will be moved to the regular type registry for future use.
510 Successful matches will be moved to the regular type registry for future use.
509 """
511 """
510 mod = getattr(cls, '__module__', None)
512 mod = getattr(cls, '__module__', None)
511 name = getattr(cls, '__name__', None)
513 name = getattr(cls, '__name__', None)
512 key = (mod, name)
514 key = (mod, name)
513 if key in self.deferred_printers:
515 if key in self.deferred_printers:
514 # Move the printer over to the regular registry.
516 # Move the printer over to the regular registry.
515 printer = self.deferred_printers.pop(key)
517 printer = self.deferred_printers.pop(key)
516 self.type_printers[cls] = printer
518 self.type_printers[cls] = printer
517 return True
519 return True
518 return False
520 return False
519
521
520
522
521 class PlainTextFormatter(BaseFormatter):
523 class PlainTextFormatter(BaseFormatter):
522 """The default pretty-printer.
524 """The default pretty-printer.
523
525
524 This uses :mod:`IPython.lib.pretty` to compute the format data of
526 This uses :mod:`IPython.lib.pretty` to compute the format data of
525 the object. If the object cannot be pretty printed, :func:`repr` is used.
527 the object. If the object cannot be pretty printed, :func:`repr` is used.
526 See the documentation of :mod:`IPython.lib.pretty` for details on
528 See the documentation of :mod:`IPython.lib.pretty` for details on
527 how to write pretty printers. Here is a simple example::
529 how to write pretty printers. Here is a simple example::
528
530
529 def dtype_pprinter(obj, p, cycle):
531 def dtype_pprinter(obj, p, cycle):
530 if cycle:
532 if cycle:
531 return p.text('dtype(...)')
533 return p.text('dtype(...)')
532 if hasattr(obj, 'fields'):
534 if hasattr(obj, 'fields'):
533 if obj.fields is None:
535 if obj.fields is None:
534 p.text(repr(obj))
536 p.text(repr(obj))
535 else:
537 else:
536 p.begin_group(7, 'dtype([')
538 p.begin_group(7, 'dtype([')
537 for i, field in enumerate(obj.descr):
539 for i, field in enumerate(obj.descr):
538 if i > 0:
540 if i > 0:
539 p.text(',')
541 p.text(',')
540 p.breakable()
542 p.breakable()
541 p.pretty(field)
543 p.pretty(field)
542 p.end_group(7, '])')
544 p.end_group(7, '])')
543 """
545 """
544
546
545 # The format type of data returned.
547 # The format type of data returned.
546 format_type = Unicode('text/plain')
548 format_type = Unicode('text/plain')
547
549
548 # This subclass ignores this attribute as it always need to return
550 # This subclass ignores this attribute as it always need to return
549 # something.
551 # something.
550 enabled = Bool(True, config=False)
552 enabled = Bool(True, config=False)
551
553
552 # Look for a _repr_pretty_ methods to use for pretty printing.
554 # Look for a _repr_pretty_ methods to use for pretty printing.
553 print_method = ObjectName('_repr_pretty_')
555 print_method = ObjectName('_repr_pretty_')
554
556
555 # Whether to pretty-print or not.
557 # Whether to pretty-print or not.
556 pprint = Bool(True, config=True)
558 pprint = Bool(True, config=True)
557
559
558 # Whether to be verbose or not.
560 # Whether to be verbose or not.
559 verbose = Bool(False, config=True)
561 verbose = Bool(False, config=True)
560
562
561 # The maximum width.
563 # The maximum width.
562 max_width = Integer(79, config=True)
564 max_width = Integer(79, config=True)
563
565
564 # The newline character.
566 # The newline character.
565 newline = Unicode('\n', config=True)
567 newline = Unicode('\n', config=True)
566
568
567 # format-string for pprinting floats
569 # format-string for pprinting floats
568 float_format = Unicode('%r')
570 float_format = Unicode('%r')
569 # setter for float precision, either int or direct format-string
571 # setter for float precision, either int or direct format-string
570 float_precision = CUnicode('', config=True)
572 float_precision = CUnicode('', config=True)
571
573
572 def _float_precision_changed(self, name, old, new):
574 def _float_precision_changed(self, name, old, new):
573 """float_precision changed, set float_format accordingly.
575 """float_precision changed, set float_format accordingly.
574
576
575 float_precision can be set by int or str.
577 float_precision can be set by int or str.
576 This will set float_format, after interpreting input.
578 This will set float_format, after interpreting input.
577 If numpy has been imported, numpy print precision will also be set.
579 If numpy has been imported, numpy print precision will also be set.
578
580
579 integer `n` sets format to '%.nf', otherwise, format set directly.
581 integer `n` sets format to '%.nf', otherwise, format set directly.
580
582
581 An empty string returns to defaults (repr for float, 8 for numpy).
583 An empty string returns to defaults (repr for float, 8 for numpy).
582
584
583 This parameter can be set via the '%precision' magic.
585 This parameter can be set via the '%precision' magic.
584 """
586 """
585
587
586 if '%' in new:
588 if '%' in new:
587 # got explicit format string
589 # got explicit format string
588 fmt = new
590 fmt = new
589 try:
591 try:
590 fmt%3.14159
592 fmt%3.14159
591 except Exception:
593 except Exception:
592 raise ValueError("Precision must be int or format string, not %r"%new)
594 raise ValueError("Precision must be int or format string, not %r"%new)
593 elif new:
595 elif new:
594 # otherwise, should be an int
596 # otherwise, should be an int
595 try:
597 try:
596 i = int(new)
598 i = int(new)
597 assert i >= 0
599 assert i >= 0
598 except ValueError:
600 except ValueError:
599 raise ValueError("Precision must be int or format string, not %r"%new)
601 raise ValueError("Precision must be int or format string, not %r"%new)
600 except AssertionError:
602 except AssertionError:
601 raise ValueError("int precision must be non-negative, not %r"%i)
603 raise ValueError("int precision must be non-negative, not %r"%i)
602
604
603 fmt = '%%.%if'%i
605 fmt = '%%.%if'%i
604 if 'numpy' in sys.modules:
606 if 'numpy' in sys.modules:
605 # set numpy precision if it has been imported
607 # set numpy precision if it has been imported
606 import numpy
608 import numpy
607 numpy.set_printoptions(precision=i)
609 numpy.set_printoptions(precision=i)
608 else:
610 else:
609 # default back to repr
611 # default back to repr
610 fmt = '%r'
612 fmt = '%r'
611 if 'numpy' in sys.modules:
613 if 'numpy' in sys.modules:
612 import numpy
614 import numpy
613 # numpy default is 8
615 # numpy default is 8
614 numpy.set_printoptions(precision=8)
616 numpy.set_printoptions(precision=8)
615 self.float_format = fmt
617 self.float_format = fmt
616
618
617 # Use the default pretty printers from IPython.lib.pretty.
619 # Use the default pretty printers from IPython.lib.pretty.
618 def _singleton_printers_default(self):
620 def _singleton_printers_default(self):
619 return pretty._singleton_pprinters.copy()
621 return pretty._singleton_pprinters.copy()
620
622
621 def _type_printers_default(self):
623 def _type_printers_default(self):
622 d = pretty._type_pprinters.copy()
624 d = pretty._type_pprinters.copy()
623 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
625 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
624 return d
626 return d
625
627
626 def _deferred_printers_default(self):
628 def _deferred_printers_default(self):
627 return pretty._deferred_type_pprinters.copy()
629 return pretty._deferred_type_pprinters.copy()
628
630
629 #### FormatterABC interface ####
631 #### FormatterABC interface ####
630
632
631 @warn_format_error
633 @warn_format_error
632 def __call__(self, obj):
634 def __call__(self, obj):
633 """Compute the pretty representation of the object."""
635 """Compute the pretty representation of the object."""
634 if not self.pprint:
636 if not self.pprint:
635 return pretty._safe_repr(obj)
637 return pretty._safe_repr(obj)
636 else:
638 else:
637 # This uses use StringIO, as cStringIO doesn't handle unicode.
639 # This uses use StringIO, as cStringIO doesn't handle unicode.
638 stream = StringIO()
640 stream = StringIO()
639 # self.newline.encode() is a quick fix for issue gh-597. We need to
641 # self.newline.encode() is a quick fix for issue gh-597. We need to
640 # ensure that stream does not get a mix of unicode and bytestrings,
642 # ensure that stream does not get a mix of unicode and bytestrings,
641 # or it will cause trouble.
643 # or it will cause trouble.
642 printer = pretty.RepresentationPrinter(stream, self.verbose,
644 printer = pretty.RepresentationPrinter(stream, self.verbose,
643 self.max_width, unicode_to_str(self.newline),
645 self.max_width, unicode_to_str(self.newline),
644 singleton_pprinters=self.singleton_printers,
646 singleton_pprinters=self.singleton_printers,
645 type_pprinters=self.type_printers,
647 type_pprinters=self.type_printers,
646 deferred_pprinters=self.deferred_printers)
648 deferred_pprinters=self.deferred_printers)
647 printer.pretty(obj)
649 printer.pretty(obj)
648 printer.flush()
650 printer.flush()
649 return stream.getvalue()
651 return stream.getvalue()
650
652
651
653
652 class HTMLFormatter(BaseFormatter):
654 class HTMLFormatter(BaseFormatter):
653 """An HTML formatter.
655 """An HTML formatter.
654
656
655 To define the callables that compute the HTML representation of your
657 To define the callables that compute the HTML representation of your
656 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
658 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
657 or :meth:`for_type_by_name` methods to register functions that handle
659 or :meth:`for_type_by_name` methods to register functions that handle
658 this.
660 this.
659
661
660 The return value of this formatter should be a valid HTML snippet that
662 The return value of this formatter should be a valid HTML snippet that
661 could be injected into an existing DOM. It should *not* include the
663 could be injected into an existing DOM. It should *not* include the
662 ```<html>`` or ```<body>`` tags.
664 ```<html>`` or ```<body>`` tags.
663 """
665 """
664 format_type = Unicode('text/html')
666 format_type = Unicode('text/html')
665
667
666 print_method = ObjectName('_repr_html_')
668 print_method = ObjectName('_repr_html_')
667
669
668
670
669 class SVGFormatter(BaseFormatter):
671 class SVGFormatter(BaseFormatter):
670 """An SVG formatter.
672 """An SVG formatter.
671
673
672 To define the callables that compute the SVG representation of your
674 To define the callables that compute the SVG representation of your
673 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
675 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
674 or :meth:`for_type_by_name` methods to register functions that handle
676 or :meth:`for_type_by_name` methods to register functions that handle
675 this.
677 this.
676
678
677 The return value of this formatter should be valid SVG enclosed in
679 The return value of this formatter should be valid SVG enclosed in
678 ```<svg>``` tags, that could be injected into an existing DOM. It should
680 ```<svg>``` tags, that could be injected into an existing DOM. It should
679 *not* include the ```<html>`` or ```<body>`` tags.
681 *not* include the ```<html>`` or ```<body>`` tags.
680 """
682 """
681 format_type = Unicode('image/svg+xml')
683 format_type = Unicode('image/svg+xml')
682
684
683 print_method = ObjectName('_repr_svg_')
685 print_method = ObjectName('_repr_svg_')
684
686
685
687
686 class PNGFormatter(BaseFormatter):
688 class PNGFormatter(BaseFormatter):
687 """A PNG formatter.
689 """A PNG formatter.
688
690
689 To define the callables that compute the PNG representation of your
691 To define the callables that compute the PNG representation of your
690 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
692 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
691 or :meth:`for_type_by_name` methods to register functions that handle
693 or :meth:`for_type_by_name` methods to register functions that handle
692 this.
694 this.
693
695
694 The return value of this formatter should be raw PNG data, *not*
696 The return value of this formatter should be raw PNG data, *not*
695 base64 encoded.
697 base64 encoded.
696 """
698 """
697 format_type = Unicode('image/png')
699 format_type = Unicode('image/png')
698
700
699 print_method = ObjectName('_repr_png_')
701 print_method = ObjectName('_repr_png_')
700
702
701 _return_type = (bytes, unicode_type)
703 _return_type = (bytes, unicode_type)
702
704
703
705
704 class JPEGFormatter(BaseFormatter):
706 class JPEGFormatter(BaseFormatter):
705 """A JPEG formatter.
707 """A JPEG formatter.
706
708
707 To define the callables that compute the JPEG representation of your
709 To define the callables that compute the JPEG representation of your
708 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
710 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
709 or :meth:`for_type_by_name` methods to register functions that handle
711 or :meth:`for_type_by_name` methods to register functions that handle
710 this.
712 this.
711
713
712 The return value of this formatter should be raw JPEG data, *not*
714 The return value of this formatter should be raw JPEG data, *not*
713 base64 encoded.
715 base64 encoded.
714 """
716 """
715 format_type = Unicode('image/jpeg')
717 format_type = Unicode('image/jpeg')
716
718
717 print_method = ObjectName('_repr_jpeg_')
719 print_method = ObjectName('_repr_jpeg_')
718
720
719 _return_type = (bytes, unicode_type)
721 _return_type = (bytes, unicode_type)
720
722
721
723
722 class LatexFormatter(BaseFormatter):
724 class LatexFormatter(BaseFormatter):
723 """A LaTeX formatter.
725 """A LaTeX formatter.
724
726
725 To define the callables that compute the LaTeX representation of your
727 To define the callables that compute the LaTeX representation of your
726 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
728 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
727 or :meth:`for_type_by_name` methods to register functions that handle
729 or :meth:`for_type_by_name` methods to register functions that handle
728 this.
730 this.
729
731
730 The return value of this formatter should be a valid LaTeX equation,
732 The return value of this formatter should be a valid LaTeX equation,
731 enclosed in either ```$```, ```$$``` or another LaTeX equation
733 enclosed in either ```$```, ```$$``` or another LaTeX equation
732 environment.
734 environment.
733 """
735 """
734 format_type = Unicode('text/latex')
736 format_type = Unicode('text/latex')
735
737
736 print_method = ObjectName('_repr_latex_')
738 print_method = ObjectName('_repr_latex_')
737
739
738
740
739 class JSONFormatter(BaseFormatter):
741 class JSONFormatter(BaseFormatter):
740 """A JSON string formatter.
742 """A JSON string formatter.
741
743
742 To define the callables that compute the JSON string representation of
744 To define the callables that compute the JSON string representation of
743 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
745 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
744 or :meth:`for_type_by_name` methods to register functions that handle
746 or :meth:`for_type_by_name` methods to register functions that handle
745 this.
747 this.
746
748
747 The return value of this formatter should be a valid JSON string.
749 The return value of this formatter should be a valid JSON string.
748 """
750 """
749 format_type = Unicode('application/json')
751 format_type = Unicode('application/json')
750
752
751 print_method = ObjectName('_repr_json_')
753 print_method = ObjectName('_repr_json_')
752
754
753
755
754 class JavascriptFormatter(BaseFormatter):
756 class JavascriptFormatter(BaseFormatter):
755 """A Javascript formatter.
757 """A Javascript formatter.
756
758
757 To define the callables that compute the Javascript representation of
759 To define the callables that compute the Javascript representation of
758 your objects, define a :meth:`_repr_javascript_` method or use the
760 your objects, define a :meth:`_repr_javascript_` method or use the
759 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
761 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
760 that handle this.
762 that handle this.
761
763
762 The return value of this formatter should be valid Javascript code and
764 The return value of this formatter should be valid Javascript code and
763 should *not* be enclosed in ```<script>``` tags.
765 should *not* be enclosed in ```<script>``` tags.
764 """
766 """
765 format_type = Unicode('application/javascript')
767 format_type = Unicode('application/javascript')
766
768
767 print_method = ObjectName('_repr_javascript_')
769 print_method = ObjectName('_repr_javascript_')
768
770
771
772 class PDFFormatter(BaseFormatter):
773 """A PDF formatter.
774
775 To defined the callables that compute to PDF representation of your
776 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
777 or :meth:`for_type_by_name` methods to register functions that handle
778 this.
779
780 The return value of this formatter should be raw PDF data, *not*
781 base64 encoded.
782 """
783 format_type = Unicode('application/pdf')
784
785 print_method = ObjectName('_repr_pdf_')
786
787
769 FormatterABC.register(BaseFormatter)
788 FormatterABC.register(BaseFormatter)
770 FormatterABC.register(PlainTextFormatter)
789 FormatterABC.register(PlainTextFormatter)
771 FormatterABC.register(HTMLFormatter)
790 FormatterABC.register(HTMLFormatter)
772 FormatterABC.register(SVGFormatter)
791 FormatterABC.register(SVGFormatter)
773 FormatterABC.register(PNGFormatter)
792 FormatterABC.register(PNGFormatter)
793 FormatterABC.register(PDFFormatter)
774 FormatterABC.register(JPEGFormatter)
794 FormatterABC.register(JPEGFormatter)
775 FormatterABC.register(LatexFormatter)
795 FormatterABC.register(LatexFormatter)
776 FormatterABC.register(JSONFormatter)
796 FormatterABC.register(JSONFormatter)
777 FormatterABC.register(JavascriptFormatter)
797 FormatterABC.register(JavascriptFormatter)
778
798
779
799
780 def format_display_data(obj, include=None, exclude=None):
800 def format_display_data(obj, include=None, exclude=None):
781 """Return a format data dict for an object.
801 """Return a format data dict for an object.
782
802
783 By default all format types will be computed.
803 By default all format types will be computed.
784
804
785 The following MIME types are currently implemented:
805 The following MIME types are currently implemented:
786
806
787 * text/plain
807 * text/plain
788 * text/html
808 * text/html
789 * text/latex
809 * text/latex
790 * application/json
810 * application/json
791 * application/javascript
811 * application/javascript
812 * application/pdf
792 * image/png
813 * image/png
793 * image/jpeg
814 * image/jpeg
794 * image/svg+xml
815 * image/svg+xml
795
816
796 Parameters
817 Parameters
797 ----------
818 ----------
798 obj : object
819 obj : object
799 The Python object whose format data will be computed.
820 The Python object whose format data will be computed.
800
821
801 Returns
822 Returns
802 -------
823 -------
803 format_dict : dict
824 format_dict : dict
804 A dictionary of key/value pairs, one or each format that was
825 A dictionary of key/value pairs, one or each format that was
805 generated for the object. The keys are the format types, which
826 generated for the object. The keys are the format types, which
806 will usually be MIME type strings and the values and JSON'able
827 will usually be MIME type strings and the values and JSON'able
807 data structure containing the raw data for the representation in
828 data structure containing the raw data for the representation in
808 that format.
829 that format.
809 include : list or tuple, optional
830 include : list or tuple, optional
810 A list of format type strings (MIME types) to include in the
831 A list of format type strings (MIME types) to include in the
811 format data dict. If this is set *only* the format types included
832 format data dict. If this is set *only* the format types included
812 in this list will be computed.
833 in this list will be computed.
813 exclude : list or tuple, optional
834 exclude : list or tuple, optional
814 A list of format type string (MIME types) to exclue in the format
835 A list of format type string (MIME types) to exclue in the format
815 data dict. If this is set all format types will be computed,
836 data dict. If this is set all format types will be computed,
816 except for those included in this argument.
837 except for those included in this argument.
817 """
838 """
818 from IPython.core.interactiveshell import InteractiveShell
839 from IPython.core.interactiveshell import InteractiveShell
819
840
820 InteractiveShell.instance().display_formatter.format(
841 InteractiveShell.instance().display_formatter.format(
821 obj,
842 obj,
822 include,
843 include,
823 exclude
844 exclude
824 )
845 )
825
846
@@ -1,143 +1,147 b''
1 """Implementation of magic functions for matplotlib/pylab support.
1 """Implementation of magic functions for matplotlib/pylab support.
2 """
2 """
3 from __future__ import print_function
3 from __future__ import print_function
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2012 The IPython Development Team.
5 # Copyright (c) 2012 The IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 # Our own packages
16 # Our own packages
17 from IPython.config.application import Application
17 from IPython.config.application import Application
18 from IPython.core import magic_arguments
18 from IPython.core import magic_arguments
19 from IPython.core.magic import Magics, magics_class, line_magic
19 from IPython.core.magic import Magics, magics_class, line_magic
20 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.testing.skipdoctest import skip_doctest
21 from IPython.utils.warn import warn
21 from IPython.utils.warn import warn
22 from IPython.core.pylabtools import backends
22 from IPython.core.pylabtools import backends
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Magic implementation classes
25 # Magic implementation classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 magic_gui_arg = magic_arguments.argument(
28 magic_gui_arg = magic_arguments.argument(
29 'gui', nargs='?',
29 'gui', nargs='?',
30 help="""Name of the matplotlib backend to use %s.
30 help="""Name of the matplotlib backend to use %s.
31 If given, the corresponding matplotlib backend is used,
31 If given, the corresponding matplotlib backend is used,
32 otherwise it will be matplotlib's default
32 otherwise it will be matplotlib's default
33 (which you can set in your matplotlib config file).
33 (which you can set in your matplotlib config file).
34 """ % str(tuple(sorted(backends.keys())))
34 """ % str(tuple(sorted(backends.keys())))
35 )
35 )
36
36
37
37
38 @magics_class
38 @magics_class
39 class PylabMagics(Magics):
39 class PylabMagics(Magics):
40 """Magics related to matplotlib's pylab support"""
40 """Magics related to matplotlib's pylab support"""
41
41
42 @skip_doctest
42 @skip_doctest
43 @line_magic
43 @line_magic
44 @magic_arguments.magic_arguments()
44 @magic_arguments.magic_arguments()
45 @magic_gui_arg
45 @magic_gui_arg
46 def matplotlib(self, line=''):
46 def matplotlib(self, line=''):
47 """Set up matplotlib to work interactively.
47 """Set up matplotlib to work interactively.
48
48
49 This function lets you activate matplotlib interactive support
49 This function lets you activate matplotlib interactive support
50 at any point during an IPython session.
50 at any point during an IPython session. It does not import anything
51 It does not import anything into the interactive namespace.
51 into the interactive namespace.
52
52
53 If you are using the inline matplotlib backend for embedded figures,
53 If you are using the inline matplotlib backend in the IPython Notebook
54 you can adjust its behavior via the %config magic::
54 you can set which figure formats are enabled using the following::
55
55
56 # enable SVG figures, necessary for SVG+XHTML export in the qtconsole
56 In [1]: from IPython.display import set_matplotlib_formats
57 In [1]: %config InlineBackend.figure_format = 'svg'
57
58 In [2]: set_matplotlib_formats('pdf', 'svg')
58
59
59 # change the behavior of closing all figures at the end of each
60 See the docstring of `IPython.display.set_matplotlib_formats` and
60 # execution (cell), or allowing reuse of active figures across
61 `IPython.display.set_matplotlib_close` for more information on
61 # cells:
62 changing the behavior of the inline backend.
62 In [2]: %config InlineBackend.close_figures = False
63
63
64 Examples
64 Examples
65 --------
65 --------
66 In this case, where the MPL default is TkAgg::
66 To enable the inline backend for usage with the IPython Notebook::
67
68 In [1]: %matplotlib inline
69
70 In this case, where the matplotlib default is TkAgg::
67
71
68 In [2]: %matplotlib
72 In [2]: %matplotlib
69 Using matplotlib backend: TkAgg
73 Using matplotlib backend: TkAgg
70
74
71 But you can explicitly request a different backend::
75 But you can explicitly request a different GUI backend::
72
76
73 In [3]: %matplotlib qt
77 In [3]: %matplotlib qt
74 """
78 """
75 args = magic_arguments.parse_argstring(self.matplotlib, line)
79 args = magic_arguments.parse_argstring(self.matplotlib, line)
76 gui, backend = self.shell.enable_matplotlib(args.gui)
80 gui, backend = self.shell.enable_matplotlib(args.gui)
77 self._show_matplotlib_backend(args.gui, backend)
81 self._show_matplotlib_backend(args.gui, backend)
78
82
79 @skip_doctest
83 @skip_doctest
80 @line_magic
84 @line_magic
81 @magic_arguments.magic_arguments()
85 @magic_arguments.magic_arguments()
82 @magic_arguments.argument(
86 @magic_arguments.argument(
83 '--no-import-all', action='store_true', default=None,
87 '--no-import-all', action='store_true', default=None,
84 help="""Prevent IPython from performing ``import *`` into the interactive namespace.
88 help="""Prevent IPython from performing ``import *`` into the interactive namespace.
85
89
86 You can govern the default behavior of this flag with the
90 You can govern the default behavior of this flag with the
87 InteractiveShellApp.pylab_import_all configurable.
91 InteractiveShellApp.pylab_import_all configurable.
88 """
92 """
89 )
93 )
90 @magic_gui_arg
94 @magic_gui_arg
91 def pylab(self, line=''):
95 def pylab(self, line=''):
92 """Load numpy and matplotlib to work interactively.
96 """Load numpy and matplotlib to work interactively.
93
97
94 This function lets you activate pylab (matplotlib, numpy and
98 This function lets you activate pylab (matplotlib, numpy and
95 interactive support) at any point during an IPython session.
99 interactive support) at any point during an IPython session.
96
100
97 %pylab makes the following imports::
101 %pylab makes the following imports::
98
102
99 import numpy
103 import numpy
100 import matplotlib
104 import matplotlib
101 from matplotlib import pylab, mlab, pyplot
105 from matplotlib import pylab, mlab, pyplot
102 np = numpy
106 np = numpy
103 plt = pyplot
107 plt = pyplot
104
108
105 from IPython.display import display
109 from IPython.display import display
106 from IPython.core.pylabtools import figsize, getfigs
110 from IPython.core.pylabtools import figsize, getfigs
107
111
108 from pylab import *
112 from pylab import *
109 from numpy import *
113 from numpy import *
110
114
111 If you pass `--no-import-all`, the last two `*` imports will be excluded.
115 If you pass `--no-import-all`, the last two `*` imports will be excluded.
112
116
113 See the %matplotlib magic for more details about activating matplotlib
117 See the %matplotlib magic for more details about activating matplotlib
114 without affecting the interactive namespace.
118 without affecting the interactive namespace.
115 """
119 """
116 args = magic_arguments.parse_argstring(self.pylab, line)
120 args = magic_arguments.parse_argstring(self.pylab, line)
117 if args.no_import_all is None:
121 if args.no_import_all is None:
118 # get default from Application
122 # get default from Application
119 if Application.initialized():
123 if Application.initialized():
120 app = Application.instance()
124 app = Application.instance()
121 try:
125 try:
122 import_all = app.pylab_import_all
126 import_all = app.pylab_import_all
123 except AttributeError:
127 except AttributeError:
124 import_all = True
128 import_all = True
125 else:
129 else:
126 # nothing specified, no app - default True
130 # nothing specified, no app - default True
127 import_all = True
131 import_all = True
128 else:
132 else:
129 # invert no-import flag
133 # invert no-import flag
130 import_all = not args.no_import_all
134 import_all = not args.no_import_all
131
135
132 gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
136 gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
133 self._show_matplotlib_backend(args.gui, backend)
137 self._show_matplotlib_backend(args.gui, backend)
134 print ("Populating the interactive namespace from numpy and matplotlib")
138 print ("Populating the interactive namespace from numpy and matplotlib")
135 if clobbered:
139 if clobbered:
136 warn("pylab import has clobbered these variables: %s" % clobbered +
140 warn("pylab import has clobbered these variables: %s" % clobbered +
137 "\n`%pylab --no-import-all` prevents importing * from pylab and numpy"
141 "\n`%pylab --no-import-all` prevents importing * from pylab and numpy"
138 )
142 )
139
143
140 def _show_matplotlib_backend(self, gui, backend):
144 def _show_matplotlib_backend(self, gui, backend):
141 """show matplotlib message backend message"""
145 """show matplotlib message backend message"""
142 if not gui or gui == 'auto':
146 if not gui or gui == 'auto':
143 print("Using matplotlib backend: %s" % backend)
147 print("Using matplotlib backend: %s" % backend)
@@ -1,346 +1,358 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2009 The IPython Development Team
13 # Copyright (C) 2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import sys
23 import sys
24 from io import BytesIO
24 from io import BytesIO
25
25
26 from IPython.core.display import _pngxy
26 from IPython.core.display import _pngxy
27 from IPython.utils.decorators import flag_calls
27 from IPython.utils.decorators import flag_calls
28 from IPython.utils import py3compat
28
29
29 # If user specifies a GUI, that dictates the backend, otherwise we read the
30 # If user specifies a GUI, that dictates the backend, otherwise we read the
30 # user's mpl default from the mpl rc structure
31 # user's mpl default from the mpl rc structure
31 backends = {'tk': 'TkAgg',
32 backends = {'tk': 'TkAgg',
32 'gtk': 'GTKAgg',
33 'gtk': 'GTKAgg',
33 'gtk3': 'GTK3Agg',
34 'gtk3': 'GTK3Agg',
34 'wx': 'WXAgg',
35 'wx': 'WXAgg',
35 'qt': 'Qt4Agg', # qt3 not supported
36 'qt': 'Qt4Agg', # qt3 not supported
36 'qt4': 'Qt4Agg',
37 'qt4': 'Qt4Agg',
37 'osx': 'MacOSX',
38 'osx': 'MacOSX',
38 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
39 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
39
40
40 # We also need a reverse backends2guis mapping that will properly choose which
41 # We also need a reverse backends2guis mapping that will properly choose which
41 # GUI support to activate based on the desired matplotlib backend. For the
42 # GUI support to activate based on the desired matplotlib backend. For the
42 # most part it's just a reverse of the above dict, but we also need to add a
43 # most part it's just a reverse of the above dict, but we also need to add a
43 # few others that map to the same GUI manually:
44 # few others that map to the same GUI manually:
44 backend2gui = dict(zip(backends.values(), backends.keys()))
45 backend2gui = dict(zip(backends.values(), backends.keys()))
45 # Our tests expect backend2gui to just return 'qt'
46 # Our tests expect backend2gui to just return 'qt'
46 backend2gui['Qt4Agg'] = 'qt'
47 backend2gui['Qt4Agg'] = 'qt'
47 # In the reverse mapping, there are a few extra valid matplotlib backends that
48 # In the reverse mapping, there are a few extra valid matplotlib backends that
48 # map to the same GUI support
49 # map to the same GUI support
49 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
50 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
50 backend2gui['GTK3Cairo'] = 'gtk3'
51 backend2gui['GTK3Cairo'] = 'gtk3'
51 backend2gui['WX'] = 'wx'
52 backend2gui['WX'] = 'wx'
52 backend2gui['CocoaAgg'] = 'osx'
53 backend2gui['CocoaAgg'] = 'osx'
53
54
54 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
55 # Matplotlib utilities
56 # Matplotlib utilities
56 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
57
58
58
59
59 def getfigs(*fig_nums):
60 def getfigs(*fig_nums):
60 """Get a list of matplotlib figures by figure numbers.
61 """Get a list of matplotlib figures by figure numbers.
61
62
62 If no arguments are given, all available figures are returned. If the
63 If no arguments are given, all available figures are returned. If the
63 argument list contains references to invalid figures, a warning is printed
64 argument list contains references to invalid figures, a warning is printed
64 but the function continues pasting further figures.
65 but the function continues pasting further figures.
65
66
66 Parameters
67 Parameters
67 ----------
68 ----------
68 figs : tuple
69 figs : tuple
69 A tuple of ints giving the figure numbers of the figures to return.
70 A tuple of ints giving the figure numbers of the figures to return.
70 """
71 """
71 from matplotlib._pylab_helpers import Gcf
72 from matplotlib._pylab_helpers import Gcf
72 if not fig_nums:
73 if not fig_nums:
73 fig_managers = Gcf.get_all_fig_managers()
74 fig_managers = Gcf.get_all_fig_managers()
74 return [fm.canvas.figure for fm in fig_managers]
75 return [fm.canvas.figure for fm in fig_managers]
75 else:
76 else:
76 figs = []
77 figs = []
77 for num in fig_nums:
78 for num in fig_nums:
78 f = Gcf.figs.get(num)
79 f = Gcf.figs.get(num)
79 if f is None:
80 if f is None:
80 print('Warning: figure %s not available.' % num)
81 print('Warning: figure %s not available.' % num)
81 else:
82 else:
82 figs.append(f.canvas.figure)
83 figs.append(f.canvas.figure)
83 return figs
84 return figs
84
85
85
86
86 def figsize(sizex, sizey):
87 def figsize(sizex, sizey):
87 """Set the default figure size to be [sizex, sizey].
88 """Set the default figure size to be [sizex, sizey].
88
89
89 This is just an easy to remember, convenience wrapper that sets::
90 This is just an easy to remember, convenience wrapper that sets::
90
91
91 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92 """
93 """
93 import matplotlib
94 import matplotlib
94 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
95 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
95
96
96
97
97 def print_figure(fig, fmt='png', quality=90):
98 def print_figure(fig, fmt='png', quality=90):
98 """Convert a figure to svg, png or jpg for inline display.
99 """Convert a figure to svg, png or jpg for inline display.
99 Quality is only relevant for jpg.
100 Quality is only relevant for jpg.
100 """
101 """
101 from matplotlib import rcParams
102 from matplotlib import rcParams
102 # When there's an empty figure, we shouldn't return anything, otherwise we
103 # When there's an empty figure, we shouldn't return anything, otherwise we
103 # get big blank areas in the qt console.
104 # get big blank areas in the qt console.
104 if not fig.axes and not fig.lines:
105 if not fig.axes and not fig.lines:
105 return
106 return
106
107
107 fc = fig.get_facecolor()
108 fc = fig.get_facecolor()
108 ec = fig.get_edgecolor()
109 ec = fig.get_edgecolor()
109 bytes_io = BytesIO()
110 bytes_io = BytesIO()
110 dpi = rcParams['savefig.dpi']
111 dpi = rcParams['savefig.dpi']
111 if fmt == 'retina':
112 if fmt == 'retina':
112 dpi = dpi * 2
113 dpi = dpi * 2
113 fmt = 'png'
114 fmt = 'png'
114 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
115 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
115 facecolor=fc, edgecolor=ec, dpi=dpi, quality=quality)
116 facecolor=fc, edgecolor=ec, dpi=dpi, quality=quality)
116 data = bytes_io.getvalue()
117 data = bytes_io.getvalue()
117 return data
118 return data
118
119
119 def retina_figure(fig):
120 def retina_figure(fig):
120 """format a figure as a pixel-doubled (retina) PNG"""
121 """format a figure as a pixel-doubled (retina) PNG"""
121 pngdata = print_figure(fig, fmt='retina')
122 pngdata = print_figure(fig, fmt='retina')
122 w, h = _pngxy(pngdata)
123 w, h = _pngxy(pngdata)
123 metadata = dict(width=w//2, height=h//2)
124 metadata = dict(width=w//2, height=h//2)
124 return pngdata, metadata
125 return pngdata, metadata
125
126
126 # We need a little factory function here to create the closure where
127 # We need a little factory function here to create the closure where
127 # safe_execfile can live.
128 # safe_execfile can live.
128 def mpl_runner(safe_execfile):
129 def mpl_runner(safe_execfile):
129 """Factory to return a matplotlib-enabled runner for %run.
130 """Factory to return a matplotlib-enabled runner for %run.
130
131
131 Parameters
132 Parameters
132 ----------
133 ----------
133 safe_execfile : function
134 safe_execfile : function
134 This must be a function with the same interface as the
135 This must be a function with the same interface as the
135 :meth:`safe_execfile` method of IPython.
136 :meth:`safe_execfile` method of IPython.
136
137
137 Returns
138 Returns
138 -------
139 -------
139 A function suitable for use as the ``runner`` argument of the %run magic
140 A function suitable for use as the ``runner`` argument of the %run magic
140 function.
141 function.
141 """
142 """
142
143
143 def mpl_execfile(fname,*where,**kw):
144 def mpl_execfile(fname,*where,**kw):
144 """matplotlib-aware wrapper around safe_execfile.
145 """matplotlib-aware wrapper around safe_execfile.
145
146
146 Its interface is identical to that of the :func:`execfile` builtin.
147 Its interface is identical to that of the :func:`execfile` builtin.
147
148
148 This is ultimately a call to execfile(), but wrapped in safeties to
149 This is ultimately a call to execfile(), but wrapped in safeties to
149 properly handle interactive rendering."""
150 properly handle interactive rendering."""
150
151
151 import matplotlib
152 import matplotlib
152 import matplotlib.pylab as pylab
153 import matplotlib.pylab as pylab
153
154
154 #print '*** Matplotlib runner ***' # dbg
155 #print '*** Matplotlib runner ***' # dbg
155 # turn off rendering until end of script
156 # turn off rendering until end of script
156 is_interactive = matplotlib.rcParams['interactive']
157 is_interactive = matplotlib.rcParams['interactive']
157 matplotlib.interactive(False)
158 matplotlib.interactive(False)
158 safe_execfile(fname,*where,**kw)
159 safe_execfile(fname,*where,**kw)
159 matplotlib.interactive(is_interactive)
160 matplotlib.interactive(is_interactive)
160 # make rendering call now, if the user tried to do it
161 # make rendering call now, if the user tried to do it
161 if pylab.draw_if_interactive.called:
162 if pylab.draw_if_interactive.called:
162 pylab.draw()
163 pylab.draw()
163 pylab.draw_if_interactive.called = False
164 pylab.draw_if_interactive.called = False
164
165
165 return mpl_execfile
166 return mpl_execfile
166
167
167
168
168 def select_figure_format(shell, fmt, quality=90):
169 def select_figure_formats(shell, formats, quality=90):
169 """Select figure format for inline backend, can be 'png', 'retina', 'jpg', or 'svg'.
170 """Select figure formats for the inline backend.
170
171
171 Using this method ensures only one figure format is active at a time.
172 Parameters
173 ==========
174 shell : InteractiveShell
175 The main IPython instance.
176 formats : list
177 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
178 quality : int
179 A percentage for the quality of JPEG figures.
172 """
180 """
173 from matplotlib.figure import Figure
181 from matplotlib.figure import Figure
174 from IPython.kernel.zmq.pylab import backend_inline
182 from IPython.kernel.zmq.pylab import backend_inline
175
183
176 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
184 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
177 png_formatter = shell.display_formatter.formatters['image/png']
185 png_formatter = shell.display_formatter.formatters['image/png']
178 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
186 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
187 pdf_formatter = shell.display_formatter.formatters['application/pdf']
179
188
180 [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ]
189 if isinstance(formats, py3compat.string_types):
190 formats = {formats}
181
191
182 if fmt == 'png':
192 [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ]
183 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
184 elif fmt in ('png2x', 'retina'):
185 png_formatter.for_type(Figure, retina_figure)
186 elif fmt in ('jpg', 'jpeg'):
187 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality))
188 elif fmt == 'svg':
189 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
190 else:
191 raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', not %r" % fmt)
192
193
193 # set the format to be used in the backend()
194 for fmt in formats:
194 backend_inline._figure_format = fmt
195 if fmt == 'png':
196 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
197 elif fmt in ('png2x', 'retina'):
198 png_formatter.for_type(Figure, retina_figure)
199 elif fmt in ('jpg', 'jpeg'):
200 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality))
201 elif fmt == 'svg':
202 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
203 elif fmt == 'pdf':
204 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf'))
205 else:
206 raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', 'pdf' not %r" % fmt)
195
207
196 #-----------------------------------------------------------------------------
208 #-----------------------------------------------------------------------------
197 # Code for initializing matplotlib and importing pylab
209 # Code for initializing matplotlib and importing pylab
198 #-----------------------------------------------------------------------------
210 #-----------------------------------------------------------------------------
199
211
200
212
201 def find_gui_and_backend(gui=None, gui_select=None):
213 def find_gui_and_backend(gui=None, gui_select=None):
202 """Given a gui string return the gui and mpl backend.
214 """Given a gui string return the gui and mpl backend.
203
215
204 Parameters
216 Parameters
205 ----------
217 ----------
206 gui : str
218 gui : str
207 Can be one of ('tk','gtk','wx','qt','qt4','inline').
219 Can be one of ('tk','gtk','wx','qt','qt4','inline').
208 gui_select : str
220 gui_select : str
209 Can be one of ('tk','gtk','wx','qt','qt4','inline').
221 Can be one of ('tk','gtk','wx','qt','qt4','inline').
210 This is any gui already selected by the shell.
222 This is any gui already selected by the shell.
211
223
212 Returns
224 Returns
213 -------
225 -------
214 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
226 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
215 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
227 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
216 """
228 """
217
229
218 import matplotlib
230 import matplotlib
219
231
220 if gui and gui != 'auto':
232 if gui and gui != 'auto':
221 # select backend based on requested gui
233 # select backend based on requested gui
222 backend = backends[gui]
234 backend = backends[gui]
223 else:
235 else:
224 # We need to read the backend from the original data structure, *not*
236 # We need to read the backend from the original data structure, *not*
225 # from mpl.rcParams, since a prior invocation of %matplotlib may have
237 # from mpl.rcParams, since a prior invocation of %matplotlib may have
226 # overwritten that.
238 # overwritten that.
227 # WARNING: this assumes matplotlib 1.1 or newer!!
239 # WARNING: this assumes matplotlib 1.1 or newer!!
228 backend = matplotlib.rcParamsOrig['backend']
240 backend = matplotlib.rcParamsOrig['backend']
229 # In this case, we need to find what the appropriate gui selection call
241 # In this case, we need to find what the appropriate gui selection call
230 # should be for IPython, so we can activate inputhook accordingly
242 # should be for IPython, so we can activate inputhook accordingly
231 gui = backend2gui.get(backend, None)
243 gui = backend2gui.get(backend, None)
232
244
233 # If we have already had a gui active, we need it and inline are the
245 # If we have already had a gui active, we need it and inline are the
234 # ones allowed.
246 # ones allowed.
235 if gui_select and gui != gui_select:
247 if gui_select and gui != gui_select:
236 gui = gui_select
248 gui = gui_select
237 backend = backends[gui]
249 backend = backends[gui]
238
250
239 return gui, backend
251 return gui, backend
240
252
241
253
242 def activate_matplotlib(backend):
254 def activate_matplotlib(backend):
243 """Activate the given backend and set interactive to True."""
255 """Activate the given backend and set interactive to True."""
244
256
245 import matplotlib
257 import matplotlib
246 matplotlib.interactive(True)
258 matplotlib.interactive(True)
247
259
248 # Matplotlib had a bug where even switch_backend could not force
260 # Matplotlib had a bug where even switch_backend could not force
249 # the rcParam to update. This needs to be set *before* the module
261 # the rcParam to update. This needs to be set *before* the module
250 # magic of switch_backend().
262 # magic of switch_backend().
251 matplotlib.rcParams['backend'] = backend
263 matplotlib.rcParams['backend'] = backend
252
264
253 import matplotlib.pyplot
265 import matplotlib.pyplot
254 matplotlib.pyplot.switch_backend(backend)
266 matplotlib.pyplot.switch_backend(backend)
255
267
256 # This must be imported last in the matplotlib series, after
268 # This must be imported last in the matplotlib series, after
257 # backend/interactivity choices have been made
269 # backend/interactivity choices have been made
258 import matplotlib.pylab as pylab
270 import matplotlib.pylab as pylab
259
271
260 pylab.show._needmain = False
272 pylab.show._needmain = False
261 # We need to detect at runtime whether show() is called by the user.
273 # We need to detect at runtime whether show() is called by the user.
262 # For this, we wrap it into a decorator which adds a 'called' flag.
274 # For this, we wrap it into a decorator which adds a 'called' flag.
263 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
275 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
264
276
265
277
266 def import_pylab(user_ns, import_all=True):
278 def import_pylab(user_ns, import_all=True):
267 """Populate the namespace with pylab-related values.
279 """Populate the namespace with pylab-related values.
268
280
269 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
281 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
270
282
271 Also imports a few names from IPython (figsize, display, getfigs)
283 Also imports a few names from IPython (figsize, display, getfigs)
272
284
273 """
285 """
274
286
275 # Import numpy as np/pyplot as plt are conventions we're trying to
287 # Import numpy as np/pyplot as plt are conventions we're trying to
276 # somewhat standardize on. Making them available to users by default
288 # somewhat standardize on. Making them available to users by default
277 # will greatly help this.
289 # will greatly help this.
278 s = ("import numpy\n"
290 s = ("import numpy\n"
279 "import matplotlib\n"
291 "import matplotlib\n"
280 "from matplotlib import pylab, mlab, pyplot\n"
292 "from matplotlib import pylab, mlab, pyplot\n"
281 "np = numpy\n"
293 "np = numpy\n"
282 "plt = pyplot\n"
294 "plt = pyplot\n"
283 )
295 )
284 exec(s, user_ns)
296 exec(s, user_ns)
285
297
286 if import_all:
298 if import_all:
287 s = ("from matplotlib.pylab import *\n"
299 s = ("from matplotlib.pylab import *\n"
288 "from numpy import *\n")
300 "from numpy import *\n")
289 exec(s, user_ns)
301 exec(s, user_ns)
290
302
291 # IPython symbols to add
303 # IPython symbols to add
292 user_ns['figsize'] = figsize
304 user_ns['figsize'] = figsize
293 from IPython.core.display import display
305 from IPython.core.display import display
294 # Add display and getfigs to the user's namespace
306 # Add display and getfigs to the user's namespace
295 user_ns['display'] = display
307 user_ns['display'] = display
296 user_ns['getfigs'] = getfigs
308 user_ns['getfigs'] = getfigs
297
309
298
310
299 def configure_inline_support(shell, backend):
311 def configure_inline_support(shell, backend):
300 """Configure an IPython shell object for matplotlib use.
312 """Configure an IPython shell object for matplotlib use.
301
313
302 Parameters
314 Parameters
303 ----------
315 ----------
304 shell : InteractiveShell instance
316 shell : InteractiveShell instance
305
317
306 backend : matplotlib backend
318 backend : matplotlib backend
307 """
319 """
308 # If using our svg payload backend, register the post-execution
320 # If using our svg payload backend, register the post-execution
309 # function that will pick up the results for display. This can only be
321 # function that will pick up the results for display. This can only be
310 # done with access to the real shell object.
322 # done with access to the real shell object.
311
323
312 # Note: if we can't load the inline backend, then there's no point
324 # Note: if we can't load the inline backend, then there's no point
313 # continuing (such as in terminal-only shells in environments without
325 # continuing (such as in terminal-only shells in environments without
314 # zeromq available).
326 # zeromq available).
315 try:
327 try:
316 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
328 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
317 except ImportError:
329 except ImportError:
318 return
330 return
319 from matplotlib import pyplot
331 from matplotlib import pyplot
320
332
321 cfg = InlineBackend.instance(parent=shell)
333 cfg = InlineBackend.instance(parent=shell)
322 cfg.shell = shell
334 cfg.shell = shell
323 if cfg not in shell.configurables:
335 if cfg not in shell.configurables:
324 shell.configurables.append(cfg)
336 shell.configurables.append(cfg)
325
337
326 if backend == backends['inline']:
338 if backend == backends['inline']:
327 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
339 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
328 shell.register_post_execute(flush_figures)
340 shell.register_post_execute(flush_figures)
329
341
330 # Save rcParams that will be overwrittern
342 # Save rcParams that will be overwrittern
331 shell._saved_rcParams = dict()
343 shell._saved_rcParams = dict()
332 for k in cfg.rc:
344 for k in cfg.rc:
333 shell._saved_rcParams[k] = pyplot.rcParams[k]
345 shell._saved_rcParams[k] = pyplot.rcParams[k]
334 # load inline_rc
346 # load inline_rc
335 pyplot.rcParams.update(cfg.rc)
347 pyplot.rcParams.update(cfg.rc)
336 else:
348 else:
337 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
349 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
338 if flush_figures in shell._post_execute:
350 if flush_figures in shell._post_execute:
339 shell._post_execute.pop(flush_figures)
351 shell._post_execute.pop(flush_figures)
340 if hasattr(shell, '_saved_rcParams'):
352 if hasattr(shell, '_saved_rcParams'):
341 pyplot.rcParams.update(shell._saved_rcParams)
353 pyplot.rcParams.update(shell._saved_rcParams)
342 del shell._saved_rcParams
354 del shell._saved_rcParams
343
355
344 # Setup the default figure format
356 # Setup the default figure format
345 select_figure_format(shell, cfg.figure_format, cfg.quality)
357 select_figure_formats(shell, cfg.figure_formats, cfg.quality)
346
358
@@ -1,282 +1,291 b''
1 """Tests for the Formatters."""
1 """Tests for the Formatters."""
2
2
3 from math import pi
3 from math import pi
4
4
5 try:
5 try:
6 import numpy
6 import numpy
7 except:
7 except:
8 numpy = None
8 numpy = None
9 import nose.tools as nt
9 import nose.tools as nt
10
10
11 from IPython.core.formatters import PlainTextFormatter, HTMLFormatter, _mod_name_key
11 from IPython.core.formatters import (
12 PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key
13 )
12 from IPython.utils.io import capture_output
14 from IPython.utils.io import capture_output
13
15
14 class A(object):
16 class A(object):
15 def __repr__(self):
17 def __repr__(self):
16 return 'A()'
18 return 'A()'
17
19
18 class B(A):
20 class B(A):
19 def __repr__(self):
21 def __repr__(self):
20 return 'B()'
22 return 'B()'
21
23
22 class C:
24 class C:
23 pass
25 pass
24
26
25 class BadPretty(object):
27 class BadPretty(object):
26 _repr_pretty_ = None
28 _repr_pretty_ = None
27
29
28 class GoodPretty(object):
30 class GoodPretty(object):
29 def _repr_pretty_(self, pp, cycle):
31 def _repr_pretty_(self, pp, cycle):
30 pp.text('foo')
32 pp.text('foo')
31
33
32 def __repr__(self):
34 def __repr__(self):
33 return 'GoodPretty()'
35 return 'GoodPretty()'
34
36
35 def foo_printer(obj, pp, cycle):
37 def foo_printer(obj, pp, cycle):
36 pp.text('foo')
38 pp.text('foo')
37
39
38 def test_pretty():
40 def test_pretty():
39 f = PlainTextFormatter()
41 f = PlainTextFormatter()
40 f.for_type(A, foo_printer)
42 f.for_type(A, foo_printer)
41 nt.assert_equal(f(A()), 'foo')
43 nt.assert_equal(f(A()), 'foo')
42 nt.assert_equal(f(B()), 'foo')
44 nt.assert_equal(f(B()), 'foo')
43 nt.assert_equal(f(GoodPretty()), 'foo')
45 nt.assert_equal(f(GoodPretty()), 'foo')
44 # Just don't raise an exception for the following:
46 # Just don't raise an exception for the following:
45 f(BadPretty())
47 f(BadPretty())
46
48
47 f.pprint = False
49 f.pprint = False
48 nt.assert_equal(f(A()), 'A()')
50 nt.assert_equal(f(A()), 'A()')
49 nt.assert_equal(f(B()), 'B()')
51 nt.assert_equal(f(B()), 'B()')
50 nt.assert_equal(f(GoodPretty()), 'GoodPretty()')
52 nt.assert_equal(f(GoodPretty()), 'GoodPretty()')
51
53
52
54
53 def test_deferred():
55 def test_deferred():
54 f = PlainTextFormatter()
56 f = PlainTextFormatter()
55
57
56 def test_precision():
58 def test_precision():
57 """test various values for float_precision."""
59 """test various values for float_precision."""
58 f = PlainTextFormatter()
60 f = PlainTextFormatter()
59 nt.assert_equal(f(pi), repr(pi))
61 nt.assert_equal(f(pi), repr(pi))
60 f.float_precision = 0
62 f.float_precision = 0
61 if numpy:
63 if numpy:
62 po = numpy.get_printoptions()
64 po = numpy.get_printoptions()
63 nt.assert_equal(po['precision'], 0)
65 nt.assert_equal(po['precision'], 0)
64 nt.assert_equal(f(pi), '3')
66 nt.assert_equal(f(pi), '3')
65 f.float_precision = 2
67 f.float_precision = 2
66 if numpy:
68 if numpy:
67 po = numpy.get_printoptions()
69 po = numpy.get_printoptions()
68 nt.assert_equal(po['precision'], 2)
70 nt.assert_equal(po['precision'], 2)
69 nt.assert_equal(f(pi), '3.14')
71 nt.assert_equal(f(pi), '3.14')
70 f.float_precision = '%g'
72 f.float_precision = '%g'
71 if numpy:
73 if numpy:
72 po = numpy.get_printoptions()
74 po = numpy.get_printoptions()
73 nt.assert_equal(po['precision'], 2)
75 nt.assert_equal(po['precision'], 2)
74 nt.assert_equal(f(pi), '3.14159')
76 nt.assert_equal(f(pi), '3.14159')
75 f.float_precision = '%e'
77 f.float_precision = '%e'
76 nt.assert_equal(f(pi), '3.141593e+00')
78 nt.assert_equal(f(pi), '3.141593e+00')
77 f.float_precision = ''
79 f.float_precision = ''
78 if numpy:
80 if numpy:
79 po = numpy.get_printoptions()
81 po = numpy.get_printoptions()
80 nt.assert_equal(po['precision'], 8)
82 nt.assert_equal(po['precision'], 8)
81 nt.assert_equal(f(pi), repr(pi))
83 nt.assert_equal(f(pi), repr(pi))
82
84
83 def test_bad_precision():
85 def test_bad_precision():
84 """test various invalid values for float_precision."""
86 """test various invalid values for float_precision."""
85 f = PlainTextFormatter()
87 f = PlainTextFormatter()
86 def set_fp(p):
88 def set_fp(p):
87 f.float_precision=p
89 f.float_precision=p
88 nt.assert_raises(ValueError, set_fp, '%')
90 nt.assert_raises(ValueError, set_fp, '%')
89 nt.assert_raises(ValueError, set_fp, '%.3f%i')
91 nt.assert_raises(ValueError, set_fp, '%.3f%i')
90 nt.assert_raises(ValueError, set_fp, 'foo')
92 nt.assert_raises(ValueError, set_fp, 'foo')
91 nt.assert_raises(ValueError, set_fp, -1)
93 nt.assert_raises(ValueError, set_fp, -1)
92
94
93 def test_for_type():
95 def test_for_type():
94 f = PlainTextFormatter()
96 f = PlainTextFormatter()
95
97
96 # initial return, None
98 # initial return, None
97 nt.assert_is(f.for_type(C, foo_printer), None)
99 nt.assert_is(f.for_type(C, foo_printer), None)
98 # no func queries
100 # no func queries
99 nt.assert_is(f.for_type(C), foo_printer)
101 nt.assert_is(f.for_type(C), foo_printer)
100 # shouldn't change anything
102 # shouldn't change anything
101 nt.assert_is(f.for_type(C), foo_printer)
103 nt.assert_is(f.for_type(C), foo_printer)
102 # None should do the same
104 # None should do the same
103 nt.assert_is(f.for_type(C, None), foo_printer)
105 nt.assert_is(f.for_type(C, None), foo_printer)
104 nt.assert_is(f.for_type(C, None), foo_printer)
106 nt.assert_is(f.for_type(C, None), foo_printer)
105
107
106 def test_for_type_string():
108 def test_for_type_string():
107 f = PlainTextFormatter()
109 f = PlainTextFormatter()
108
110
109 mod = C.__module__
111 mod = C.__module__
110
112
111 type_str = '%s.%s' % (C.__module__, 'C')
113 type_str = '%s.%s' % (C.__module__, 'C')
112
114
113 # initial return, None
115 # initial return, None
114 nt.assert_is(f.for_type(type_str, foo_printer), None)
116 nt.assert_is(f.for_type(type_str, foo_printer), None)
115 # no func queries
117 # no func queries
116 nt.assert_is(f.for_type(type_str), foo_printer)
118 nt.assert_is(f.for_type(type_str), foo_printer)
117 nt.assert_in(_mod_name_key(C), f.deferred_printers)
119 nt.assert_in(_mod_name_key(C), f.deferred_printers)
118 nt.assert_is(f.for_type(C), foo_printer)
120 nt.assert_is(f.for_type(C), foo_printer)
119 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
121 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
120 nt.assert_in(C, f.type_printers)
122 nt.assert_in(C, f.type_printers)
121
123
122 def test_for_type_by_name():
124 def test_for_type_by_name():
123 f = PlainTextFormatter()
125 f = PlainTextFormatter()
124
126
125 mod = C.__module__
127 mod = C.__module__
126
128
127 # initial return, None
129 # initial return, None
128 nt.assert_is(f.for_type_by_name(mod, 'C', foo_printer), None)
130 nt.assert_is(f.for_type_by_name(mod, 'C', foo_printer), None)
129 # no func queries
131 # no func queries
130 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
132 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
131 # shouldn't change anything
133 # shouldn't change anything
132 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
134 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
133 # None should do the same
135 # None should do the same
134 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
136 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
135 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
137 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
136
138
137 def test_lookup():
139 def test_lookup():
138 f = PlainTextFormatter()
140 f = PlainTextFormatter()
139
141
140 f.for_type(C, foo_printer)
142 f.for_type(C, foo_printer)
141 nt.assert_is(f.lookup(C()), foo_printer)
143 nt.assert_is(f.lookup(C()), foo_printer)
142 with nt.assert_raises(KeyError):
144 with nt.assert_raises(KeyError):
143 f.lookup(A())
145 f.lookup(A())
144
146
145 def test_lookup_string():
147 def test_lookup_string():
146 f = PlainTextFormatter()
148 f = PlainTextFormatter()
147 type_str = '%s.%s' % (C.__module__, 'C')
149 type_str = '%s.%s' % (C.__module__, 'C')
148
150
149 f.for_type(type_str, foo_printer)
151 f.for_type(type_str, foo_printer)
150 nt.assert_is(f.lookup(C()), foo_printer)
152 nt.assert_is(f.lookup(C()), foo_printer)
151 # should move from deferred to imported dict
153 # should move from deferred to imported dict
152 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
154 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
153 nt.assert_in(C, f.type_printers)
155 nt.assert_in(C, f.type_printers)
154
156
155 def test_lookup_by_type():
157 def test_lookup_by_type():
156 f = PlainTextFormatter()
158 f = PlainTextFormatter()
157 f.for_type(C, foo_printer)
159 f.for_type(C, foo_printer)
158 nt.assert_is(f.lookup_by_type(C), foo_printer)
160 nt.assert_is(f.lookup_by_type(C), foo_printer)
159 type_str = '%s.%s' % (C.__module__, 'C')
161 type_str = '%s.%s' % (C.__module__, 'C')
160 with nt.assert_raises(KeyError):
162 with nt.assert_raises(KeyError):
161 f.lookup_by_type(A)
163 f.lookup_by_type(A)
162
164
163 def test_lookup_by_type_string():
165 def test_lookup_by_type_string():
164 f = PlainTextFormatter()
166 f = PlainTextFormatter()
165 type_str = '%s.%s' % (C.__module__, 'C')
167 type_str = '%s.%s' % (C.__module__, 'C')
166 f.for_type(type_str, foo_printer)
168 f.for_type(type_str, foo_printer)
167
169
168 # verify insertion
170 # verify insertion
169 nt.assert_in(_mod_name_key(C), f.deferred_printers)
171 nt.assert_in(_mod_name_key(C), f.deferred_printers)
170 nt.assert_not_in(C, f.type_printers)
172 nt.assert_not_in(C, f.type_printers)
171
173
172 nt.assert_is(f.lookup_by_type(type_str), foo_printer)
174 nt.assert_is(f.lookup_by_type(type_str), foo_printer)
173 # lookup by string doesn't cause import
175 # lookup by string doesn't cause import
174 nt.assert_in(_mod_name_key(C), f.deferred_printers)
176 nt.assert_in(_mod_name_key(C), f.deferred_printers)
175 nt.assert_not_in(C, f.type_printers)
177 nt.assert_not_in(C, f.type_printers)
176
178
177 nt.assert_is(f.lookup_by_type(C), foo_printer)
179 nt.assert_is(f.lookup_by_type(C), foo_printer)
178 # should move from deferred to imported dict
180 # should move from deferred to imported dict
179 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
181 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
180 nt.assert_in(C, f.type_printers)
182 nt.assert_in(C, f.type_printers)
181
183
182 def test_in_formatter():
184 def test_in_formatter():
183 f = PlainTextFormatter()
185 f = PlainTextFormatter()
184 f.for_type(C, foo_printer)
186 f.for_type(C, foo_printer)
185 type_str = '%s.%s' % (C.__module__, 'C')
187 type_str = '%s.%s' % (C.__module__, 'C')
186 nt.assert_in(C, f)
188 nt.assert_in(C, f)
187 nt.assert_in(type_str, f)
189 nt.assert_in(type_str, f)
188
190
189 def test_string_in_formatter():
191 def test_string_in_formatter():
190 f = PlainTextFormatter()
192 f = PlainTextFormatter()
191 type_str = '%s.%s' % (C.__module__, 'C')
193 type_str = '%s.%s' % (C.__module__, 'C')
192 f.for_type(type_str, foo_printer)
194 f.for_type(type_str, foo_printer)
193 nt.assert_in(type_str, f)
195 nt.assert_in(type_str, f)
194 nt.assert_in(C, f)
196 nt.assert_in(C, f)
195
197
196 def test_pop():
198 def test_pop():
197 f = PlainTextFormatter()
199 f = PlainTextFormatter()
198 f.for_type(C, foo_printer)
200 f.for_type(C, foo_printer)
199 nt.assert_is(f.lookup_by_type(C), foo_printer)
201 nt.assert_is(f.lookup_by_type(C), foo_printer)
200 nt.assert_is(f.pop(C, None), foo_printer)
202 nt.assert_is(f.pop(C, None), foo_printer)
201 f.for_type(C, foo_printer)
203 f.for_type(C, foo_printer)
202 nt.assert_is(f.pop(C), foo_printer)
204 nt.assert_is(f.pop(C), foo_printer)
203 with nt.assert_raises(KeyError):
205 with nt.assert_raises(KeyError):
204 f.lookup_by_type(C)
206 f.lookup_by_type(C)
205 with nt.assert_raises(KeyError):
207 with nt.assert_raises(KeyError):
206 f.pop(C)
208 f.pop(C)
207 with nt.assert_raises(KeyError):
209 with nt.assert_raises(KeyError):
208 f.pop(A)
210 f.pop(A)
209 nt.assert_is(f.pop(A, None), None)
211 nt.assert_is(f.pop(A, None), None)
210
212
211 def test_pop_string():
213 def test_pop_string():
212 f = PlainTextFormatter()
214 f = PlainTextFormatter()
213 type_str = '%s.%s' % (C.__module__, 'C')
215 type_str = '%s.%s' % (C.__module__, 'C')
214
216
215 with nt.assert_raises(KeyError):
217 with nt.assert_raises(KeyError):
216 f.pop(type_str)
218 f.pop(type_str)
217
219
218 f.for_type(type_str, foo_printer)
220 f.for_type(type_str, foo_printer)
219 f.pop(type_str)
221 f.pop(type_str)
220 with nt.assert_raises(KeyError):
222 with nt.assert_raises(KeyError):
221 f.lookup_by_type(C)
223 f.lookup_by_type(C)
222 with nt.assert_raises(KeyError):
224 with nt.assert_raises(KeyError):
223 f.pop(type_str)
225 f.pop(type_str)
224
226
225 f.for_type(C, foo_printer)
227 f.for_type(C, foo_printer)
226 nt.assert_is(f.pop(type_str, None), foo_printer)
228 nt.assert_is(f.pop(type_str, None), foo_printer)
227 with nt.assert_raises(KeyError):
229 with nt.assert_raises(KeyError):
228 f.lookup_by_type(C)
230 f.lookup_by_type(C)
229 with nt.assert_raises(KeyError):
231 with nt.assert_raises(KeyError):
230 f.pop(type_str)
232 f.pop(type_str)
231 nt.assert_is(f.pop(type_str, None), None)
233 nt.assert_is(f.pop(type_str, None), None)
232
234
233
235
234 def test_warn_error_method():
236 def test_warn_error_method():
235 f = HTMLFormatter()
237 f = HTMLFormatter()
236 class BadHTML(object):
238 class BadHTML(object):
237 def _repr_html_(self):
239 def _repr_html_(self):
238 return 1/0
240 return 1/0
239 bad = BadHTML()
241 bad = BadHTML()
240 with capture_output() as captured:
242 with capture_output() as captured:
241 result = f(bad)
243 result = f(bad)
242 nt.assert_is(result, None)
244 nt.assert_is(result, None)
243 nt.assert_in("FormatterWarning", captured.stderr)
245 nt.assert_in("FormatterWarning", captured.stderr)
244 nt.assert_in("text/html", captured.stderr)
246 nt.assert_in("text/html", captured.stderr)
245 nt.assert_in("zero", captured.stderr)
247 nt.assert_in("zero", captured.stderr)
246
248
247 def test_nowarn_notimplemented():
249 def test_nowarn_notimplemented():
248 f = HTMLFormatter()
250 f = HTMLFormatter()
249 class HTMLNotImplemented(object):
251 class HTMLNotImplemented(object):
250 def _repr_html_(self):
252 def _repr_html_(self):
251 raise NotImplementedError
253 raise NotImplementedError
252 return 1/0
254 return 1/0
253 h = HTMLNotImplemented()
255 h = HTMLNotImplemented()
254 with capture_output() as captured:
256 with capture_output() as captured:
255 result = f(h)
257 result = f(h)
256 nt.assert_is(result, None)
258 nt.assert_is(result, None)
257 nt.assert_not_in("FormatterWarning", captured.stderr)
259 nt.assert_not_in("FormatterWarning", captured.stderr)
258
260
259 def test_warn_error_for_type():
261 def test_warn_error_for_type():
260 f = HTMLFormatter()
262 f = HTMLFormatter()
261 f.for_type(int, lambda i: name_error)
263 f.for_type(int, lambda i: name_error)
262 with capture_output() as captured:
264 with capture_output() as captured:
263 result = f(5)
265 result = f(5)
264 nt.assert_is(result, None)
266 nt.assert_is(result, None)
265 nt.assert_in("FormatterWarning", captured.stderr)
267 nt.assert_in("FormatterWarning", captured.stderr)
266 nt.assert_in("text/html", captured.stderr)
268 nt.assert_in("text/html", captured.stderr)
267 nt.assert_in("name_error", captured.stderr)
269 nt.assert_in("name_error", captured.stderr)
268
270
269 def test_warn_error_pretty_method():
271 def test_warn_error_pretty_method():
270 f = PlainTextFormatter()
272 f = PlainTextFormatter()
271 class BadPretty(object):
273 class BadPretty(object):
272 def _repr_pretty_(self):
274 def _repr_pretty_(self):
273 return "hello"
275 return "hello"
274 bad = BadPretty()
276 bad = BadPretty()
275 with capture_output() as captured:
277 with capture_output() as captured:
276 result = f(bad)
278 result = f(bad)
277 nt.assert_is(result, None)
279 nt.assert_is(result, None)
278 nt.assert_in("FormatterWarning", captured.stderr)
280 nt.assert_in("FormatterWarning", captured.stderr)
279 nt.assert_in("text/plain", captured.stderr)
281 nt.assert_in("text/plain", captured.stderr)
280 nt.assert_in("argument", captured.stderr)
282 nt.assert_in("argument", captured.stderr)
281
283
284 class MakePDF(object):
285 def _repr_pdf_(self):
286 return 'PDF'
282
287
288 def test_pdf_formatter():
289 pdf = MakePDF()
290 f = PDFFormatter()
291 nt.assert_equal(f(pdf), 'PDF')
@@ -1,62 +1,62 b''
1 """Tornado handlers logging into the notebook.
1 """Tornado handlers logging into 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) 2011 The IPython Development Team
9 # Copyright (C) 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 uuid
19 import uuid
20
20
21 from tornado.escape import url_escape
21 from tornado.escape import url_escape
22
22
23 from IPython.lib.security import passwd_check
23 from IPython.lib.security import passwd_check
24
24
25 from ..base.handlers import IPythonHandler
25 from ..base.handlers import IPythonHandler
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Handler
28 # Handler
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class LoginHandler(IPythonHandler):
31 class LoginHandler(IPythonHandler):
32
32
33 def _render(self, message=None):
33 def _render(self, message=None):
34 self.write(self.render_template('login.html',
34 self.write(self.render_template('login.html',
35 next=url_escape(self.get_argument('next', default=self.base_project_url)),
35 next=url_escape(self.get_argument('next', default=self.base_url)),
36 message=message,
36 message=message,
37 ))
37 ))
38
38
39 def get(self):
39 def get(self):
40 if self.current_user:
40 if self.current_user:
41 self.redirect(self.get_argument('next', default=self.base_project_url))
41 self.redirect(self.get_argument('next', default=self.base_url))
42 else:
42 else:
43 self._render()
43 self._render()
44
44
45 def post(self):
45 def post(self):
46 pwd = self.get_argument('password', default=u'')
46 pwd = self.get_argument('password', default=u'')
47 if self.login_available:
47 if self.login_available:
48 if passwd_check(self.password, pwd):
48 if passwd_check(self.password, pwd):
49 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()))
49 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()))
50 else:
50 else:
51 self._render(message={'error': 'Invalid password'})
51 self._render(message={'error': 'Invalid password'})
52 return
52 return
53
53
54 self.redirect(self.get_argument('next', default=self.base_project_url))
54 self.redirect(self.get_argument('next', default=self.base_url))
55
55
56
56
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # URL to handler mappings
58 # URL to handler mappings
59 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
60
60
61
61
62 default_handlers = [(r"/login", LoginHandler)]
62 default_handlers = [(r"/login", LoginHandler)]
@@ -1,387 +1,387 b''
1 """Base Tornado handlers for the notebook.
1 """Base 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) 2011 The IPython Development Team
9 # Copyright (C) 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
19
20 import functools
20 import functools
21 import json
21 import json
22 import logging
22 import logging
23 import os
23 import os
24 import re
24 import re
25 import sys
25 import sys
26 import traceback
26 import traceback
27 try:
27 try:
28 # py3
28 # py3
29 from http.client import responses
29 from http.client import responses
30 except ImportError:
30 except ImportError:
31 from httplib import responses
31 from httplib import responses
32
32
33 from jinja2 import TemplateNotFound
33 from jinja2 import TemplateNotFound
34 from tornado import web
34 from tornado import web
35
35
36 try:
36 try:
37 from tornado.log import app_log
37 from tornado.log import app_log
38 except ImportError:
38 except ImportError:
39 app_log = logging.getLogger()
39 app_log = logging.getLogger()
40
40
41 from IPython.config import Application
41 from IPython.config import Application
42 from IPython.utils.path import filefind
42 from IPython.utils.path import filefind
43 from IPython.utils.py3compat import string_types
43 from IPython.utils.py3compat import string_types
44 from IPython.html.utils import is_hidden
44 from IPython.html.utils import is_hidden
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Top-level handlers
47 # Top-level handlers
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 non_alphanum = re.compile(r'[^A-Za-z0-9]')
49 non_alphanum = re.compile(r'[^A-Za-z0-9]')
50
50
51 class AuthenticatedHandler(web.RequestHandler):
51 class AuthenticatedHandler(web.RequestHandler):
52 """A RequestHandler with an authenticated user."""
52 """A RequestHandler with an authenticated user."""
53
53
54 def clear_login_cookie(self):
54 def clear_login_cookie(self):
55 self.clear_cookie(self.cookie_name)
55 self.clear_cookie(self.cookie_name)
56
56
57 def get_current_user(self):
57 def get_current_user(self):
58 user_id = self.get_secure_cookie(self.cookie_name)
58 user_id = self.get_secure_cookie(self.cookie_name)
59 # For now the user_id should not return empty, but it could eventually
59 # For now the user_id should not return empty, but it could eventually
60 if user_id == '':
60 if user_id == '':
61 user_id = 'anonymous'
61 user_id = 'anonymous'
62 if user_id is None:
62 if user_id is None:
63 # prevent extra Invalid cookie sig warnings:
63 # prevent extra Invalid cookie sig warnings:
64 self.clear_login_cookie()
64 self.clear_login_cookie()
65 if not self.login_available:
65 if not self.login_available:
66 user_id = 'anonymous'
66 user_id = 'anonymous'
67 return user_id
67 return user_id
68
68
69 @property
69 @property
70 def cookie_name(self):
70 def cookie_name(self):
71 default_cookie_name = non_alphanum.sub('-', 'username-{}'.format(
71 default_cookie_name = non_alphanum.sub('-', 'username-{}'.format(
72 self.request.host
72 self.request.host
73 ))
73 ))
74 return self.settings.get('cookie_name', default_cookie_name)
74 return self.settings.get('cookie_name', default_cookie_name)
75
75
76 @property
76 @property
77 def password(self):
77 def password(self):
78 """our password"""
78 """our password"""
79 return self.settings.get('password', '')
79 return self.settings.get('password', '')
80
80
81 @property
81 @property
82 def logged_in(self):
82 def logged_in(self):
83 """Is a user currently logged in?
83 """Is a user currently logged in?
84
84
85 """
85 """
86 user = self.get_current_user()
86 user = self.get_current_user()
87 return (user and not user == 'anonymous')
87 return (user and not user == 'anonymous')
88
88
89 @property
89 @property
90 def login_available(self):
90 def login_available(self):
91 """May a user proceed to log in?
91 """May a user proceed to log in?
92
92
93 This returns True if login capability is available, irrespective of
93 This returns True if login capability is available, irrespective of
94 whether the user is already logged in or not.
94 whether the user is already logged in or not.
95
95
96 """
96 """
97 return bool(self.settings.get('password', ''))
97 return bool(self.settings.get('password', ''))
98
98
99
99
100 class IPythonHandler(AuthenticatedHandler):
100 class IPythonHandler(AuthenticatedHandler):
101 """IPython-specific extensions to authenticated handling
101 """IPython-specific extensions to authenticated handling
102
102
103 Mostly property shortcuts to IPython-specific settings.
103 Mostly property shortcuts to IPython-specific settings.
104 """
104 """
105
105
106 @property
106 @property
107 def config(self):
107 def config(self):
108 return self.settings.get('config', None)
108 return self.settings.get('config', None)
109
109
110 @property
110 @property
111 def log(self):
111 def log(self):
112 """use the IPython log by default, falling back on tornado's logger"""
112 """use the IPython log by default, falling back on tornado's logger"""
113 if Application.initialized():
113 if Application.initialized():
114 return Application.instance().log
114 return Application.instance().log
115 else:
115 else:
116 return app_log
116 return app_log
117
117
118 #---------------------------------------------------------------
118 #---------------------------------------------------------------
119 # URLs
119 # URLs
120 #---------------------------------------------------------------
120 #---------------------------------------------------------------
121
121
122 @property
122 @property
123 def ws_url(self):
123 def ws_url(self):
124 """websocket url matching the current request
124 """websocket url matching the current request
125
125
126 By default, this is just `''`, indicating that it should match
126 By default, this is just `''`, indicating that it should match
127 the same host, protocol, port, etc.
127 the same host, protocol, port, etc.
128 """
128 """
129 return self.settings.get('websocket_url', '')
129 return self.settings.get('websocket_url', '')
130
130
131 @property
131 @property
132 def mathjax_url(self):
132 def mathjax_url(self):
133 return self.settings.get('mathjax_url', '')
133 return self.settings.get('mathjax_url', '')
134
134
135 @property
135 @property
136 def base_project_url(self):
136 def base_url(self):
137 return self.settings.get('base_project_url', '/')
137 return self.settings.get('base_url', '/')
138
138
139 @property
139 @property
140 def base_kernel_url(self):
140 def base_kernel_url(self):
141 return self.settings.get('base_kernel_url', '/')
141 return self.settings.get('base_kernel_url', '/')
142
142
143 #---------------------------------------------------------------
143 #---------------------------------------------------------------
144 # Manager objects
144 # Manager objects
145 #---------------------------------------------------------------
145 #---------------------------------------------------------------
146
146
147 @property
147 @property
148 def kernel_manager(self):
148 def kernel_manager(self):
149 return self.settings['kernel_manager']
149 return self.settings['kernel_manager']
150
150
151 @property
151 @property
152 def notebook_manager(self):
152 def notebook_manager(self):
153 return self.settings['notebook_manager']
153 return self.settings['notebook_manager']
154
154
155 @property
155 @property
156 def cluster_manager(self):
156 def cluster_manager(self):
157 return self.settings['cluster_manager']
157 return self.settings['cluster_manager']
158
158
159 @property
159 @property
160 def session_manager(self):
160 def session_manager(self):
161 return self.settings['session_manager']
161 return self.settings['session_manager']
162
162
163 @property
163 @property
164 def project_dir(self):
164 def project_dir(self):
165 return self.notebook_manager.notebook_dir
165 return self.notebook_manager.notebook_dir
166
166
167 #---------------------------------------------------------------
167 #---------------------------------------------------------------
168 # template rendering
168 # template rendering
169 #---------------------------------------------------------------
169 #---------------------------------------------------------------
170
170
171 def get_template(self, name):
171 def get_template(self, name):
172 """Return the jinja template object for a given name"""
172 """Return the jinja template object for a given name"""
173 return self.settings['jinja2_env'].get_template(name)
173 return self.settings['jinja2_env'].get_template(name)
174
174
175 def render_template(self, name, **ns):
175 def render_template(self, name, **ns):
176 ns.update(self.template_namespace)
176 ns.update(self.template_namespace)
177 template = self.get_template(name)
177 template = self.get_template(name)
178 return template.render(**ns)
178 return template.render(**ns)
179
179
180 @property
180 @property
181 def template_namespace(self):
181 def template_namespace(self):
182 return dict(
182 return dict(
183 base_project_url=self.base_project_url,
183 base_url=self.base_url,
184 base_kernel_url=self.base_kernel_url,
184 base_kernel_url=self.base_kernel_url,
185 logged_in=self.logged_in,
185 logged_in=self.logged_in,
186 login_available=self.login_available,
186 login_available=self.login_available,
187 static_url=self.static_url,
187 static_url=self.static_url,
188 )
188 )
189
189
190 def get_json_body(self):
190 def get_json_body(self):
191 """Return the body of the request as JSON data."""
191 """Return the body of the request as JSON data."""
192 if not self.request.body:
192 if not self.request.body:
193 return None
193 return None
194 # Do we need to call body.decode('utf-8') here?
194 # Do we need to call body.decode('utf-8') here?
195 body = self.request.body.strip().decode(u'utf-8')
195 body = self.request.body.strip().decode(u'utf-8')
196 try:
196 try:
197 model = json.loads(body)
197 model = json.loads(body)
198 except Exception:
198 except Exception:
199 self.log.debug("Bad JSON: %r", body)
199 self.log.debug("Bad JSON: %r", body)
200 self.log.error("Couldn't parse JSON", exc_info=True)
200 self.log.error("Couldn't parse JSON", exc_info=True)
201 raise web.HTTPError(400, u'Invalid JSON in body of request')
201 raise web.HTTPError(400, u'Invalid JSON in body of request')
202 return model
202 return model
203
203
204 def get_error_html(self, status_code, **kwargs):
204 def get_error_html(self, status_code, **kwargs):
205 """render custom error pages"""
205 """render custom error pages"""
206 exception = kwargs.get('exception')
206 exception = kwargs.get('exception')
207 message = ''
207 message = ''
208 status_message = responses.get(status_code, 'Unknown HTTP Error')
208 status_message = responses.get(status_code, 'Unknown HTTP Error')
209 if exception:
209 if exception:
210 # get the custom message, if defined
210 # get the custom message, if defined
211 try:
211 try:
212 message = exception.log_message % exception.args
212 message = exception.log_message % exception.args
213 except Exception:
213 except Exception:
214 pass
214 pass
215
215
216 # construct the custom reason, if defined
216 # construct the custom reason, if defined
217 reason = getattr(exception, 'reason', '')
217 reason = getattr(exception, 'reason', '')
218 if reason:
218 if reason:
219 status_message = reason
219 status_message = reason
220
220
221 # build template namespace
221 # build template namespace
222 ns = dict(
222 ns = dict(
223 status_code=status_code,
223 status_code=status_code,
224 status_message=status_message,
224 status_message=status_message,
225 message=message,
225 message=message,
226 exception=exception,
226 exception=exception,
227 )
227 )
228
228
229 # render the template
229 # render the template
230 try:
230 try:
231 html = self.render_template('%s.html' % status_code, **ns)
231 html = self.render_template('%s.html' % status_code, **ns)
232 except TemplateNotFound:
232 except TemplateNotFound:
233 self.log.debug("No template for %d", status_code)
233 self.log.debug("No template for %d", status_code)
234 html = self.render_template('error.html', **ns)
234 html = self.render_template('error.html', **ns)
235 return html
235 return html
236
236
237
237
238 class Template404(IPythonHandler):
238 class Template404(IPythonHandler):
239 """Render our 404 template"""
239 """Render our 404 template"""
240 def prepare(self):
240 def prepare(self):
241 raise web.HTTPError(404)
241 raise web.HTTPError(404)
242
242
243
243
244 class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):
244 class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):
245 """static files should only be accessible when logged in"""
245 """static files should only be accessible when logged in"""
246
246
247 @web.authenticated
247 @web.authenticated
248 def get(self, path):
248 def get(self, path):
249 if os.path.splitext(path)[1] == '.ipynb':
249 if os.path.splitext(path)[1] == '.ipynb':
250 name = os.path.basename(path)
250 name = os.path.basename(path)
251 self.set_header('Content-Type', 'application/json')
251 self.set_header('Content-Type', 'application/json')
252 self.set_header('Content-Disposition','attachment; filename="%s"' % name)
252 self.set_header('Content-Disposition','attachment; filename="%s"' % name)
253
253
254 return web.StaticFileHandler.get(self, path)
254 return web.StaticFileHandler.get(self, path)
255
255
256 def compute_etag(self):
256 def compute_etag(self):
257 return None
257 return None
258
258
259 def validate_absolute_path(self, root, absolute_path):
259 def validate_absolute_path(self, root, absolute_path):
260 """Validate and return the absolute path.
260 """Validate and return the absolute path.
261
261
262 Requires tornado 3.1
262 Requires tornado 3.1
263
263
264 Adding to tornado's own handling, forbids the serving of hidden files.
264 Adding to tornado's own handling, forbids the serving of hidden files.
265 """
265 """
266 abs_path = super(AuthenticatedFileHandler, self).validate_absolute_path(root, absolute_path)
266 abs_path = super(AuthenticatedFileHandler, self).validate_absolute_path(root, absolute_path)
267 abs_root = os.path.abspath(root)
267 abs_root = os.path.abspath(root)
268 if is_hidden(abs_path, abs_root):
268 if is_hidden(abs_path, abs_root):
269 raise web.HTTPError(404)
269 raise web.HTTPError(404)
270 return abs_path
270 return abs_path
271
271
272
272
273 def json_errors(method):
273 def json_errors(method):
274 """Decorate methods with this to return GitHub style JSON errors.
274 """Decorate methods with this to return GitHub style JSON errors.
275
275
276 This should be used on any JSON API on any handler method that can raise HTTPErrors.
276 This should be used on any JSON API on any handler method that can raise HTTPErrors.
277
277
278 This will grab the latest HTTPError exception using sys.exc_info
278 This will grab the latest HTTPError exception using sys.exc_info
279 and then:
279 and then:
280
280
281 1. Set the HTTP status code based on the HTTPError
281 1. Set the HTTP status code based on the HTTPError
282 2. Create and return a JSON body with a message field describing
282 2. Create and return a JSON body with a message field describing
283 the error in a human readable form.
283 the error in a human readable form.
284 """
284 """
285 @functools.wraps(method)
285 @functools.wraps(method)
286 def wrapper(self, *args, **kwargs):
286 def wrapper(self, *args, **kwargs):
287 try:
287 try:
288 result = method(self, *args, **kwargs)
288 result = method(self, *args, **kwargs)
289 except web.HTTPError as e:
289 except web.HTTPError as e:
290 status = e.status_code
290 status = e.status_code
291 message = e.log_message
291 message = e.log_message
292 self.set_status(e.status_code)
292 self.set_status(e.status_code)
293 self.finish(json.dumps(dict(message=message)))
293 self.finish(json.dumps(dict(message=message)))
294 except Exception:
294 except Exception:
295 self.log.error("Unhandled error in API request", exc_info=True)
295 self.log.error("Unhandled error in API request", exc_info=True)
296 status = 500
296 status = 500
297 message = "Unknown server error"
297 message = "Unknown server error"
298 t, value, tb = sys.exc_info()
298 t, value, tb = sys.exc_info()
299 self.set_status(status)
299 self.set_status(status)
300 tb_text = ''.join(traceback.format_exception(t, value, tb))
300 tb_text = ''.join(traceback.format_exception(t, value, tb))
301 reply = dict(message=message, traceback=tb_text)
301 reply = dict(message=message, traceback=tb_text)
302 self.finish(json.dumps(reply))
302 self.finish(json.dumps(reply))
303 else:
303 else:
304 return result
304 return result
305 return wrapper
305 return wrapper
306
306
307
307
308
308
309 #-----------------------------------------------------------------------------
309 #-----------------------------------------------------------------------------
310 # File handler
310 # File handler
311 #-----------------------------------------------------------------------------
311 #-----------------------------------------------------------------------------
312
312
313 # to minimize subclass changes:
313 # to minimize subclass changes:
314 HTTPError = web.HTTPError
314 HTTPError = web.HTTPError
315
315
316 class FileFindHandler(web.StaticFileHandler):
316 class FileFindHandler(web.StaticFileHandler):
317 """subclass of StaticFileHandler for serving files from a search path"""
317 """subclass of StaticFileHandler for serving files from a search path"""
318
318
319 # cache search results, don't search for files more than once
319 # cache search results, don't search for files more than once
320 _static_paths = {}
320 _static_paths = {}
321
321
322 def initialize(self, path, default_filename=None):
322 def initialize(self, path, default_filename=None):
323 if isinstance(path, string_types):
323 if isinstance(path, string_types):
324 path = [path]
324 path = [path]
325
325
326 self.root = tuple(
326 self.root = tuple(
327 os.path.abspath(os.path.expanduser(p)) + os.sep for p in path
327 os.path.abspath(os.path.expanduser(p)) + os.sep for p in path
328 )
328 )
329 self.default_filename = default_filename
329 self.default_filename = default_filename
330
330
331 def compute_etag(self):
331 def compute_etag(self):
332 return None
332 return None
333
333
334 @classmethod
334 @classmethod
335 def get_absolute_path(cls, roots, path):
335 def get_absolute_path(cls, roots, path):
336 """locate a file to serve on our static file search path"""
336 """locate a file to serve on our static file search path"""
337 with cls._lock:
337 with cls._lock:
338 if path in cls._static_paths:
338 if path in cls._static_paths:
339 return cls._static_paths[path]
339 return cls._static_paths[path]
340 try:
340 try:
341 abspath = os.path.abspath(filefind(path, roots))
341 abspath = os.path.abspath(filefind(path, roots))
342 except IOError:
342 except IOError:
343 # IOError means not found
343 # IOError means not found
344 return ''
344 return ''
345
345
346 cls._static_paths[path] = abspath
346 cls._static_paths[path] = abspath
347 return abspath
347 return abspath
348
348
349 def validate_absolute_path(self, root, absolute_path):
349 def validate_absolute_path(self, root, absolute_path):
350 """check if the file should be served (raises 404, 403, etc.)"""
350 """check if the file should be served (raises 404, 403, etc.)"""
351 if absolute_path == '':
351 if absolute_path == '':
352 raise web.HTTPError(404)
352 raise web.HTTPError(404)
353
353
354 for root in self.root:
354 for root in self.root:
355 if (absolute_path + os.sep).startswith(root):
355 if (absolute_path + os.sep).startswith(root):
356 break
356 break
357
357
358 return super(FileFindHandler, self).validate_absolute_path(root, absolute_path)
358 return super(FileFindHandler, self).validate_absolute_path(root, absolute_path)
359
359
360
360
361 class TrailingSlashHandler(web.RequestHandler):
361 class TrailingSlashHandler(web.RequestHandler):
362 """Simple redirect handler that strips trailing slashes
362 """Simple redirect handler that strips trailing slashes
363
363
364 This should be the first, highest priority handler.
364 This should be the first, highest priority handler.
365 """
365 """
366
366
367 SUPPORTED_METHODS = ['GET']
367 SUPPORTED_METHODS = ['GET']
368
368
369 def get(self):
369 def get(self):
370 self.redirect(self.request.uri.rstrip('/'))
370 self.redirect(self.request.uri.rstrip('/'))
371
371
372 #-----------------------------------------------------------------------------
372 #-----------------------------------------------------------------------------
373 # URL pattern fragments for re-use
373 # URL pattern fragments for re-use
374 #-----------------------------------------------------------------------------
374 #-----------------------------------------------------------------------------
375
375
376 path_regex = r"(?P<path>(?:/.*)*)"
376 path_regex = r"(?P<path>(?:/.*)*)"
377 notebook_name_regex = r"(?P<name>[^/]+\.ipynb)"
377 notebook_name_regex = r"(?P<name>[^/]+\.ipynb)"
378 notebook_path_regex = "%s/%s" % (path_regex, notebook_name_regex)
378 notebook_path_regex = "%s/%s" % (path_regex, notebook_name_regex)
379
379
380 #-----------------------------------------------------------------------------
380 #-----------------------------------------------------------------------------
381 # URL to handler mappings
381 # URL to handler mappings
382 #-----------------------------------------------------------------------------
382 #-----------------------------------------------------------------------------
383
383
384
384
385 default_handlers = [
385 default_handlers = [
386 (r".*/", TrailingSlashHandler)
386 (r".*/", TrailingSlashHandler)
387 ]
387 ]
@@ -1,90 +1,90 b''
1 """Tornado handlers for the live notebook view.
1 """Tornado handlers for the live notebook view.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 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 os
19 import os
20 from tornado import web
20 from tornado import web
21 HTTPError = web.HTTPError
21 HTTPError = web.HTTPError
22
22
23 from ..base.handlers import IPythonHandler, notebook_path_regex, path_regex
23 from ..base.handlers import IPythonHandler, notebook_path_regex, path_regex
24 from ..utils import url_path_join, url_escape
24 from ..utils import url_path_join, url_escape
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Handlers
27 # Handlers
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30
30
31 class NotebookHandler(IPythonHandler):
31 class NotebookHandler(IPythonHandler):
32
32
33 @web.authenticated
33 @web.authenticated
34 def get(self, path='', name=None):
34 def get(self, path='', name=None):
35 """get renders the notebook template if a name is given, or
35 """get renders the notebook template if a name is given, or
36 redirects to the '/files/' handler if the name is not given."""
36 redirects to the '/files/' handler if the name is not given."""
37 path = path.strip('/')
37 path = path.strip('/')
38 nbm = self.notebook_manager
38 nbm = self.notebook_manager
39 if name is None:
39 if name is None:
40 raise web.HTTPError(500, "This shouldn't be accessible: %s" % self.request.uri)
40 raise web.HTTPError(500, "This shouldn't be accessible: %s" % self.request.uri)
41
41
42 # a .ipynb filename was given
42 # a .ipynb filename was given
43 if not nbm.notebook_exists(name, path):
43 if not nbm.notebook_exists(name, path):
44 raise web.HTTPError(404, u'Notebook does not exist: %s/%s' % (path, name))
44 raise web.HTTPError(404, u'Notebook does not exist: %s/%s' % (path, name))
45 name = url_escape(name)
45 name = url_escape(name)
46 path = url_escape(path)
46 path = url_escape(path)
47 self.write(self.render_template('notebook.html',
47 self.write(self.render_template('notebook.html',
48 project=self.project_dir,
48 project=self.project_dir,
49 notebook_path=path,
49 notebook_path=path,
50 notebook_name=name,
50 notebook_name=name,
51 kill_kernel=False,
51 kill_kernel=False,
52 mathjax_url=self.mathjax_url,
52 mathjax_url=self.mathjax_url,
53 )
53 )
54 )
54 )
55
55
56 class NotebookRedirectHandler(IPythonHandler):
56 class NotebookRedirectHandler(IPythonHandler):
57 def get(self, path=''):
57 def get(self, path=''):
58 nbm = self.notebook_manager
58 nbm = self.notebook_manager
59 if nbm.path_exists(path):
59 if nbm.path_exists(path):
60 # it's a *directory*, redirect to /tree
60 # it's a *directory*, redirect to /tree
61 url = url_path_join(self.base_project_url, 'tree', path)
61 url = url_path_join(self.base_url, 'tree', path)
62 else:
62 else:
63 # otherwise, redirect to /files
63 # otherwise, redirect to /files
64 if '/files/' in path:
64 if '/files/' in path:
65 # redirect without files/ iff it would 404
65 # redirect without files/ iff it would 404
66 # this preserves pre-2.0-style 'files/' links
66 # this preserves pre-2.0-style 'files/' links
67 # FIXME: this is hardcoded based on notebook_path,
67 # FIXME: this is hardcoded based on notebook_path,
68 # but so is the files handler itself,
68 # but so is the files handler itself,
69 # so it should work until both are cleaned up.
69 # so it should work until both are cleaned up.
70 parts = path.split('/')
70 parts = path.split('/')
71 files_path = os.path.join(nbm.notebook_dir, *parts)
71 files_path = os.path.join(nbm.notebook_dir, *parts)
72 self.log.warn("filespath: %s", files_path)
72 self.log.warn("filespath: %s", files_path)
73 if not os.path.exists(files_path):
73 if not os.path.exists(files_path):
74 path = path.replace('/files/', '/', 1)
74 path = path.replace('/files/', '/', 1)
75
75
76 url = url_path_join(self.base_project_url, 'files', path)
76 url = url_path_join(self.base_url, 'files', path)
77 url = url_escape(url)
77 url = url_escape(url)
78 self.log.debug("Redirecting %s to %s", self.request.path, url)
78 self.log.debug("Redirecting %s to %s", self.request.path, url)
79 self.redirect(url)
79 self.redirect(url)
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # URL to handler mappings
82 # URL to handler mappings
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85
85
86 default_handlers = [
86 default_handlers = [
87 (r"/notebooks%s" % notebook_path_regex, NotebookHandler),
87 (r"/notebooks%s" % notebook_path_regex, NotebookHandler),
88 (r"/notebooks%s" % path_regex, NotebookRedirectHandler),
88 (r"/notebooks%s" % path_regex, NotebookRedirectHandler),
89 ]
89 ]
90
90
@@ -1,837 +1,842 b''
1 # coding: utf-8
1 # coding: utf-8
2 """A tornado based IPython notebook server.
2 """A tornado based IPython notebook server.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8 from __future__ import print_function
8 from __future__ import print_function
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2013 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 # stdlib
20 # stdlib
21 import errno
21 import errno
22 import io
22 import io
23 import json
23 import json
24 import logging
24 import logging
25 import os
25 import os
26 import random
26 import random
27 import select
27 import select
28 import signal
28 import signal
29 import socket
29 import socket
30 import sys
30 import sys
31 import threading
31 import threading
32 import time
32 import time
33 import webbrowser
33 import webbrowser
34
34
35
35
36 # Third party
36 # Third party
37 # check for pyzmq 2.1.11
37 # check for pyzmq 2.1.11
38 from IPython.utils.zmqrelated import check_for_zmq
38 from IPython.utils.zmqrelated import check_for_zmq
39 check_for_zmq('2.1.11', 'IPython.html')
39 check_for_zmq('2.1.11', 'IPython.html')
40
40
41 from jinja2 import Environment, FileSystemLoader
41 from jinja2 import Environment, FileSystemLoader
42
42
43 # Install the pyzmq ioloop. This has to be done before anything else from
43 # Install the pyzmq ioloop. This has to be done before anything else from
44 # tornado is imported.
44 # tornado is imported.
45 from zmq.eventloop import ioloop
45 from zmq.eventloop import ioloop
46 ioloop.install()
46 ioloop.install()
47
47
48 # check for tornado 3.1.0
48 # check for tornado 3.1.0
49 msg = "The IPython Notebook requires tornado >= 3.1.0"
49 msg = "The IPython Notebook requires tornado >= 3.1.0"
50 try:
50 try:
51 import tornado
51 import tornado
52 except ImportError:
52 except ImportError:
53 raise ImportError(msg)
53 raise ImportError(msg)
54 try:
54 try:
55 version_info = tornado.version_info
55 version_info = tornado.version_info
56 except AttributeError:
56 except AttributeError:
57 raise ImportError(msg + ", but you have < 1.1.0")
57 raise ImportError(msg + ", but you have < 1.1.0")
58 if version_info < (3,1,0):
58 if version_info < (3,1,0):
59 raise ImportError(msg + ", but you have %s" % tornado.version)
59 raise ImportError(msg + ", but you have %s" % tornado.version)
60
60
61 from tornado import httpserver
61 from tornado import httpserver
62 from tornado import web
62 from tornado import web
63
63
64 # Our own libraries
64 # Our own libraries
65 from IPython.html import DEFAULT_STATIC_FILES_PATH
65 from IPython.html import DEFAULT_STATIC_FILES_PATH
66 from .base.handlers import Template404
66 from .base.handlers import Template404
67 from .log import log_request
67 from .log import log_request
68 from .services.kernels.kernelmanager import MappingKernelManager
68 from .services.kernels.kernelmanager import MappingKernelManager
69 from .services.notebooks.nbmanager import NotebookManager
69 from .services.notebooks.nbmanager import NotebookManager
70 from .services.notebooks.filenbmanager import FileNotebookManager
70 from .services.notebooks.filenbmanager import FileNotebookManager
71 from .services.clusters.clustermanager import ClusterManager
71 from .services.clusters.clustermanager import ClusterManager
72 from .services.sessions.sessionmanager import SessionManager
72 from .services.sessions.sessionmanager import SessionManager
73
73
74 from .base.handlers import AuthenticatedFileHandler, FileFindHandler
74 from .base.handlers import AuthenticatedFileHandler, FileFindHandler
75
75
76 from IPython.config.application import catch_config_error, boolean_flag
76 from IPython.config.application import catch_config_error, boolean_flag
77 from IPython.core.application import BaseIPythonApplication
77 from IPython.core.application import BaseIPythonApplication
78 from IPython.core.profiledir import ProfileDir
78 from IPython.core.profiledir import ProfileDir
79 from IPython.consoleapp import IPythonConsoleApp
79 from IPython.consoleapp import IPythonConsoleApp
80 from IPython.kernel import swallow_argv
80 from IPython.kernel import swallow_argv
81 from IPython.kernel.zmq.session import default_secure
81 from IPython.kernel.zmq.session import default_secure
82 from IPython.kernel.zmq.kernelapp import (
82 from IPython.kernel.zmq.kernelapp import (
83 kernel_flags,
83 kernel_flags,
84 kernel_aliases,
84 kernel_aliases,
85 )
85 )
86 from IPython.utils.importstring import import_item
86 from IPython.utils.importstring import import_item
87 from IPython.utils.localinterfaces import localhost
87 from IPython.utils.localinterfaces import localhost
88 from IPython.utils import submodule
88 from IPython.utils import submodule
89 from IPython.utils.traitlets import (
89 from IPython.utils.traitlets import (
90 Dict, Unicode, Integer, List, Bool, Bytes,
90 Dict, Unicode, Integer, List, Bool, Bytes,
91 DottedObjectName
91 DottedObjectName
92 )
92 )
93 from IPython.utils import py3compat
93 from IPython.utils import py3compat
94 from IPython.utils.path import filefind, get_ipython_dir
94 from IPython.utils.path import filefind, get_ipython_dir
95
95
96 from .utils import url_path_join
96 from .utils import url_path_join
97
97
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99 # Module globals
99 # Module globals
100 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
101
101
102 _examples = """
102 _examples = """
103 ipython notebook # start the notebook
103 ipython notebook # start the notebook
104 ipython notebook --profile=sympy # use the sympy profile
104 ipython notebook --profile=sympy # use the sympy profile
105 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
105 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
106 """
106 """
107
107
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109 # Helper functions
109 # Helper functions
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111
111
112 def random_ports(port, n):
112 def random_ports(port, n):
113 """Generate a list of n random ports near the given port.
113 """Generate a list of n random ports near the given port.
114
114
115 The first 5 ports will be sequential, and the remaining n-5 will be
115 The first 5 ports will be sequential, and the remaining n-5 will be
116 randomly selected in the range [port-2*n, port+2*n].
116 randomly selected in the range [port-2*n, port+2*n].
117 """
117 """
118 for i in range(min(5, n)):
118 for i in range(min(5, n)):
119 yield port + i
119 yield port + i
120 for i in range(n-5):
120 for i in range(n-5):
121 yield max(1, port + random.randint(-2*n, 2*n))
121 yield max(1, port + random.randint(-2*n, 2*n))
122
122
123 def load_handlers(name):
123 def load_handlers(name):
124 """Load the (URL pattern, handler) tuples for each component."""
124 """Load the (URL pattern, handler) tuples for each component."""
125 name = 'IPython.html.' + name
125 name = 'IPython.html.' + name
126 mod = __import__(name, fromlist=['default_handlers'])
126 mod = __import__(name, fromlist=['default_handlers'])
127 return mod.default_handlers
127 return mod.default_handlers
128
128
129 #-----------------------------------------------------------------------------
129 #-----------------------------------------------------------------------------
130 # The Tornado web application
130 # The Tornado web application
131 #-----------------------------------------------------------------------------
131 #-----------------------------------------------------------------------------
132
132
133 class NotebookWebApplication(web.Application):
133 class NotebookWebApplication(web.Application):
134
134
135 def __init__(self, ipython_app, kernel_manager, notebook_manager,
135 def __init__(self, ipython_app, kernel_manager, notebook_manager,
136 cluster_manager, session_manager, log, base_project_url,
136 cluster_manager, session_manager, log, base_url,
137 settings_overrides):
137 settings_overrides):
138
138
139 settings = self.init_settings(
139 settings = self.init_settings(
140 ipython_app, kernel_manager, notebook_manager, cluster_manager,
140 ipython_app, kernel_manager, notebook_manager, cluster_manager,
141 session_manager, log, base_project_url, settings_overrides)
141 session_manager, log, base_url, settings_overrides)
142 handlers = self.init_handlers(settings)
142 handlers = self.init_handlers(settings)
143
143
144 super(NotebookWebApplication, self).__init__(handlers, **settings)
144 super(NotebookWebApplication, self).__init__(handlers, **settings)
145
145
146 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
146 def init_settings(self, ipython_app, kernel_manager, notebook_manager,
147 cluster_manager, session_manager, log, base_project_url,
147 cluster_manager, session_manager, log, base_url,
148 settings_overrides):
148 settings_overrides):
149 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
149 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
150 # base_project_url will always be unicode, which will in turn
150 # base_url will always be unicode, which will in turn
151 # make the patterns unicode, and ultimately result in unicode
151 # make the patterns unicode, and ultimately result in unicode
152 # keys in kwargs to handler._execute(**kwargs) in tornado.
152 # keys in kwargs to handler._execute(**kwargs) in tornado.
153 # This enforces that base_project_url be ascii in that situation.
153 # This enforces that base_url be ascii in that situation.
154 #
154 #
155 # Note that the URLs these patterns check against are escaped,
155 # Note that the URLs these patterns check against are escaped,
156 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
156 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
157 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
157 base_url = py3compat.unicode_to_str(base_url, 'ascii')
158 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
158 template_path = settings_overrides.get("template_path", os.path.join(os.path.dirname(__file__), "templates"))
159 settings = dict(
159 settings = dict(
160 # basics
160 # basics
161 log_function=log_request,
161 log_function=log_request,
162 base_project_url=base_project_url,
162 base_url=base_url,
163 base_kernel_url=ipython_app.base_kernel_url,
163 base_kernel_url=ipython_app.base_kernel_url,
164 template_path=template_path,
164 template_path=template_path,
165 static_path=ipython_app.static_file_path,
165 static_path=ipython_app.static_file_path,
166 static_handler_class = FileFindHandler,
166 static_handler_class = FileFindHandler,
167 static_url_prefix = url_path_join(base_project_url,'/static/'),
167 static_url_prefix = url_path_join(base_url,'/static/'),
168
168
169 # authentication
169 # authentication
170 cookie_secret=ipython_app.cookie_secret,
170 cookie_secret=ipython_app.cookie_secret,
171 login_url=url_path_join(base_project_url,'/login'),
171 login_url=url_path_join(base_url,'/login'),
172 password=ipython_app.password,
172 password=ipython_app.password,
173
173
174 # managers
174 # managers
175 kernel_manager=kernel_manager,
175 kernel_manager=kernel_manager,
176 notebook_manager=notebook_manager,
176 notebook_manager=notebook_manager,
177 cluster_manager=cluster_manager,
177 cluster_manager=cluster_manager,
178 session_manager=session_manager,
178 session_manager=session_manager,
179
179
180 # IPython stuff
180 # IPython stuff
181 nbextensions_path = ipython_app.nbextensions_path,
181 nbextensions_path = ipython_app.nbextensions_path,
182 mathjax_url=ipython_app.mathjax_url,
182 mathjax_url=ipython_app.mathjax_url,
183 config=ipython_app.config,
183 config=ipython_app.config,
184 jinja2_env=Environment(loader=FileSystemLoader(template_path)),
184 jinja2_env=Environment(loader=FileSystemLoader(template_path)),
185 )
185 )
186
186
187 # allow custom overrides for the tornado web app.
187 # allow custom overrides for the tornado web app.
188 settings.update(settings_overrides)
188 settings.update(settings_overrides)
189 return settings
189 return settings
190
190
191 def init_handlers(self, settings):
191 def init_handlers(self, settings):
192 # Load the (URL pattern, handler) tuples for each component.
192 # Load the (URL pattern, handler) tuples for each component.
193 handlers = []
193 handlers = []
194 handlers.extend(load_handlers('base.handlers'))
194 handlers.extend(load_handlers('base.handlers'))
195 handlers.extend(load_handlers('tree.handlers'))
195 handlers.extend(load_handlers('tree.handlers'))
196 handlers.extend(load_handlers('auth.login'))
196 handlers.extend(load_handlers('auth.login'))
197 handlers.extend(load_handlers('auth.logout'))
197 handlers.extend(load_handlers('auth.logout'))
198 handlers.extend(load_handlers('notebook.handlers'))
198 handlers.extend(load_handlers('notebook.handlers'))
199 handlers.extend(load_handlers('nbconvert.handlers'))
199 handlers.extend(load_handlers('nbconvert.handlers'))
200 handlers.extend(load_handlers('services.kernels.handlers'))
200 handlers.extend(load_handlers('services.kernels.handlers'))
201 handlers.extend(load_handlers('services.notebooks.handlers'))
201 handlers.extend(load_handlers('services.notebooks.handlers'))
202 handlers.extend(load_handlers('services.clusters.handlers'))
202 handlers.extend(load_handlers('services.clusters.handlers'))
203 handlers.extend(load_handlers('services.sessions.handlers'))
203 handlers.extend(load_handlers('services.sessions.handlers'))
204 handlers.extend(load_handlers('services.nbconvert.handlers'))
204 handlers.extend(load_handlers('services.nbconvert.handlers'))
205 handlers.extend([
205 handlers.extend([
206 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : settings['notebook_manager'].notebook_dir}),
206 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : settings['notebook_manager'].notebook_dir}),
207 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
207 (r"/nbextensions/(.*)", FileFindHandler, {'path' : settings['nbextensions_path']}),
208 ])
208 ])
209 # prepend base_project_url onto the patterns that we match
209 # prepend base_url onto the patterns that we match
210 new_handlers = []
210 new_handlers = []
211 for handler in handlers:
211 for handler in handlers:
212 pattern = url_path_join(settings['base_project_url'], handler[0])
212 pattern = url_path_join(settings['base_url'], handler[0])
213 new_handler = tuple([pattern] + list(handler[1:]))
213 new_handler = tuple([pattern] + list(handler[1:]))
214 new_handlers.append(new_handler)
214 new_handlers.append(new_handler)
215 # add 404 on the end, which will catch everything that falls through
215 # add 404 on the end, which will catch everything that falls through
216 new_handlers.append((r'(.*)', Template404))
216 new_handlers.append((r'(.*)', Template404))
217 return new_handlers
217 return new_handlers
218
218
219
219
220 class NbserverListApp(BaseIPythonApplication):
220 class NbserverListApp(BaseIPythonApplication):
221
221
222 description="List currently running notebook servers in this profile."
222 description="List currently running notebook servers in this profile."
223
223
224 flags = dict(
224 flags = dict(
225 json=({'NbserverListApp': {'json': True}},
225 json=({'NbserverListApp': {'json': True}},
226 "Produce machine-readable JSON output."),
226 "Produce machine-readable JSON output."),
227 )
227 )
228
228
229 json = Bool(False, config=True,
229 json = Bool(False, config=True,
230 help="If True, each line of output will be a JSON object with the "
230 help="If True, each line of output will be a JSON object with the "
231 "details from the server info file.")
231 "details from the server info file.")
232
232
233 def start(self):
233 def start(self):
234 if not self.json:
234 if not self.json:
235 print("Currently running servers:")
235 print("Currently running servers:")
236 for serverinfo in list_running_servers(self.profile):
236 for serverinfo in list_running_servers(self.profile):
237 if self.json:
237 if self.json:
238 print(json.dumps(serverinfo))
238 print(json.dumps(serverinfo))
239 else:
239 else:
240 print(serverinfo['url'], "::", serverinfo['notebook_dir'])
240 print(serverinfo['url'], "::", serverinfo['notebook_dir'])
241
241
242 #-----------------------------------------------------------------------------
242 #-----------------------------------------------------------------------------
243 # Aliases and Flags
243 # Aliases and Flags
244 #-----------------------------------------------------------------------------
244 #-----------------------------------------------------------------------------
245
245
246 flags = dict(kernel_flags)
246 flags = dict(kernel_flags)
247 flags['no-browser']=(
247 flags['no-browser']=(
248 {'NotebookApp' : {'open_browser' : False}},
248 {'NotebookApp' : {'open_browser' : False}},
249 "Don't open the notebook in a browser after startup."
249 "Don't open the notebook in a browser after startup."
250 )
250 )
251 flags['no-mathjax']=(
251 flags['no-mathjax']=(
252 {'NotebookApp' : {'enable_mathjax' : False}},
252 {'NotebookApp' : {'enable_mathjax' : False}},
253 """Disable MathJax
253 """Disable MathJax
254
254
255 MathJax is the javascript library IPython uses to render math/LaTeX. It is
255 MathJax is the javascript library IPython uses to render math/LaTeX. It is
256 very large, so you may want to disable it if you have a slow internet
256 very large, so you may want to disable it if you have a slow internet
257 connection, or for offline use of the notebook.
257 connection, or for offline use of the notebook.
258
258
259 When disabled, equations etc. will appear as their untransformed TeX source.
259 When disabled, equations etc. will appear as their untransformed TeX source.
260 """
260 """
261 )
261 )
262
262
263 # Add notebook manager flags
263 # Add notebook manager flags
264 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
264 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
265 'Auto-save a .py script everytime the .ipynb notebook is saved',
265 'Auto-save a .py script everytime the .ipynb notebook is saved',
266 'Do not auto-save .py scripts for every notebook'))
266 'Do not auto-save .py scripts for every notebook'))
267
267
268 # the flags that are specific to the frontend
268 # the flags that are specific to the frontend
269 # these must be scrubbed before being passed to the kernel,
269 # these must be scrubbed before being passed to the kernel,
270 # or it will raise an error on unrecognized flags
270 # or it will raise an error on unrecognized flags
271 notebook_flags = ['no-browser', 'no-mathjax', 'script', 'no-script']
271 notebook_flags = ['no-browser', 'no-mathjax', 'script', 'no-script']
272
272
273 aliases = dict(kernel_aliases)
273 aliases = dict(kernel_aliases)
274
274
275 aliases.update({
275 aliases.update({
276 'ip': 'NotebookApp.ip',
276 'ip': 'NotebookApp.ip',
277 'port': 'NotebookApp.port',
277 'port': 'NotebookApp.port',
278 'port-retries': 'NotebookApp.port_retries',
278 'port-retries': 'NotebookApp.port_retries',
279 'transport': 'KernelManager.transport',
279 'transport': 'KernelManager.transport',
280 'keyfile': 'NotebookApp.keyfile',
280 'keyfile': 'NotebookApp.keyfile',
281 'certfile': 'NotebookApp.certfile',
281 'certfile': 'NotebookApp.certfile',
282 'notebook-dir': 'NotebookManager.notebook_dir',
282 'notebook-dir': 'NotebookManager.notebook_dir',
283 'browser': 'NotebookApp.browser',
283 'browser': 'NotebookApp.browser',
284 })
284 })
285
285
286 # remove ipkernel flags that are singletons, and don't make sense in
286 # remove ipkernel flags that are singletons, and don't make sense in
287 # multi-kernel evironment:
287 # multi-kernel evironment:
288 aliases.pop('f', None)
288 aliases.pop('f', None)
289
289
290 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
290 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
291 u'notebook-dir', u'profile', u'profile-dir']
291 u'notebook-dir', u'profile', u'profile-dir']
292
292
293 #-----------------------------------------------------------------------------
293 #-----------------------------------------------------------------------------
294 # NotebookApp
294 # NotebookApp
295 #-----------------------------------------------------------------------------
295 #-----------------------------------------------------------------------------
296
296
297 class NotebookApp(BaseIPythonApplication):
297 class NotebookApp(BaseIPythonApplication):
298
298
299 name = 'ipython-notebook'
299 name = 'ipython-notebook'
300
300
301 description = """
301 description = """
302 The IPython HTML Notebook.
302 The IPython HTML Notebook.
303
303
304 This launches a Tornado based HTML Notebook Server that serves up an
304 This launches a Tornado based HTML Notebook Server that serves up an
305 HTML5/Javascript Notebook client.
305 HTML5/Javascript Notebook client.
306 """
306 """
307 examples = _examples
307 examples = _examples
308
308
309 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
309 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
310 FileNotebookManager]
310 FileNotebookManager]
311 flags = Dict(flags)
311 flags = Dict(flags)
312 aliases = Dict(aliases)
312 aliases = Dict(aliases)
313
313
314 subcommands = dict(
314 subcommands = dict(
315 list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
315 list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
316 )
316 )
317
317
318 kernel_argv = List(Unicode)
318 kernel_argv = List(Unicode)
319
319
320 def _log_level_default(self):
320 def _log_level_default(self):
321 return logging.INFO
321 return logging.INFO
322
322
323 def _log_format_default(self):
323 def _log_format_default(self):
324 """override default log format to include time"""
324 """override default log format to include time"""
325 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
325 return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s"
326
326
327 # create requested profiles by default, if they don't exist:
327 # create requested profiles by default, if they don't exist:
328 auto_create = Bool(True)
328 auto_create = Bool(True)
329
329
330 # file to be opened in the notebook server
330 # file to be opened in the notebook server
331 file_to_run = Unicode('')
331 file_to_run = Unicode('')
332
332
333 # Network related information.
333 # Network related information.
334
334
335 ip = Unicode(config=True,
335 ip = Unicode(config=True,
336 help="The IP address the notebook server will listen on."
336 help="The IP address the notebook server will listen on."
337 )
337 )
338 def _ip_default(self):
338 def _ip_default(self):
339 return localhost()
339 return localhost()
340
340
341 def _ip_changed(self, name, old, new):
341 def _ip_changed(self, name, old, new):
342 if new == u'*': self.ip = u''
342 if new == u'*': self.ip = u''
343
343
344 port = Integer(8888, config=True,
344 port = Integer(8888, config=True,
345 help="The port the notebook server will listen on."
345 help="The port the notebook server will listen on."
346 )
346 )
347 port_retries = Integer(50, config=True,
347 port_retries = Integer(50, config=True,
348 help="The number of additional ports to try if the specified port is not available."
348 help="The number of additional ports to try if the specified port is not available."
349 )
349 )
350
350
351 certfile = Unicode(u'', config=True,
351 certfile = Unicode(u'', config=True,
352 help="""The full path to an SSL/TLS certificate file."""
352 help="""The full path to an SSL/TLS certificate file."""
353 )
353 )
354
354
355 keyfile = Unicode(u'', config=True,
355 keyfile = Unicode(u'', config=True,
356 help="""The full path to a private key file for usage with SSL/TLS."""
356 help="""The full path to a private key file for usage with SSL/TLS."""
357 )
357 )
358
358
359 cookie_secret = Bytes(b'', config=True,
359 cookie_secret = Bytes(b'', config=True,
360 help="""The random bytes used to secure cookies.
360 help="""The random bytes used to secure cookies.
361 By default this is a new random number every time you start the Notebook.
361 By default this is a new random number every time you start the Notebook.
362 Set it to a value in a config file to enable logins to persist across server sessions.
362 Set it to a value in a config file to enable logins to persist across server sessions.
363
363
364 Note: Cookie secrets should be kept private, do not share config files with
364 Note: Cookie secrets should be kept private, do not share config files with
365 cookie_secret stored in plaintext (you can read the value from a file).
365 cookie_secret stored in plaintext (you can read the value from a file).
366 """
366 """
367 )
367 )
368 def _cookie_secret_default(self):
368 def _cookie_secret_default(self):
369 return os.urandom(1024)
369 return os.urandom(1024)
370
370
371 password = Unicode(u'', config=True,
371 password = Unicode(u'', config=True,
372 help="""Hashed password to use for web authentication.
372 help="""Hashed password to use for web authentication.
373
373
374 To generate, type in a python/IPython shell:
374 To generate, type in a python/IPython shell:
375
375
376 from IPython.lib import passwd; passwd()
376 from IPython.lib import passwd; passwd()
377
377
378 The string should be of the form type:salt:hashed-password.
378 The string should be of the form type:salt:hashed-password.
379 """
379 """
380 )
380 )
381
381
382 open_browser = Bool(True, config=True,
382 open_browser = Bool(True, config=True,
383 help="""Whether to open in a browser after starting.
383 help="""Whether to open in a browser after starting.
384 The specific browser used is platform dependent and
384 The specific browser used is platform dependent and
385 determined by the python standard library `webbrowser`
385 determined by the python standard library `webbrowser`
386 module, unless it is overridden using the --browser
386 module, unless it is overridden using the --browser
387 (NotebookApp.browser) configuration option.
387 (NotebookApp.browser) configuration option.
388 """)
388 """)
389
389
390 browser = Unicode(u'', config=True,
390 browser = Unicode(u'', config=True,
391 help="""Specify what command to use to invoke a web
391 help="""Specify what command to use to invoke a web
392 browser when opening the notebook. If not specified, the
392 browser when opening the notebook. If not specified, the
393 default browser will be determined by the `webbrowser`
393 default browser will be determined by the `webbrowser`
394 standard library module, which allows setting of the
394 standard library module, which allows setting of the
395 BROWSER environment variable to override it.
395 BROWSER environment variable to override it.
396 """)
396 """)
397
397
398 webapp_settings = Dict(config=True,
398 webapp_settings = Dict(config=True,
399 help="Supply overrides for the tornado.web.Application that the "
399 help="Supply overrides for the tornado.web.Application that the "
400 "IPython notebook uses.")
400 "IPython notebook uses.")
401
401
402 enable_mathjax = Bool(True, config=True,
402 enable_mathjax = Bool(True, config=True,
403 help="""Whether to enable MathJax for typesetting math/TeX
403 help="""Whether to enable MathJax for typesetting math/TeX
404
404
405 MathJax is the javascript library IPython uses to render math/LaTeX. It is
405 MathJax is the javascript library IPython uses to render math/LaTeX. It is
406 very large, so you may want to disable it if you have a slow internet
406 very large, so you may want to disable it if you have a slow internet
407 connection, or for offline use of the notebook.
407 connection, or for offline use of the notebook.
408
408
409 When disabled, equations etc. will appear as their untransformed TeX source.
409 When disabled, equations etc. will appear as their untransformed TeX source.
410 """
410 """
411 )
411 )
412 def _enable_mathjax_changed(self, name, old, new):
412 def _enable_mathjax_changed(self, name, old, new):
413 """set mathjax url to empty if mathjax is disabled"""
413 """set mathjax url to empty if mathjax is disabled"""
414 if not new:
414 if not new:
415 self.mathjax_url = u''
415 self.mathjax_url = u''
416
416
417 base_project_url = Unicode('/', config=True,
417 base_url = Unicode('/', config=True,
418 help='''The base URL for the notebook server.
418 help='''The base URL for the notebook server.
419
419
420 Leading and trailing slashes can be omitted,
420 Leading and trailing slashes can be omitted,
421 and will automatically be added.
421 and will automatically be added.
422 ''')
422 ''')
423 def _base_project_url_changed(self, name, old, new):
423 def _base_url_changed(self, name, old, new):
424 if not new.startswith('/'):
424 if not new.startswith('/'):
425 self.base_project_url = '/'+new
425 self.base_url = '/'+new
426 elif not new.endswith('/'):
426 elif not new.endswith('/'):
427 self.base_project_url = new+'/'
427 self.base_url = new+'/'
428
429 base_project_url = Unicode('/', config=True, help="""DEPRECATED use base_url""")
430 def _base_project_url_changed(self, name, old, new):
431 self.log.warn("base_project_url is deprecated, use base_url")
432 self.base_url = new
428
433
429 base_kernel_url = Unicode('/', config=True,
434 base_kernel_url = Unicode('/', config=True,
430 help='''The base URL for the kernel server
435 help='''The base URL for the kernel server
431
436
432 Leading and trailing slashes can be omitted,
437 Leading and trailing slashes can be omitted,
433 and will automatically be added.
438 and will automatically be added.
434 ''')
439 ''')
435 def _base_kernel_url_changed(self, name, old, new):
440 def _base_kernel_url_changed(self, name, old, new):
436 if not new.startswith('/'):
441 if not new.startswith('/'):
437 self.base_kernel_url = '/'+new
442 self.base_kernel_url = '/'+new
438 elif not new.endswith('/'):
443 elif not new.endswith('/'):
439 self.base_kernel_url = new+'/'
444 self.base_kernel_url = new+'/'
440
445
441 websocket_url = Unicode("", config=True,
446 websocket_url = Unicode("", config=True,
442 help="""The base URL for the websocket server,
447 help="""The base URL for the websocket server,
443 if it differs from the HTTP server (hint: it almost certainly doesn't).
448 if it differs from the HTTP server (hint: it almost certainly doesn't).
444
449
445 Should be in the form of an HTTP origin: ws[s]://hostname[:port]
450 Should be in the form of an HTTP origin: ws[s]://hostname[:port]
446 """
451 """
447 )
452 )
448
453
449 extra_static_paths = List(Unicode, config=True,
454 extra_static_paths = List(Unicode, config=True,
450 help="""Extra paths to search for serving static files.
455 help="""Extra paths to search for serving static files.
451
456
452 This allows adding javascript/css to be available from the notebook server machine,
457 This allows adding javascript/css to be available from the notebook server machine,
453 or overriding individual files in the IPython"""
458 or overriding individual files in the IPython"""
454 )
459 )
455 def _extra_static_paths_default(self):
460 def _extra_static_paths_default(self):
456 return [os.path.join(self.profile_dir.location, 'static')]
461 return [os.path.join(self.profile_dir.location, 'static')]
457
462
458 @property
463 @property
459 def static_file_path(self):
464 def static_file_path(self):
460 """return extra paths + the default location"""
465 """return extra paths + the default location"""
461 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
466 return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
462
467
463 nbextensions_path = List(Unicode, config=True,
468 nbextensions_path = List(Unicode, config=True,
464 help="""paths for Javascript extensions. By default, this is just IPYTHONDIR/nbextensions"""
469 help="""paths for Javascript extensions. By default, this is just IPYTHONDIR/nbextensions"""
465 )
470 )
466 def _nbextensions_path_default(self):
471 def _nbextensions_path_default(self):
467 return [os.path.join(get_ipython_dir(), 'nbextensions')]
472 return [os.path.join(get_ipython_dir(), 'nbextensions')]
468
473
469 mathjax_url = Unicode("", config=True,
474 mathjax_url = Unicode("", config=True,
470 help="""The url for MathJax.js."""
475 help="""The url for MathJax.js."""
471 )
476 )
472 def _mathjax_url_default(self):
477 def _mathjax_url_default(self):
473 if not self.enable_mathjax:
478 if not self.enable_mathjax:
474 return u''
479 return u''
475 static_url_prefix = self.webapp_settings.get("static_url_prefix",
480 static_url_prefix = self.webapp_settings.get("static_url_prefix",
476 url_path_join(self.base_project_url, "static")
481 url_path_join(self.base_url, "static")
477 )
482 )
478
483
479 # try local mathjax, either in nbextensions/mathjax or static/mathjax
484 # try local mathjax, either in nbextensions/mathjax or static/mathjax
480 for (url_prefix, search_path) in [
485 for (url_prefix, search_path) in [
481 (url_path_join(self.base_project_url, "nbextensions"), self.nbextensions_path),
486 (url_path_join(self.base_url, "nbextensions"), self.nbextensions_path),
482 (static_url_prefix, self.static_file_path),
487 (static_url_prefix, self.static_file_path),
483 ]:
488 ]:
484 self.log.debug("searching for local mathjax in %s", search_path)
489 self.log.debug("searching for local mathjax in %s", search_path)
485 try:
490 try:
486 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
491 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), search_path)
487 except IOError:
492 except IOError:
488 continue
493 continue
489 else:
494 else:
490 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
495 url = url_path_join(url_prefix, u"mathjax/MathJax.js")
491 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
496 self.log.info("Serving local MathJax from %s at %s", mathjax, url)
492 return url
497 return url
493
498
494 # no local mathjax, serve from CDN
499 # no local mathjax, serve from CDN
495 if self.certfile:
500 if self.certfile:
496 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
501 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
497 host = u"https://c328740.ssl.cf1.rackcdn.com"
502 host = u"https://c328740.ssl.cf1.rackcdn.com"
498 else:
503 else:
499 host = u"http://cdn.mathjax.org"
504 host = u"http://cdn.mathjax.org"
500
505
501 url = host + u"/mathjax/latest/MathJax.js"
506 url = host + u"/mathjax/latest/MathJax.js"
502 self.log.info("Using MathJax from CDN: %s", url)
507 self.log.info("Using MathJax from CDN: %s", url)
503 return url
508 return url
504
509
505 def _mathjax_url_changed(self, name, old, new):
510 def _mathjax_url_changed(self, name, old, new):
506 if new and not self.enable_mathjax:
511 if new and not self.enable_mathjax:
507 # enable_mathjax=False overrides mathjax_url
512 # enable_mathjax=False overrides mathjax_url
508 self.mathjax_url = u''
513 self.mathjax_url = u''
509 else:
514 else:
510 self.log.info("Using MathJax: %s", new)
515 self.log.info("Using MathJax: %s", new)
511
516
512 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
517 notebook_manager_class = DottedObjectName('IPython.html.services.notebooks.filenbmanager.FileNotebookManager',
513 config=True,
518 config=True,
514 help='The notebook manager class to use.')
519 help='The notebook manager class to use.')
515
520
516 trust_xheaders = Bool(False, config=True,
521 trust_xheaders = Bool(False, config=True,
517 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
522 help=("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers"
518 "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")
523 "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")
519 )
524 )
520
525
521 info_file = Unicode()
526 info_file = Unicode()
522
527
523 def _info_file_default(self):
528 def _info_file_default(self):
524 info_file = "nbserver-%s.json"%os.getpid()
529 info_file = "nbserver-%s.json"%os.getpid()
525 return os.path.join(self.profile_dir.security_dir, info_file)
530 return os.path.join(self.profile_dir.security_dir, info_file)
526
531
527 def parse_command_line(self, argv=None):
532 def parse_command_line(self, argv=None):
528 super(NotebookApp, self).parse_command_line(argv)
533 super(NotebookApp, self).parse_command_line(argv)
529
534
530 if self.extra_args:
535 if self.extra_args:
531 arg0 = self.extra_args[0]
536 arg0 = self.extra_args[0]
532 f = os.path.abspath(arg0)
537 f = os.path.abspath(arg0)
533 self.argv.remove(arg0)
538 self.argv.remove(arg0)
534 if not os.path.exists(f):
539 if not os.path.exists(f):
535 self.log.critical("No such file or directory: %s", f)
540 self.log.critical("No such file or directory: %s", f)
536 self.exit(1)
541 self.exit(1)
537 if os.path.isdir(f):
542 if os.path.isdir(f):
538 self.config.FileNotebookManager.notebook_dir = f
543 self.config.FileNotebookManager.notebook_dir = f
539 elif os.path.isfile(f):
544 elif os.path.isfile(f):
540 self.file_to_run = f
545 self.file_to_run = f
541
546
542 def init_kernel_argv(self):
547 def init_kernel_argv(self):
543 """construct the kernel arguments"""
548 """construct the kernel arguments"""
544 # Scrub frontend-specific flags
549 # Scrub frontend-specific flags
545 self.kernel_argv = swallow_argv(self.argv, notebook_aliases, notebook_flags)
550 self.kernel_argv = swallow_argv(self.argv, notebook_aliases, notebook_flags)
546 if any(arg.startswith(u'--pylab') for arg in self.kernel_argv):
551 if any(arg.startswith(u'--pylab') for arg in self.kernel_argv):
547 self.log.warn('\n '.join([
552 self.log.warn('\n '.join([
548 "Starting all kernels in pylab mode is not recommended,",
553 "Starting all kernels in pylab mode is not recommended,",
549 "and will be disabled in a future release.",
554 "and will be disabled in a future release.",
550 "Please use the %matplotlib magic to enable matplotlib instead.",
555 "Please use the %matplotlib magic to enable matplotlib instead.",
551 "pylab implies many imports, which can have confusing side effects",
556 "pylab implies many imports, which can have confusing side effects",
552 "and harm the reproducibility of your notebooks.",
557 "and harm the reproducibility of your notebooks.",
553 ]))
558 ]))
554 # Kernel should inherit default config file from frontend
559 # Kernel should inherit default config file from frontend
555 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
560 self.kernel_argv.append("--IPKernelApp.parent_appname='%s'" % self.name)
556 # Kernel should get *absolute* path to profile directory
561 # Kernel should get *absolute* path to profile directory
557 self.kernel_argv.extend(["--profile-dir", self.profile_dir.location])
562 self.kernel_argv.extend(["--profile-dir", self.profile_dir.location])
558
563
559 def init_configurables(self):
564 def init_configurables(self):
560 # force Session default to be secure
565 # force Session default to be secure
561 default_secure(self.config)
566 default_secure(self.config)
562 self.kernel_manager = MappingKernelManager(
567 self.kernel_manager = MappingKernelManager(
563 parent=self, log=self.log, kernel_argv=self.kernel_argv,
568 parent=self, log=self.log, kernel_argv=self.kernel_argv,
564 connection_dir = self.profile_dir.security_dir,
569 connection_dir = self.profile_dir.security_dir,
565 )
570 )
566 kls = import_item(self.notebook_manager_class)
571 kls = import_item(self.notebook_manager_class)
567 self.notebook_manager = kls(parent=self, log=self.log)
572 self.notebook_manager = kls(parent=self, log=self.log)
568 self.session_manager = SessionManager(parent=self, log=self.log)
573 self.session_manager = SessionManager(parent=self, log=self.log)
569 self.cluster_manager = ClusterManager(parent=self, log=self.log)
574 self.cluster_manager = ClusterManager(parent=self, log=self.log)
570 self.cluster_manager.update_profiles()
575 self.cluster_manager.update_profiles()
571
576
572 def init_logging(self):
577 def init_logging(self):
573 # This prevents double log messages because tornado use a root logger that
578 # This prevents double log messages because tornado use a root logger that
574 # self.log is a child of. The logging module dipatches log messages to a log
579 # self.log is a child of. The logging module dipatches log messages to a log
575 # and all of its ancenstors until propagate is set to False.
580 # and all of its ancenstors until propagate is set to False.
576 self.log.propagate = False
581 self.log.propagate = False
577
582
578 # hook up tornado 3's loggers to our app handlers
583 # hook up tornado 3's loggers to our app handlers
579 for name in ('access', 'application', 'general'):
584 for name in ('access', 'application', 'general'):
580 logger = logging.getLogger('tornado.%s' % name)
585 logger = logging.getLogger('tornado.%s' % name)
581 logger.parent = self.log
586 logger.parent = self.log
582 logger.setLevel(self.log.level)
587 logger.setLevel(self.log.level)
583
588
584 def init_webapp(self):
589 def init_webapp(self):
585 """initialize tornado webapp and httpserver"""
590 """initialize tornado webapp and httpserver"""
586 self.web_app = NotebookWebApplication(
591 self.web_app = NotebookWebApplication(
587 self, self.kernel_manager, self.notebook_manager,
592 self, self.kernel_manager, self.notebook_manager,
588 self.cluster_manager, self.session_manager,
593 self.cluster_manager, self.session_manager,
589 self.log, self.base_project_url, self.webapp_settings
594 self.log, self.base_url, self.webapp_settings
590 )
595 )
591 if self.certfile:
596 if self.certfile:
592 ssl_options = dict(certfile=self.certfile)
597 ssl_options = dict(certfile=self.certfile)
593 if self.keyfile:
598 if self.keyfile:
594 ssl_options['keyfile'] = self.keyfile
599 ssl_options['keyfile'] = self.keyfile
595 else:
600 else:
596 ssl_options = None
601 ssl_options = None
597 self.web_app.password = self.password
602 self.web_app.password = self.password
598 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
603 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options,
599 xheaders=self.trust_xheaders)
604 xheaders=self.trust_xheaders)
600 if not self.ip:
605 if not self.ip:
601 warning = "WARNING: The notebook server is listening on all IP addresses"
606 warning = "WARNING: The notebook server is listening on all IP addresses"
602 if ssl_options is None:
607 if ssl_options is None:
603 self.log.critical(warning + " and not using encryption. This "
608 self.log.critical(warning + " and not using encryption. This "
604 "is not recommended.")
609 "is not recommended.")
605 if not self.password:
610 if not self.password:
606 self.log.critical(warning + " and not using authentication. "
611 self.log.critical(warning + " and not using authentication. "
607 "This is highly insecure and not recommended.")
612 "This is highly insecure and not recommended.")
608 success = None
613 success = None
609 for port in random_ports(self.port, self.port_retries+1):
614 for port in random_ports(self.port, self.port_retries+1):
610 try:
615 try:
611 self.http_server.listen(port, self.ip)
616 self.http_server.listen(port, self.ip)
612 except socket.error as e:
617 except socket.error as e:
613 if e.errno == errno.EADDRINUSE:
618 if e.errno == errno.EADDRINUSE:
614 self.log.info('The port %i is already in use, trying another random port.' % port)
619 self.log.info('The port %i is already in use, trying another random port.' % port)
615 continue
620 continue
616 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
621 elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)):
617 self.log.warn("Permission to listen on port %i denied" % port)
622 self.log.warn("Permission to listen on port %i denied" % port)
618 continue
623 continue
619 else:
624 else:
620 raise
625 raise
621 else:
626 else:
622 self.port = port
627 self.port = port
623 success = True
628 success = True
624 break
629 break
625 if not success:
630 if not success:
626 self.log.critical('ERROR: the notebook server could not be started because '
631 self.log.critical('ERROR: the notebook server could not be started because '
627 'no available port could be found.')
632 'no available port could be found.')
628 self.exit(1)
633 self.exit(1)
629
634
630 @property
635 @property
631 def display_url(self):
636 def display_url(self):
632 ip = self.ip if self.ip else '[all ip addresses on your system]'
637 ip = self.ip if self.ip else '[all ip addresses on your system]'
633 return self._url(ip)
638 return self._url(ip)
634
639
635 @property
640 @property
636 def connection_url(self):
641 def connection_url(self):
637 ip = self.ip if self.ip else localhost()
642 ip = self.ip if self.ip else localhost()
638 return self._url(ip)
643 return self._url(ip)
639
644
640 def _url(self, ip):
645 def _url(self, ip):
641 proto = 'https' if self.certfile else 'http'
646 proto = 'https' if self.certfile else 'http'
642 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_project_url)
647 return "%s://%s:%i%s" % (proto, ip, self.port, self.base_url)
643
648
644 def init_signal(self):
649 def init_signal(self):
645 if not sys.platform.startswith('win'):
650 if not sys.platform.startswith('win'):
646 signal.signal(signal.SIGINT, self._handle_sigint)
651 signal.signal(signal.SIGINT, self._handle_sigint)
647 signal.signal(signal.SIGTERM, self._signal_stop)
652 signal.signal(signal.SIGTERM, self._signal_stop)
648 if hasattr(signal, 'SIGUSR1'):
653 if hasattr(signal, 'SIGUSR1'):
649 # Windows doesn't support SIGUSR1
654 # Windows doesn't support SIGUSR1
650 signal.signal(signal.SIGUSR1, self._signal_info)
655 signal.signal(signal.SIGUSR1, self._signal_info)
651 if hasattr(signal, 'SIGINFO'):
656 if hasattr(signal, 'SIGINFO'):
652 # only on BSD-based systems
657 # only on BSD-based systems
653 signal.signal(signal.SIGINFO, self._signal_info)
658 signal.signal(signal.SIGINFO, self._signal_info)
654
659
655 def _handle_sigint(self, sig, frame):
660 def _handle_sigint(self, sig, frame):
656 """SIGINT handler spawns confirmation dialog"""
661 """SIGINT handler spawns confirmation dialog"""
657 # register more forceful signal handler for ^C^C case
662 # register more forceful signal handler for ^C^C case
658 signal.signal(signal.SIGINT, self._signal_stop)
663 signal.signal(signal.SIGINT, self._signal_stop)
659 # request confirmation dialog in bg thread, to avoid
664 # request confirmation dialog in bg thread, to avoid
660 # blocking the App
665 # blocking the App
661 thread = threading.Thread(target=self._confirm_exit)
666 thread = threading.Thread(target=self._confirm_exit)
662 thread.daemon = True
667 thread.daemon = True
663 thread.start()
668 thread.start()
664
669
665 def _restore_sigint_handler(self):
670 def _restore_sigint_handler(self):
666 """callback for restoring original SIGINT handler"""
671 """callback for restoring original SIGINT handler"""
667 signal.signal(signal.SIGINT, self._handle_sigint)
672 signal.signal(signal.SIGINT, self._handle_sigint)
668
673
669 def _confirm_exit(self):
674 def _confirm_exit(self):
670 """confirm shutdown on ^C
675 """confirm shutdown on ^C
671
676
672 A second ^C, or answering 'y' within 5s will cause shutdown,
677 A second ^C, or answering 'y' within 5s will cause shutdown,
673 otherwise original SIGINT handler will be restored.
678 otherwise original SIGINT handler will be restored.
674
679
675 This doesn't work on Windows.
680 This doesn't work on Windows.
676 """
681 """
677 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
682 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
678 time.sleep(0.1)
683 time.sleep(0.1)
679 info = self.log.info
684 info = self.log.info
680 info('interrupted')
685 info('interrupted')
681 print(self.notebook_info())
686 print(self.notebook_info())
682 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
687 sys.stdout.write("Shutdown this notebook server (y/[n])? ")
683 sys.stdout.flush()
688 sys.stdout.flush()
684 r,w,x = select.select([sys.stdin], [], [], 5)
689 r,w,x = select.select([sys.stdin], [], [], 5)
685 if r:
690 if r:
686 line = sys.stdin.readline()
691 line = sys.stdin.readline()
687 if line.lower().startswith('y'):
692 if line.lower().startswith('y'):
688 self.log.critical("Shutdown confirmed")
693 self.log.critical("Shutdown confirmed")
689 ioloop.IOLoop.instance().stop()
694 ioloop.IOLoop.instance().stop()
690 return
695 return
691 else:
696 else:
692 print("No answer for 5s:", end=' ')
697 print("No answer for 5s:", end=' ')
693 print("resuming operation...")
698 print("resuming operation...")
694 # no answer, or answer is no:
699 # no answer, or answer is no:
695 # set it back to original SIGINT handler
700 # set it back to original SIGINT handler
696 # use IOLoop.add_callback because signal.signal must be called
701 # use IOLoop.add_callback because signal.signal must be called
697 # from main thread
702 # from main thread
698 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
703 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
699
704
700 def _signal_stop(self, sig, frame):
705 def _signal_stop(self, sig, frame):
701 self.log.critical("received signal %s, stopping", sig)
706 self.log.critical("received signal %s, stopping", sig)
702 ioloop.IOLoop.instance().stop()
707 ioloop.IOLoop.instance().stop()
703
708
704 def _signal_info(self, sig, frame):
709 def _signal_info(self, sig, frame):
705 print(self.notebook_info())
710 print(self.notebook_info())
706
711
707 def init_components(self):
712 def init_components(self):
708 """Check the components submodule, and warn if it's unclean"""
713 """Check the components submodule, and warn if it's unclean"""
709 status = submodule.check_submodule_status()
714 status = submodule.check_submodule_status()
710 if status == 'missing':
715 if status == 'missing':
711 self.log.warn("components submodule missing, running `git submodule update`")
716 self.log.warn("components submodule missing, running `git submodule update`")
712 submodule.update_submodules(submodule.ipython_parent())
717 submodule.update_submodules(submodule.ipython_parent())
713 elif status == 'unclean':
718 elif status == 'unclean':
714 self.log.warn("components submodule unclean, you may see 404s on static/components")
719 self.log.warn("components submodule unclean, you may see 404s on static/components")
715 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
720 self.log.warn("run `setup.py submodule` or `git submodule update` to update")
716
721
717 @catch_config_error
722 @catch_config_error
718 def initialize(self, argv=None):
723 def initialize(self, argv=None):
719 super(NotebookApp, self).initialize(argv)
724 super(NotebookApp, self).initialize(argv)
720 self.init_logging()
725 self.init_logging()
721 self.init_kernel_argv()
726 self.init_kernel_argv()
722 self.init_configurables()
727 self.init_configurables()
723 self.init_components()
728 self.init_components()
724 self.init_webapp()
729 self.init_webapp()
725 self.init_signal()
730 self.init_signal()
726
731
727 def cleanup_kernels(self):
732 def cleanup_kernels(self):
728 """Shutdown all kernels.
733 """Shutdown all kernels.
729
734
730 The kernels will shutdown themselves when this process no longer exists,
735 The kernels will shutdown themselves when this process no longer exists,
731 but explicit shutdown allows the KernelManagers to cleanup the connection files.
736 but explicit shutdown allows the KernelManagers to cleanup the connection files.
732 """
737 """
733 self.log.info('Shutting down kernels')
738 self.log.info('Shutting down kernels')
734 self.kernel_manager.shutdown_all()
739 self.kernel_manager.shutdown_all()
735
740
736 def notebook_info(self):
741 def notebook_info(self):
737 "Return the current working directory and the server url information"
742 "Return the current working directory and the server url information"
738 info = self.notebook_manager.info_string() + "\n"
743 info = self.notebook_manager.info_string() + "\n"
739 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
744 info += "%d active kernels \n" % len(self.kernel_manager._kernels)
740 return info + "The IPython Notebook is running at: %s" % self.display_url
745 return info + "The IPython Notebook is running at: %s" % self.display_url
741
746
742 def server_info(self):
747 def server_info(self):
743 """Return a JSONable dict of information about this server."""
748 """Return a JSONable dict of information about this server."""
744 return {'url': self.connection_url,
749 return {'url': self.connection_url,
745 'hostname': self.ip if self.ip else 'localhost',
750 'hostname': self.ip if self.ip else 'localhost',
746 'port': self.port,
751 'port': self.port,
747 'secure': bool(self.certfile),
752 'secure': bool(self.certfile),
748 'base_project_url': self.base_project_url,
753 'base_url': self.base_url,
749 'notebook_dir': os.path.abspath(self.notebook_manager.notebook_dir),
754 'notebook_dir': os.path.abspath(self.notebook_manager.notebook_dir),
750 }
755 }
751
756
752 def write_server_info_file(self):
757 def write_server_info_file(self):
753 """Write the result of server_info() to the JSON file info_file."""
758 """Write the result of server_info() to the JSON file info_file."""
754 with open(self.info_file, 'w') as f:
759 with open(self.info_file, 'w') as f:
755 json.dump(self.server_info(), f, indent=2)
760 json.dump(self.server_info(), f, indent=2)
756
761
757 def remove_server_info_file(self):
762 def remove_server_info_file(self):
758 """Remove the nbserver-<pid>.json file created for this server.
763 """Remove the nbserver-<pid>.json file created for this server.
759
764
760 Ignores the error raised when the file has already been removed.
765 Ignores the error raised when the file has already been removed.
761 """
766 """
762 try:
767 try:
763 os.unlink(self.info_file)
768 os.unlink(self.info_file)
764 except OSError as e:
769 except OSError as e:
765 if e.errno != errno.ENOENT:
770 if e.errno != errno.ENOENT:
766 raise
771 raise
767
772
768 def start(self):
773 def start(self):
769 """ Start the IPython Notebook server app, after initialization
774 """ Start the IPython Notebook server app, after initialization
770
775
771 This method takes no arguments so all configuration and initialization
776 This method takes no arguments so all configuration and initialization
772 must be done prior to calling this method."""
777 must be done prior to calling this method."""
773 if self.subapp is not None:
778 if self.subapp is not None:
774 return self.subapp.start()
779 return self.subapp.start()
775
780
776 info = self.log.info
781 info = self.log.info
777 for line in self.notebook_info().split("\n"):
782 for line in self.notebook_info().split("\n"):
778 info(line)
783 info(line)
779 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
784 info("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")
780
785
781 self.write_server_info_file()
786 self.write_server_info_file()
782
787
783 if self.open_browser or self.file_to_run:
788 if self.open_browser or self.file_to_run:
784 try:
789 try:
785 browser = webbrowser.get(self.browser or None)
790 browser = webbrowser.get(self.browser or None)
786 except webbrowser.Error as e:
791 except webbrowser.Error as e:
787 self.log.warn('No web browser found: %s.' % e)
792 self.log.warn('No web browser found: %s.' % e)
788 browser = None
793 browser = None
789
794
790 f = self.file_to_run
795 f = self.file_to_run
791 if f:
796 if f:
792 nbdir = os.path.abspath(self.notebook_manager.notebook_dir)
797 nbdir = os.path.abspath(self.notebook_manager.notebook_dir)
793 if f.startswith(nbdir):
798 if f.startswith(nbdir):
794 f = f[len(nbdir):]
799 f = f[len(nbdir):]
795 else:
800 else:
796 self.log.warn(
801 self.log.warn(
797 "Probably won't be able to open notebook %s "
802 "Probably won't be able to open notebook %s "
798 "because it is not in notebook_dir %s",
803 "because it is not in notebook_dir %s",
799 f, nbdir,
804 f, nbdir,
800 )
805 )
801
806
802 if os.path.isfile(self.file_to_run):
807 if os.path.isfile(self.file_to_run):
803 url = url_path_join('notebooks', f)
808 url = url_path_join('notebooks', f)
804 else:
809 else:
805 url = url_path_join('tree', f)
810 url = url_path_join('tree', f)
806 if browser:
811 if browser:
807 b = lambda : browser.open("%s%s" % (self.connection_url, url),
812 b = lambda : browser.open("%s%s" % (self.connection_url, url),
808 new=2)
813 new=2)
809 threading.Thread(target=b).start()
814 threading.Thread(target=b).start()
810 try:
815 try:
811 ioloop.IOLoop.instance().start()
816 ioloop.IOLoop.instance().start()
812 except KeyboardInterrupt:
817 except KeyboardInterrupt:
813 info("Interrupted...")
818 info("Interrupted...")
814 finally:
819 finally:
815 self.cleanup_kernels()
820 self.cleanup_kernels()
816 self.remove_server_info_file()
821 self.remove_server_info_file()
817
822
818
823
819 def list_running_servers(profile='default'):
824 def list_running_servers(profile='default'):
820 """Iterate over the server info files of running notebook servers.
825 """Iterate over the server info files of running notebook servers.
821
826
822 Given a profile name, find nbserver-* files in the security directory of
827 Given a profile name, find nbserver-* files in the security directory of
823 that profile, and yield dicts of their information, each one pertaining to
828 that profile, and yield dicts of their information, each one pertaining to
824 a currently running notebook server instance.
829 a currently running notebook server instance.
825 """
830 """
826 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile)
831 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), name=profile)
827 for file in os.listdir(pd.security_dir):
832 for file in os.listdir(pd.security_dir):
828 if file.startswith('nbserver-'):
833 if file.startswith('nbserver-'):
829 with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f:
834 with io.open(os.path.join(pd.security_dir, file), encoding='utf-8') as f:
830 yield json.load(f)
835 yield json.load(f)
831
836
832 #-----------------------------------------------------------------------------
837 #-----------------------------------------------------------------------------
833 # Main entry point
838 # Main entry point
834 #-----------------------------------------------------------------------------
839 #-----------------------------------------------------------------------------
835
840
836 launch_new_instance = NotebookApp.launch_instance
841 launch_new_instance = NotebookApp.launch_instance
837
842
@@ -1,290 +1,290 b''
1 """Tornado handlers for the notebooks web service.
1 """Tornado handlers for the notebooks web service.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 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 json
19 import json
20
20
21 from tornado import web
21 from tornado import web
22
22
23 from IPython.html.utils import url_path_join, url_escape
23 from IPython.html.utils import url_path_join, url_escape
24 from IPython.utils.jsonutil import date_default
24 from IPython.utils.jsonutil import date_default
25
25
26 from IPython.html.base.handlers import (IPythonHandler, json_errors,
26 from IPython.html.base.handlers import (IPythonHandler, json_errors,
27 notebook_path_regex, path_regex,
27 notebook_path_regex, path_regex,
28 notebook_name_regex)
28 notebook_name_regex)
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Notebook web service handlers
31 # Notebook web service handlers
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34
34
35 class NotebookHandler(IPythonHandler):
35 class NotebookHandler(IPythonHandler):
36
36
37 SUPPORTED_METHODS = (u'GET', u'PUT', u'PATCH', u'POST', u'DELETE')
37 SUPPORTED_METHODS = (u'GET', u'PUT', u'PATCH', u'POST', u'DELETE')
38
38
39 def notebook_location(self, name, path=''):
39 def notebook_location(self, name, path=''):
40 """Return the full URL location of a notebook based.
40 """Return the full URL location of a notebook based.
41
41
42 Parameters
42 Parameters
43 ----------
43 ----------
44 name : unicode
44 name : unicode
45 The base name of the notebook, such as "foo.ipynb".
45 The base name of the notebook, such as "foo.ipynb".
46 path : unicode
46 path : unicode
47 The URL path of the notebook.
47 The URL path of the notebook.
48 """
48 """
49 return url_escape(url_path_join(
49 return url_escape(url_path_join(
50 self.base_project_url, 'api', 'notebooks', path, name
50 self.base_url, 'api', 'notebooks', path, name
51 ))
51 ))
52
52
53 def _finish_model(self, model, location=True):
53 def _finish_model(self, model, location=True):
54 """Finish a JSON request with a model, setting relevant headers, etc."""
54 """Finish a JSON request with a model, setting relevant headers, etc."""
55 if location:
55 if location:
56 location = self.notebook_location(model['name'], model['path'])
56 location = self.notebook_location(model['name'], model['path'])
57 self.set_header('Location', location)
57 self.set_header('Location', location)
58 self.set_header('Last-Modified', model['last_modified'])
58 self.set_header('Last-Modified', model['last_modified'])
59 self.finish(json.dumps(model, default=date_default))
59 self.finish(json.dumps(model, default=date_default))
60
60
61 @web.authenticated
61 @web.authenticated
62 @json_errors
62 @json_errors
63 def get(self, path='', name=None):
63 def get(self, path='', name=None):
64 """Return a Notebook or list of notebooks.
64 """Return a Notebook or list of notebooks.
65
65
66 * GET with path and no notebook name lists notebooks in a directory
66 * GET with path and no notebook name lists notebooks in a directory
67 * GET with path and notebook name returns notebook JSON
67 * GET with path and notebook name returns notebook JSON
68 """
68 """
69 nbm = self.notebook_manager
69 nbm = self.notebook_manager
70 # Check to see if a notebook name was given
70 # Check to see if a notebook name was given
71 if name is None:
71 if name is None:
72 # TODO: Remove this after we create the contents web service and directories are
72 # TODO: Remove this after we create the contents web service and directories are
73 # no longer listed by the notebook web service. This should only handle notebooks
73 # no longer listed by the notebook web service. This should only handle notebooks
74 # and not directories.
74 # and not directories.
75 dirs = nbm.list_dirs(path)
75 dirs = nbm.list_dirs(path)
76 notebooks = []
76 notebooks = []
77 index = []
77 index = []
78 for nb in nbm.list_notebooks(path):
78 for nb in nbm.list_notebooks(path):
79 if nb['name'].lower() == 'index.ipynb':
79 if nb['name'].lower() == 'index.ipynb':
80 index.append(nb)
80 index.append(nb)
81 else:
81 else:
82 notebooks.append(nb)
82 notebooks.append(nb)
83 notebooks = index + dirs + notebooks
83 notebooks = index + dirs + notebooks
84 self.finish(json.dumps(notebooks, default=date_default))
84 self.finish(json.dumps(notebooks, default=date_default))
85 return
85 return
86 # get and return notebook representation
86 # get and return notebook representation
87 model = nbm.get_notebook_model(name, path)
87 model = nbm.get_notebook_model(name, path)
88 self._finish_model(model, location=False)
88 self._finish_model(model, location=False)
89
89
90 @web.authenticated
90 @web.authenticated
91 @json_errors
91 @json_errors
92 def patch(self, path='', name=None):
92 def patch(self, path='', name=None):
93 """PATCH renames a notebook without re-uploading content."""
93 """PATCH renames a notebook without re-uploading content."""
94 nbm = self.notebook_manager
94 nbm = self.notebook_manager
95 if name is None:
95 if name is None:
96 raise web.HTTPError(400, u'Notebook name missing')
96 raise web.HTTPError(400, u'Notebook name missing')
97 model = self.get_json_body()
97 model = self.get_json_body()
98 if model is None:
98 if model is None:
99 raise web.HTTPError(400, u'JSON body missing')
99 raise web.HTTPError(400, u'JSON body missing')
100 model = nbm.update_notebook_model(model, name, path)
100 model = nbm.update_notebook_model(model, name, path)
101 self._finish_model(model)
101 self._finish_model(model)
102
102
103 def _copy_notebook(self, copy_from, path, copy_to=None):
103 def _copy_notebook(self, copy_from, path, copy_to=None):
104 """Copy a notebook in path, optionally specifying the new name.
104 """Copy a notebook in path, optionally specifying the new name.
105
105
106 Only support copying within the same directory.
106 Only support copying within the same directory.
107 """
107 """
108 self.log.info(u"Copying notebook from %s/%s to %s/%s",
108 self.log.info(u"Copying notebook from %s/%s to %s/%s",
109 path, copy_from,
109 path, copy_from,
110 path, copy_to or '',
110 path, copy_to or '',
111 )
111 )
112 model = self.notebook_manager.copy_notebook(copy_from, copy_to, path)
112 model = self.notebook_manager.copy_notebook(copy_from, copy_to, path)
113 self.set_status(201)
113 self.set_status(201)
114 self._finish_model(model)
114 self._finish_model(model)
115
115
116 def _upload_notebook(self, model, path, name=None):
116 def _upload_notebook(self, model, path, name=None):
117 """Upload a notebook
117 """Upload a notebook
118
118
119 If name specified, create it in path/name.
119 If name specified, create it in path/name.
120 """
120 """
121 self.log.info(u"Uploading notebook to %s/%s", path, name or '')
121 self.log.info(u"Uploading notebook to %s/%s", path, name or '')
122 if name:
122 if name:
123 model['name'] = name
123 model['name'] = name
124
124
125 model = self.notebook_manager.create_notebook_model(model, path)
125 model = self.notebook_manager.create_notebook_model(model, path)
126 self.set_status(201)
126 self.set_status(201)
127 self._finish_model(model)
127 self._finish_model(model)
128
128
129 def _create_empty_notebook(self, path, name=None):
129 def _create_empty_notebook(self, path, name=None):
130 """Create an empty notebook in path
130 """Create an empty notebook in path
131
131
132 If name specified, create it in path/name.
132 If name specified, create it in path/name.
133 """
133 """
134 self.log.info(u"Creating new notebook in %s/%s", path, name or '')
134 self.log.info(u"Creating new notebook in %s/%s", path, name or '')
135 model = {}
135 model = {}
136 if name:
136 if name:
137 model['name'] = name
137 model['name'] = name
138 model = self.notebook_manager.create_notebook_model(model, path=path)
138 model = self.notebook_manager.create_notebook_model(model, path=path)
139 self.set_status(201)
139 self.set_status(201)
140 self._finish_model(model)
140 self._finish_model(model)
141
141
142 def _save_notebook(self, model, path, name):
142 def _save_notebook(self, model, path, name):
143 """Save an existing notebook."""
143 """Save an existing notebook."""
144 self.log.info(u"Saving notebook at %s/%s", path, name)
144 self.log.info(u"Saving notebook at %s/%s", path, name)
145 model = self.notebook_manager.save_notebook_model(model, name, path)
145 model = self.notebook_manager.save_notebook_model(model, name, path)
146 if model['path'] != path.strip('/') or model['name'] != name:
146 if model['path'] != path.strip('/') or model['name'] != name:
147 # a rename happened, set Location header
147 # a rename happened, set Location header
148 location = True
148 location = True
149 else:
149 else:
150 location = False
150 location = False
151 self._finish_model(model, location)
151 self._finish_model(model, location)
152
152
153 @web.authenticated
153 @web.authenticated
154 @json_errors
154 @json_errors
155 def post(self, path='', name=None):
155 def post(self, path='', name=None):
156 """Create a new notebook in the specified path.
156 """Create a new notebook in the specified path.
157
157
158 POST creates new notebooks. The server always decides on the notebook name.
158 POST creates new notebooks. The server always decides on the notebook name.
159
159
160 POST /api/notebooks/path
160 POST /api/notebooks/path
161 New untitled notebook in path. If content specified, upload a
161 New untitled notebook in path. If content specified, upload a
162 notebook, otherwise start empty.
162 notebook, otherwise start empty.
163 POST /api/notebooks/path?copy=OtherNotebook.ipynb
163 POST /api/notebooks/path?copy=OtherNotebook.ipynb
164 New copy of OtherNotebook in path
164 New copy of OtherNotebook in path
165 """
165 """
166
166
167 if name is not None:
167 if name is not None:
168 raise web.HTTPError(400, "Only POST to directories. Use PUT for full names.")
168 raise web.HTTPError(400, "Only POST to directories. Use PUT for full names.")
169
169
170 model = self.get_json_body()
170 model = self.get_json_body()
171
171
172 if model is not None:
172 if model is not None:
173 copy_from = model.get('copy_from')
173 copy_from = model.get('copy_from')
174 if copy_from:
174 if copy_from:
175 if model.get('content'):
175 if model.get('content'):
176 raise web.HTTPError(400, "Can't upload and copy at the same time.")
176 raise web.HTTPError(400, "Can't upload and copy at the same time.")
177 self._copy_notebook(copy_from, path)
177 self._copy_notebook(copy_from, path)
178 else:
178 else:
179 self._upload_notebook(model, path)
179 self._upload_notebook(model, path)
180 else:
180 else:
181 self._create_empty_notebook(path)
181 self._create_empty_notebook(path)
182
182
183 @web.authenticated
183 @web.authenticated
184 @json_errors
184 @json_errors
185 def put(self, path='', name=None):
185 def put(self, path='', name=None):
186 """Saves the notebook in the location specified by name and path.
186 """Saves the notebook in the location specified by name and path.
187
187
188 PUT is very similar to POST, but the requester specifies the name,
188 PUT is very similar to POST, but the requester specifies the name,
189 whereas with POST, the server picks the name.
189 whereas with POST, the server picks the name.
190
190
191 PUT /api/notebooks/path/Name.ipynb
191 PUT /api/notebooks/path/Name.ipynb
192 Save notebook at ``path/Name.ipynb``. Notebook structure is specified
192 Save notebook at ``path/Name.ipynb``. Notebook structure is specified
193 in `content` key of JSON request body. If content is not specified,
193 in `content` key of JSON request body. If content is not specified,
194 create a new empty notebook.
194 create a new empty notebook.
195 PUT /api/notebooks/path/Name.ipynb?copy=OtherNotebook.ipynb
195 PUT /api/notebooks/path/Name.ipynb?copy=OtherNotebook.ipynb
196 Copy OtherNotebook to Name
196 Copy OtherNotebook to Name
197 """
197 """
198 if name is None:
198 if name is None:
199 raise web.HTTPError(400, "Only PUT to full names. Use POST for directories.")
199 raise web.HTTPError(400, "Only PUT to full names. Use POST for directories.")
200
200
201 model = self.get_json_body()
201 model = self.get_json_body()
202 if model:
202 if model:
203 copy_from = model.get('copy_from')
203 copy_from = model.get('copy_from')
204 if copy_from:
204 if copy_from:
205 if model.get('content'):
205 if model.get('content'):
206 raise web.HTTPError(400, "Can't upload and copy at the same time.")
206 raise web.HTTPError(400, "Can't upload and copy at the same time.")
207 self._copy_notebook(copy_from, path, name)
207 self._copy_notebook(copy_from, path, name)
208 elif self.notebook_manager.notebook_exists(name, path):
208 elif self.notebook_manager.notebook_exists(name, path):
209 self._save_notebook(model, path, name)
209 self._save_notebook(model, path, name)
210 else:
210 else:
211 self._upload_notebook(model, path, name)
211 self._upload_notebook(model, path, name)
212 else:
212 else:
213 self._create_empty_notebook(path, name)
213 self._create_empty_notebook(path, name)
214
214
215 @web.authenticated
215 @web.authenticated
216 @json_errors
216 @json_errors
217 def delete(self, path='', name=None):
217 def delete(self, path='', name=None):
218 """delete the notebook in the given notebook path"""
218 """delete the notebook in the given notebook path"""
219 nbm = self.notebook_manager
219 nbm = self.notebook_manager
220 nbm.delete_notebook_model(name, path)
220 nbm.delete_notebook_model(name, path)
221 self.set_status(204)
221 self.set_status(204)
222 self.finish()
222 self.finish()
223
223
224
224
225 class NotebookCheckpointsHandler(IPythonHandler):
225 class NotebookCheckpointsHandler(IPythonHandler):
226
226
227 SUPPORTED_METHODS = ('GET', 'POST')
227 SUPPORTED_METHODS = ('GET', 'POST')
228
228
229 @web.authenticated
229 @web.authenticated
230 @json_errors
230 @json_errors
231 def get(self, path='', name=None):
231 def get(self, path='', name=None):
232 """get lists checkpoints for a notebook"""
232 """get lists checkpoints for a notebook"""
233 nbm = self.notebook_manager
233 nbm = self.notebook_manager
234 checkpoints = nbm.list_checkpoints(name, path)
234 checkpoints = nbm.list_checkpoints(name, path)
235 data = json.dumps(checkpoints, default=date_default)
235 data = json.dumps(checkpoints, default=date_default)
236 self.finish(data)
236 self.finish(data)
237
237
238 @web.authenticated
238 @web.authenticated
239 @json_errors
239 @json_errors
240 def post(self, path='', name=None):
240 def post(self, path='', name=None):
241 """post creates a new checkpoint"""
241 """post creates a new checkpoint"""
242 nbm = self.notebook_manager
242 nbm = self.notebook_manager
243 checkpoint = nbm.create_checkpoint(name, path)
243 checkpoint = nbm.create_checkpoint(name, path)
244 data = json.dumps(checkpoint, default=date_default)
244 data = json.dumps(checkpoint, default=date_default)
245 location = url_path_join(self.base_project_url, 'api/notebooks',
245 location = url_path_join(self.base_url, 'api/notebooks',
246 path, name, 'checkpoints', checkpoint['id'])
246 path, name, 'checkpoints', checkpoint['id'])
247 self.set_header('Location', url_escape(location))
247 self.set_header('Location', url_escape(location))
248 self.set_status(201)
248 self.set_status(201)
249 self.finish(data)
249 self.finish(data)
250
250
251
251
252 class ModifyNotebookCheckpointsHandler(IPythonHandler):
252 class ModifyNotebookCheckpointsHandler(IPythonHandler):
253
253
254 SUPPORTED_METHODS = ('POST', 'DELETE')
254 SUPPORTED_METHODS = ('POST', 'DELETE')
255
255
256 @web.authenticated
256 @web.authenticated
257 @json_errors
257 @json_errors
258 def post(self, path, name, checkpoint_id):
258 def post(self, path, name, checkpoint_id):
259 """post restores a notebook from a checkpoint"""
259 """post restores a notebook from a checkpoint"""
260 nbm = self.notebook_manager
260 nbm = self.notebook_manager
261 nbm.restore_checkpoint(checkpoint_id, name, path)
261 nbm.restore_checkpoint(checkpoint_id, name, path)
262 self.set_status(204)
262 self.set_status(204)
263 self.finish()
263 self.finish()
264
264
265 @web.authenticated
265 @web.authenticated
266 @json_errors
266 @json_errors
267 def delete(self, path, name, checkpoint_id):
267 def delete(self, path, name, checkpoint_id):
268 """delete clears a checkpoint for a given notebook"""
268 """delete clears a checkpoint for a given notebook"""
269 nbm = self.notebook_manager
269 nbm = self.notebook_manager
270 nbm.delete_checkpoint(checkpoint_id, name, path)
270 nbm.delete_checkpoint(checkpoint_id, name, path)
271 self.set_status(204)
271 self.set_status(204)
272 self.finish()
272 self.finish()
273
273
274 #-----------------------------------------------------------------------------
274 #-----------------------------------------------------------------------------
275 # URL to handler mappings
275 # URL to handler mappings
276 #-----------------------------------------------------------------------------
276 #-----------------------------------------------------------------------------
277
277
278
278
279 _checkpoint_id_regex = r"(?P<checkpoint_id>[\w-]+)"
279 _checkpoint_id_regex = r"(?P<checkpoint_id>[\w-]+)"
280
280
281 default_handlers = [
281 default_handlers = [
282 (r"/api/notebooks%s/checkpoints" % notebook_path_regex, NotebookCheckpointsHandler),
282 (r"/api/notebooks%s/checkpoints" % notebook_path_regex, NotebookCheckpointsHandler),
283 (r"/api/notebooks%s/checkpoints/%s" % (notebook_path_regex, _checkpoint_id_regex),
283 (r"/api/notebooks%s/checkpoints/%s" % (notebook_path_regex, _checkpoint_id_regex),
284 ModifyNotebookCheckpointsHandler),
284 ModifyNotebookCheckpointsHandler),
285 (r"/api/notebooks%s" % notebook_path_regex, NotebookHandler),
285 (r"/api/notebooks%s" % notebook_path_regex, NotebookHandler),
286 (r"/api/notebooks%s" % path_regex, NotebookHandler),
286 (r"/api/notebooks%s" % path_regex, NotebookHandler),
287 ]
287 ]
288
288
289
289
290
290
@@ -1,45 +1,52 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 // Login button
9 // Login button
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13
14
14 var LoginWidget = function (selector, options) {
15 var LoginWidget = function (selector, options) {
15 var options = options || {};
16 options = options || {};
16 this.base_url = options.baseProjectUrl || $('body').data('baseProjectUrl') ;
17 this.base_url = options.base_url || IPython.utils.get_body_data("baseUrl");
17 this.selector = selector;
18 this.selector = selector;
18 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
19 this.element = $(selector);
20 this.element = $(selector);
20 this.style();
21 this.style();
21 this.bind_events();
22 this.bind_events();
22 }
23 }
23 };
24 };
24
25
25 LoginWidget.prototype.style = function () {
26 LoginWidget.prototype.style = function () {
26 this.element.find("button").addClass("btn btn-small");
27 this.element.find("button").addClass("btn btn-small");
27 };
28 };
28
29
29
30
30 LoginWidget.prototype.bind_events = function () {
31 LoginWidget.prototype.bind_events = function () {
31 var that = this;
32 var that = this;
32 this.element.find("button#logout").click(function () {
33 this.element.find("button#logout").click(function () {
33 window.location = that.base_url+"logout";
34 window.location = IPythin.utils.url_join_encode(
35 that.base_url,
36 "logout"
37 );
34 });
38 });
35 this.element.find("button#login").click(function () {
39 this.element.find("button#login").click(function () {
36 window.location = that.base_url+"login";
40 window.location = IPythin.utils.url_join_encode(
41 that.base_url,
42 "login"
43 );
37 });
44 });
38 };
45 };
39
46
40 // Set module variables
47 // Set module variables
41 IPython.LoginWidget = LoginWidget;
48 IPython.LoginWidget = LoginWidget;
42
49
43 return IPython;
50 return IPython;
44
51
45 }(IPython));
52 }(IPython));
@@ -1,523 +1,547 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2012 The IPython Development Team
2 // Copyright (C) 2008-2012 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Utilities
9 // Utilities
10 //============================================================================
10 //============================================================================
11 IPython.namespace('IPython.utils');
11 IPython.namespace('IPython.utils');
12
12
13 IPython.utils = (function (IPython) {
13 IPython.utils = (function (IPython) {
14 "use strict";
14 "use strict";
15
15
16 //============================================================================
16 //============================================================================
17 // Cross-browser RegEx Split
17 // Cross-browser RegEx Split
18 //============================================================================
18 //============================================================================
19
19
20 // This code has been MODIFIED from the code licensed below to not replace the
20 // This code has been MODIFIED from the code licensed below to not replace the
21 // default browser split. The license is reproduced here.
21 // default browser split. The license is reproduced here.
22
22
23 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
23 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
24 /*!
24 /*!
25 * Cross-Browser Split 1.1.1
25 * Cross-Browser Split 1.1.1
26 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
26 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
27 * Available under the MIT License
27 * Available under the MIT License
28 * ECMAScript compliant, uniform cross-browser split method
28 * ECMAScript compliant, uniform cross-browser split method
29 */
29 */
30
30
31 /**
31 /**
32 * Splits a string into an array of strings using a regex or string
32 * Splits a string into an array of strings using a regex or string
33 * separator. Matches of the separator are not included in the result array.
33 * separator. Matches of the separator are not included in the result array.
34 * However, if `separator` is a regex that contains capturing groups,
34 * However, if `separator` is a regex that contains capturing groups,
35 * backreferences are spliced into the result each time `separator` is
35 * backreferences are spliced into the result each time `separator` is
36 * matched. Fixes browser bugs compared to the native
36 * matched. Fixes browser bugs compared to the native
37 * `String.prototype.split` and can be used reliably cross-browser.
37 * `String.prototype.split` and can be used reliably cross-browser.
38 * @param {String} str String to split.
38 * @param {String} str String to split.
39 * @param {RegExp|String} separator Regex or string to use for separating
39 * @param {RegExp|String} separator Regex or string to use for separating
40 * the string.
40 * the string.
41 * @param {Number} [limit] Maximum number of items to include in the result
41 * @param {Number} [limit] Maximum number of items to include in the result
42 * array.
42 * array.
43 * @returns {Array} Array of substrings.
43 * @returns {Array} Array of substrings.
44 * @example
44 * @example
45 *
45 *
46 * // Basic use
46 * // Basic use
47 * regex_split('a b c d', ' ');
47 * regex_split('a b c d', ' ');
48 * // -> ['a', 'b', 'c', 'd']
48 * // -> ['a', 'b', 'c', 'd']
49 *
49 *
50 * // With limit
50 * // With limit
51 * regex_split('a b c d', ' ', 2);
51 * regex_split('a b c d', ' ', 2);
52 * // -> ['a', 'b']
52 * // -> ['a', 'b']
53 *
53 *
54 * // Backreferences in result array
54 * // Backreferences in result array
55 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
55 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
56 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
56 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
57 */
57 */
58 var regex_split = function (str, separator, limit) {
58 var regex_split = function (str, separator, limit) {
59 // If `separator` is not a regex, use `split`
59 // If `separator` is not a regex, use `split`
60 if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
60 if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
61 return split.call(str, separator, limit);
61 return split.call(str, separator, limit);
62 }
62 }
63 var output = [],
63 var output = [],
64 flags = (separator.ignoreCase ? "i" : "") +
64 flags = (separator.ignoreCase ? "i" : "") +
65 (separator.multiline ? "m" : "") +
65 (separator.multiline ? "m" : "") +
66 (separator.extended ? "x" : "") + // Proposed for ES6
66 (separator.extended ? "x" : "") + // Proposed for ES6
67 (separator.sticky ? "y" : ""), // Firefox 3+
67 (separator.sticky ? "y" : ""), // Firefox 3+
68 lastLastIndex = 0,
68 lastLastIndex = 0,
69 // Make `global` and avoid `lastIndex` issues by working with a copy
69 // Make `global` and avoid `lastIndex` issues by working with a copy
70 separator = new RegExp(separator.source, flags + "g"),
70 separator = new RegExp(separator.source, flags + "g"),
71 separator2, match, lastIndex, lastLength;
71 separator2, match, lastIndex, lastLength;
72 str += ""; // Type-convert
72 str += ""; // Type-convert
73
73
74 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
74 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
75 if (!compliantExecNpcg) {
75 if (!compliantExecNpcg) {
76 // Doesn't need flags gy, but they don't hurt
76 // Doesn't need flags gy, but they don't hurt
77 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
77 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
78 }
78 }
79 /* Values for `limit`, per the spec:
79 /* Values for `limit`, per the spec:
80 * If undefined: 4294967295 // Math.pow(2, 32) - 1
80 * If undefined: 4294967295 // Math.pow(2, 32) - 1
81 * If 0, Infinity, or NaN: 0
81 * If 0, Infinity, or NaN: 0
82 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
82 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
83 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
83 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
84 * If other: Type-convert, then use the above rules
84 * If other: Type-convert, then use the above rules
85 */
85 */
86 limit = typeof(limit) === "undefined" ?
86 limit = typeof(limit) === "undefined" ?
87 -1 >>> 0 : // Math.pow(2, 32) - 1
87 -1 >>> 0 : // Math.pow(2, 32) - 1
88 limit >>> 0; // ToUint32(limit)
88 limit >>> 0; // ToUint32(limit)
89 while (match = separator.exec(str)) {
89 while (match = separator.exec(str)) {
90 // `separator.lastIndex` is not reliable cross-browser
90 // `separator.lastIndex` is not reliable cross-browser
91 lastIndex = match.index + match[0].length;
91 lastIndex = match.index + match[0].length;
92 if (lastIndex > lastLastIndex) {
92 if (lastIndex > lastLastIndex) {
93 output.push(str.slice(lastLastIndex, match.index));
93 output.push(str.slice(lastLastIndex, match.index));
94 // Fix browsers whose `exec` methods don't consistently return `undefined` for
94 // Fix browsers whose `exec` methods don't consistently return `undefined` for
95 // nonparticipating capturing groups
95 // nonparticipating capturing groups
96 if (!compliantExecNpcg && match.length > 1) {
96 if (!compliantExecNpcg && match.length > 1) {
97 match[0].replace(separator2, function () {
97 match[0].replace(separator2, function () {
98 for (var i = 1; i < arguments.length - 2; i++) {
98 for (var i = 1; i < arguments.length - 2; i++) {
99 if (typeof(arguments[i]) === "undefined") {
99 if (typeof(arguments[i]) === "undefined") {
100 match[i] = undefined;
100 match[i] = undefined;
101 }
101 }
102 }
102 }
103 });
103 });
104 }
104 }
105 if (match.length > 1 && match.index < str.length) {
105 if (match.length > 1 && match.index < str.length) {
106 Array.prototype.push.apply(output, match.slice(1));
106 Array.prototype.push.apply(output, match.slice(1));
107 }
107 }
108 lastLength = match[0].length;
108 lastLength = match[0].length;
109 lastLastIndex = lastIndex;
109 lastLastIndex = lastIndex;
110 if (output.length >= limit) {
110 if (output.length >= limit) {
111 break;
111 break;
112 }
112 }
113 }
113 }
114 if (separator.lastIndex === match.index) {
114 if (separator.lastIndex === match.index) {
115 separator.lastIndex++; // Avoid an infinite loop
115 separator.lastIndex++; // Avoid an infinite loop
116 }
116 }
117 }
117 }
118 if (lastLastIndex === str.length) {
118 if (lastLastIndex === str.length) {
119 if (lastLength || !separator.test("")) {
119 if (lastLength || !separator.test("")) {
120 output.push("");
120 output.push("");
121 }
121 }
122 } else {
122 } else {
123 output.push(str.slice(lastLastIndex));
123 output.push(str.slice(lastLastIndex));
124 }
124 }
125 return output.length > limit ? output.slice(0, limit) : output;
125 return output.length > limit ? output.slice(0, limit) : output;
126 };
126 };
127
127
128 //============================================================================
128 //============================================================================
129 // End contributed Cross-browser RegEx Split
129 // End contributed Cross-browser RegEx Split
130 //============================================================================
130 //============================================================================
131
131
132
132
133 var uuid = function () {
133 var uuid = function () {
134 // http://www.ietf.org/rfc/rfc4122.txt
134 // http://www.ietf.org/rfc/rfc4122.txt
135 var s = [];
135 var s = [];
136 var hexDigits = "0123456789ABCDEF";
136 var hexDigits = "0123456789ABCDEF";
137 for (var i = 0; i < 32; i++) {
137 for (var i = 0; i < 32; i++) {
138 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
138 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
139 }
139 }
140 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
140 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
141 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
141 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
142
142
143 var uuid = s.join("");
143 var uuid = s.join("");
144 return uuid;
144 return uuid;
145 };
145 };
146
146
147
147
148 //Fix raw text to parse correctly in crazy XML
148 //Fix raw text to parse correctly in crazy XML
149 function xmlencode(string) {
149 function xmlencode(string) {
150 return string.replace(/\&/g,'&'+'amp;')
150 return string.replace(/\&/g,'&'+'amp;')
151 .replace(/</g,'&'+'lt;')
151 .replace(/</g,'&'+'lt;')
152 .replace(/>/g,'&'+'gt;')
152 .replace(/>/g,'&'+'gt;')
153 .replace(/\'/g,'&'+'apos;')
153 .replace(/\'/g,'&'+'apos;')
154 .replace(/\"/g,'&'+'quot;')
154 .replace(/\"/g,'&'+'quot;')
155 .replace(/`/g,'&'+'#96;');
155 .replace(/`/g,'&'+'#96;');
156 }
156 }
157
157
158
158
159 //Map from terminal commands to CSS classes
159 //Map from terminal commands to CSS classes
160 var ansi_colormap = {
160 var ansi_colormap = {
161 "01":"ansibold",
161 "01":"ansibold",
162
162
163 "30":"ansiblack",
163 "30":"ansiblack",
164 "31":"ansired",
164 "31":"ansired",
165 "32":"ansigreen",
165 "32":"ansigreen",
166 "33":"ansiyellow",
166 "33":"ansiyellow",
167 "34":"ansiblue",
167 "34":"ansiblue",
168 "35":"ansipurple",
168 "35":"ansipurple",
169 "36":"ansicyan",
169 "36":"ansicyan",
170 "37":"ansigray",
170 "37":"ansigray",
171
171
172 "40":"ansibgblack",
172 "40":"ansibgblack",
173 "41":"ansibgred",
173 "41":"ansibgred",
174 "42":"ansibggreen",
174 "42":"ansibggreen",
175 "43":"ansibgyellow",
175 "43":"ansibgyellow",
176 "44":"ansibgblue",
176 "44":"ansibgblue",
177 "45":"ansibgpurple",
177 "45":"ansibgpurple",
178 "46":"ansibgcyan",
178 "46":"ansibgcyan",
179 "47":"ansibggray"
179 "47":"ansibggray"
180 };
180 };
181
181
182 function _process_numbers(attrs, numbers) {
182 function _process_numbers(attrs, numbers) {
183 // process ansi escapes
183 // process ansi escapes
184 var n = numbers.shift();
184 var n = numbers.shift();
185 if (ansi_colormap[n]) {
185 if (ansi_colormap[n]) {
186 if ( ! attrs["class"] ) {
186 if ( ! attrs["class"] ) {
187 attrs["class"] = ansi_colormap[n];
187 attrs["class"] = ansi_colormap[n];
188 } else {
188 } else {
189 attrs["class"] += " " + ansi_colormap[n];
189 attrs["class"] += " " + ansi_colormap[n];
190 }
190 }
191 } else if (n == "38" || n == "48") {
191 } else if (n == "38" || n == "48") {
192 // VT100 256 color or 24 bit RGB
192 // VT100 256 color or 24 bit RGB
193 if (numbers.length < 2) {
193 if (numbers.length < 2) {
194 console.log("Not enough fields for VT100 color", numbers);
194 console.log("Not enough fields for VT100 color", numbers);
195 return;
195 return;
196 }
196 }
197
197
198 var index_or_rgb = numbers.shift();
198 var index_or_rgb = numbers.shift();
199 var r,g,b;
199 var r,g,b;
200 if (index_or_rgb == "5") {
200 if (index_or_rgb == "5") {
201 // 256 color
201 // 256 color
202 var idx = parseInt(numbers.shift());
202 var idx = parseInt(numbers.shift());
203 if (idx < 16) {
203 if (idx < 16) {
204 // indexed ANSI
204 // indexed ANSI
205 // ignore bright / non-bright distinction
205 // ignore bright / non-bright distinction
206 idx = idx % 8;
206 idx = idx % 8;
207 var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
207 var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
208 if ( ! attrs["class"] ) {
208 if ( ! attrs["class"] ) {
209 attrs["class"] = ansiclass;
209 attrs["class"] = ansiclass;
210 } else {
210 } else {
211 attrs["class"] += " " + ansiclass;
211 attrs["class"] += " " + ansiclass;
212 }
212 }
213 return;
213 return;
214 } else if (idx < 232) {
214 } else if (idx < 232) {
215 // 216 color 6x6x6 RGB
215 // 216 color 6x6x6 RGB
216 idx = idx - 16;
216 idx = idx - 16;
217 b = idx % 6;
217 b = idx % 6;
218 g = Math.floor(idx / 6) % 6;
218 g = Math.floor(idx / 6) % 6;
219 r = Math.floor(idx / 36) % 6;
219 r = Math.floor(idx / 36) % 6;
220 // convert to rgb
220 // convert to rgb
221 r = (r * 51);
221 r = (r * 51);
222 g = (g * 51);
222 g = (g * 51);
223 b = (b * 51);
223 b = (b * 51);
224 } else {
224 } else {
225 // grayscale
225 // grayscale
226 idx = idx - 231;
226 idx = idx - 231;
227 // it's 1-24 and should *not* include black or white,
227 // it's 1-24 and should *not* include black or white,
228 // so a 26 point scale
228 // so a 26 point scale
229 r = g = b = Math.floor(idx * 256 / 26);
229 r = g = b = Math.floor(idx * 256 / 26);
230 }
230 }
231 } else if (index_or_rgb == "2") {
231 } else if (index_or_rgb == "2") {
232 // Simple 24 bit RGB
232 // Simple 24 bit RGB
233 if (numbers.length > 3) {
233 if (numbers.length > 3) {
234 console.log("Not enough fields for RGB", numbers);
234 console.log("Not enough fields for RGB", numbers);
235 return;
235 return;
236 }
236 }
237 r = numbers.shift();
237 r = numbers.shift();
238 g = numbers.shift();
238 g = numbers.shift();
239 b = numbers.shift();
239 b = numbers.shift();
240 } else {
240 } else {
241 console.log("unrecognized control", numbers);
241 console.log("unrecognized control", numbers);
242 return;
242 return;
243 }
243 }
244 if (r !== undefined) {
244 if (r !== undefined) {
245 // apply the rgb color
245 // apply the rgb color
246 var line;
246 var line;
247 if (n == "38") {
247 if (n == "38") {
248 line = "color: ";
248 line = "color: ";
249 } else {
249 } else {
250 line = "background-color: ";
250 line = "background-color: ";
251 }
251 }
252 line = line + "rgb(" + r + "," + g + "," + b + ");"
252 line = line + "rgb(" + r + "," + g + "," + b + ");"
253 if ( !attrs["style"] ) {
253 if ( !attrs["style"] ) {
254 attrs["style"] = line;
254 attrs["style"] = line;
255 } else {
255 } else {
256 attrs["style"] += " " + line;
256 attrs["style"] += " " + line;
257 }
257 }
258 }
258 }
259 }
259 }
260 }
260 }
261
261
262 function ansispan(str) {
262 function ansispan(str) {
263 // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
263 // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
264 // regular ansi escapes (using the table above)
264 // regular ansi escapes (using the table above)
265 return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
265 return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
266 if (!pattern) {
266 if (!pattern) {
267 // [(01|22|39|)m close spans
267 // [(01|22|39|)m close spans
268 return "</span>";
268 return "</span>";
269 }
269 }
270 // consume sequence of color escapes
270 // consume sequence of color escapes
271 var numbers = pattern.match(/\d+/g);
271 var numbers = pattern.match(/\d+/g);
272 var attrs = {};
272 var attrs = {};
273 while (numbers.length > 0) {
273 while (numbers.length > 0) {
274 _process_numbers(attrs, numbers);
274 _process_numbers(attrs, numbers);
275 }
275 }
276
276
277 var span = "<span ";
277 var span = "<span ";
278 for (var attr in attrs) {
278 for (var attr in attrs) {
279 var value = attrs[attr];
279 var value = attrs[attr];
280 span = span + " " + attr + '="' + attrs[attr] + '"';
280 span = span + " " + attr + '="' + attrs[attr] + '"';
281 }
281 }
282 return span + ">";
282 return span + ">";
283 });
283 });
284 };
284 };
285
285
286 // Transform ANSI color escape codes into HTML <span> tags with css
286 // Transform ANSI color escape codes into HTML <span> tags with css
287 // classes listed in the above ansi_colormap object. The actual color used
287 // classes listed in the above ansi_colormap object. The actual color used
288 // are set in the css file.
288 // are set in the css file.
289 function fixConsole(txt) {
289 function fixConsole(txt) {
290 txt = xmlencode(txt);
290 txt = xmlencode(txt);
291 var re = /\033\[([\dA-Fa-f;]*?)m/;
291 var re = /\033\[([\dA-Fa-f;]*?)m/;
292 var opened = false;
292 var opened = false;
293 var cmds = [];
293 var cmds = [];
294 var opener = "";
294 var opener = "";
295 var closer = "";
295 var closer = "";
296
296
297 // Strip all ANSI codes that are not color related. Matches
297 // Strip all ANSI codes that are not color related. Matches
298 // all ANSI codes that do not end with "m".
298 // all ANSI codes that do not end with "m".
299 var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
299 var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
300 txt = txt.replace(ignored_re, "");
300 txt = txt.replace(ignored_re, "");
301
301
302 // color ansi codes
302 // color ansi codes
303 txt = ansispan(txt);
303 txt = ansispan(txt);
304 return txt;
304 return txt;
305 }
305 }
306
306
307 // Remove chunks that should be overridden by the effect of
307 // Remove chunks that should be overridden by the effect of
308 // carriage return characters
308 // carriage return characters
309 function fixCarriageReturn(txt) {
309 function fixCarriageReturn(txt) {
310 var tmp = txt;
310 var tmp = txt;
311 do {
311 do {
312 txt = tmp;
312 txt = tmp;
313 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
313 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
314 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
314 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
315 } while (tmp.length < txt.length);
315 } while (tmp.length < txt.length);
316 return txt;
316 return txt;
317 }
317 }
318
318
319 // Locate any URLs and convert them to a anchor tag
319 // Locate any URLs and convert them to a anchor tag
320 function autoLinkUrls(txt) {
320 function autoLinkUrls(txt) {
321 return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
321 return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
322 "$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
322 "$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
323 }
323 }
324
324
325 // some keycodes that seem to be platform/browser independent
325 // some keycodes that seem to be platform/browser independent
326 var keycodes = {
326 var keycodes = {
327 BACKSPACE: 8,
327 BACKSPACE: 8,
328 TAB : 9,
328 TAB : 9,
329 ENTER : 13,
329 ENTER : 13,
330 SHIFT : 16,
330 SHIFT : 16,
331 CTRL : 17,
331 CTRL : 17,
332 CONTROL : 17,
332 CONTROL : 17,
333 ALT : 18,
333 ALT : 18,
334 CAPS_LOCK: 20,
334 CAPS_LOCK: 20,
335 ESC : 27,
335 ESC : 27,
336 SPACE : 32,
336 SPACE : 32,
337 PGUP : 33,
337 PGUP : 33,
338 PGDOWN : 34,
338 PGDOWN : 34,
339 END : 35,
339 END : 35,
340 HOME : 36,
340 HOME : 36,
341 LEFT_ARROW: 37,
341 LEFT_ARROW: 37,
342 LEFTARROW: 37,
342 LEFTARROW: 37,
343 LEFT : 37,
343 LEFT : 37,
344 UP_ARROW : 38,
344 UP_ARROW : 38,
345 UPARROW : 38,
345 UPARROW : 38,
346 UP : 38,
346 UP : 38,
347 RIGHT_ARROW:39,
347 RIGHT_ARROW:39,
348 RIGHTARROW:39,
348 RIGHTARROW:39,
349 RIGHT : 39,
349 RIGHT : 39,
350 DOWN_ARROW: 40,
350 DOWN_ARROW: 40,
351 DOWNARROW: 40,
351 DOWNARROW: 40,
352 DOWN : 40,
352 DOWN : 40,
353 I : 73,
353 I : 73,
354 M : 77,
354 M : 77,
355 // all three of these keys may be COMMAND on OS X:
355 // all three of these keys may be COMMAND on OS X:
356 LEFT_SUPER : 91,
356 LEFT_SUPER : 91,
357 RIGHT_SUPER : 92,
357 RIGHT_SUPER : 92,
358 COMMAND : 93,
358 COMMAND : 93,
359 };
359 };
360
360
361 // trigger a key press event
361 // trigger a key press event
362 var press = function (key) {
362 var press = function (key) {
363 var key_press = $.Event('keydown', {which: key});
363 var key_press = $.Event('keydown', {which: key});
364 $(document).trigger(key_press);
364 $(document).trigger(key_press);
365 }
365 }
366
366
367 var press_up = function() { press(keycodes.UP); };
367 var press_up = function() { press(keycodes.UP); };
368 var press_down = function() { press(keycodes.DOWN); };
368 var press_down = function() { press(keycodes.DOWN); };
369
369
370 var press_ctrl_enter = function() {
370 var press_ctrl_enter = function() {
371 $(document).trigger($.Event('keydown', {which: keycodes.ENTER, ctrlKey: true}));
371 $(document).trigger($.Event('keydown', {which: keycodes.ENTER, ctrlKey: true}));
372 };
372 };
373
373
374 var press_shift_enter = function() {
374 var press_shift_enter = function() {
375 $(document).trigger($.Event('keydown', {which: keycodes.ENTER, shiftKey: true}));
375 $(document).trigger($.Event('keydown', {which: keycodes.ENTER, shiftKey: true}));
376 };
376 };
377
377
378 // trigger the ctrl-m shortcut followed by one of our keys
378 // trigger the ctrl-m shortcut followed by one of our keys
379 var press_ghetto = function(key) {
379 var press_ghetto = function(key) {
380 $(document).trigger($.Event('keydown', {which: keycodes.M, ctrlKey: true}));
380 $(document).trigger($.Event('keydown', {which: keycodes.M, ctrlKey: true}));
381 press(key);
381 press(key);
382 };
382 };
383
383
384
384
385 var points_to_pixels = function (points) {
385 var points_to_pixels = function (points) {
386 // A reasonably good way of converting between points and pixels.
386 // A reasonably good way of converting between points and pixels.
387 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
387 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
388 $(body).append(test);
388 $(body).append(test);
389 var pixel_per_point = test.width()/10000;
389 var pixel_per_point = test.width()/10000;
390 test.remove();
390 test.remove();
391 return Math.floor(points*pixel_per_point);
391 return Math.floor(points*pixel_per_point);
392 };
392 };
393
393
394 var always_new = function (constructor) {
394 var always_new = function (constructor) {
395 // wrapper around contructor to avoid requiring `var a = new constructor()`
395 // wrapper around contructor to avoid requiring `var a = new constructor()`
396 // useful for passing constructors as callbacks,
396 // useful for passing constructors as callbacks,
397 // not for programmer laziness.
397 // not for programmer laziness.
398 // from http://programmers.stackexchange.com/questions/118798
398 // from http://programmers.stackexchange.com/questions/118798
399 return function () {
399 return function () {
400 var obj = Object.create(constructor.prototype);
400 var obj = Object.create(constructor.prototype);
401 constructor.apply(obj, arguments);
401 constructor.apply(obj, arguments);
402 return obj;
402 return obj;
403 };
403 };
404 };
404 };
405
405
406
406
407 var url_path_join = function () {
407 var url_path_join = function () {
408 // join a sequence of url components with '/'
408 // join a sequence of url components with '/'
409 var url = '';
409 var url = '';
410 for (var i = 0; i < arguments.length; i++) {
410 for (var i = 0; i < arguments.length; i++) {
411 if (arguments[i] === '') {
411 if (arguments[i] === '') {
412 continue;
412 continue;
413 }
413 }
414 if (url.length > 0 && url[url.length-1] != '/') {
414 if (url.length > 0 && url[url.length-1] != '/') {
415 url = url + '/' + arguments[i];
415 url = url + '/' + arguments[i];
416 } else {
416 } else {
417 url = url + arguments[i];
417 url = url + arguments[i];
418 }
418 }
419 }
419 }
420 url = url.replace(/\/\/+/, '/');
420 return url;
421 return url;
421 };
422 };
422
423
424 var parse_url = function (url) {
425 // an `a` element with an href allows attr-access to the parsed segments of a URL
426 // a = parse_url("http://localhost:8888/path/name#hash")
427 // a.protocol = "http:"
428 // a.host = "localhost:8888"
429 // a.hostname = "localhost"
430 // a.port = 8888
431 // a.pathname = "/path/name"
432 // a.hash = "#hash"
433 var a = document.createElement("a");
434 a.href = url;
435 return a;
436 };
423
437
424 var encode_uri_components = function (uri) {
438 var encode_uri_components = function (uri) {
425 // encode just the components of a multi-segment uri,
439 // encode just the components of a multi-segment uri,
426 // leaving '/' separators
440 // leaving '/' separators
427 return uri.split('/').map(encodeURIComponent).join('/');
441 return uri.split('/').map(encodeURIComponent).join('/');
428 }
442 };
429
443
430 var url_join_encode = function () {
444 var url_join_encode = function () {
431 // join a sequence of url components with '/',
445 // join a sequence of url components with '/',
432 // encoding each component with encodeURIComponent
446 // encoding each component with encodeURIComponent
433 return encode_uri_components(url_path_join.apply(null, arguments));
447 return encode_uri_components(url_path_join.apply(null, arguments));
434 };
448 };
435
449
436
450
437 var splitext = function (filename) {
451 var splitext = function (filename) {
438 // mimic Python os.path.splitext
452 // mimic Python os.path.splitext
439 // Returns ['base', '.ext']
453 // Returns ['base', '.ext']
440 var idx = filename.lastIndexOf('.');
454 var idx = filename.lastIndexOf('.');
441 if (idx > 0) {
455 if (idx > 0) {
442 return [filename.slice(0, idx), filename.slice(idx)];
456 return [filename.slice(0, idx), filename.slice(idx)];
443 } else {
457 } else {
444 return [filename, ''];
458 return [filename, ''];
445 }
459 }
446 }
460 };
461
462
463 var get_body_data = function(key) {
464 // get a url-encoded item from body.data and decode it
465 // we should never have any encoded URLs anywhere else in code
466 // until we are building an actual request
467 return decodeURIComponent($('body').data(key));
468 };
447
469
448
470
449 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
471 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
450 var browser = (function() {
472 var browser = (function() {
451 if (typeof navigator === 'undefined') {
473 if (typeof navigator === 'undefined') {
452 // navigator undefined in node
474 // navigator undefined in node
453 return 'None';
475 return 'None';
454 }
476 }
455 var N= navigator.appName, ua= navigator.userAgent, tem;
477 var N= navigator.appName, ua= navigator.userAgent, tem;
456 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
478 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
457 if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
479 if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
458 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
480 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
459 return M;
481 return M;
460 })();
482 })();
461
483
462 // http://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript
484 // http://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript
463 var platform = (function () {
485 var platform = (function () {
464 if (typeof navigator === 'undefined') {
486 if (typeof navigator === 'undefined') {
465 // navigator undefined in node
487 // navigator undefined in node
466 return 'None';
488 return 'None';
467 }
489 }
468 var OSName="None";
490 var OSName="None";
469 if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
491 if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
470 if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
492 if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
471 if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
493 if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
472 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
494 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
473 return OSName
495 return OSName
474 })();
496 })();
475
497
476 var is_or_has = function (a, b) {
498 var is_or_has = function (a, b) {
477 // Is b a child of a or a itself?
499 // Is b a child of a or a itself?
478 return a.has(b).length !==0 || a.is(b);
500 return a.has(b).length !==0 || a.is(b);
479 }
501 }
480
502
481 var is_focused = function (e) {
503 var is_focused = function (e) {
482 // Is element e, or one of its children focused?
504 // Is element e, or one of its children focused?
483 e = $(e);
505 e = $(e);
484 var target = $(document.activeElement);
506 var target = $(document.activeElement);
485 if (target.length > 0) {
507 if (target.length > 0) {
486 if (is_or_has(e, target)) {
508 if (is_or_has(e, target)) {
487 return true;
509 return true;
488 } else {
510 } else {
489 return false;
511 return false;
490 }
512 }
491 } else {
513 } else {
492 return false;
514 return false;
493 }
515 }
494 }
516 }
495
517
496
518
497 return {
519 return {
498 regex_split : regex_split,
520 regex_split : regex_split,
499 uuid : uuid,
521 uuid : uuid,
500 fixConsole : fixConsole,
522 fixConsole : fixConsole,
501 keycodes : keycodes,
523 keycodes : keycodes,
502 press : press,
524 press : press,
503 press_up : press_up,
525 press_up : press_up,
504 press_down : press_down,
526 press_down : press_down,
505 press_ctrl_enter : press_ctrl_enter,
527 press_ctrl_enter : press_ctrl_enter,
506 press_shift_enter : press_shift_enter,
528 press_shift_enter : press_shift_enter,
507 press_ghetto : press_ghetto,
529 press_ghetto : press_ghetto,
508 fixCarriageReturn : fixCarriageReturn,
530 fixCarriageReturn : fixCarriageReturn,
509 autoLinkUrls : autoLinkUrls,
531 autoLinkUrls : autoLinkUrls,
510 points_to_pixels : points_to_pixels,
532 points_to_pixels : points_to_pixels,
533 get_body_data : get_body_data,
534 parse_url : parse_url,
511 url_path_join : url_path_join,
535 url_path_join : url_path_join,
512 url_join_encode : url_join_encode,
536 url_join_encode : url_join_encode,
513 encode_uri_components : encode_uri_components,
537 encode_uri_components : encode_uri_components,
514 splitext : splitext,
538 splitext : splitext,
515 always_new : always_new,
539 always_new : always_new,
516 browser : browser,
540 browser : browser,
517 platform: platform,
541 platform: platform,
518 is_or_has : is_or_has,
542 is_or_has : is_or_has,
519 is_focused : is_focused
543 is_focused : is_focused
520 };
544 };
521
545
522 }(IPython));
546 }(IPython));
523
547
@@ -1,764 +1,772 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Keyboard management
9 // Keyboard management
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 // Setup global keycodes and inverse keycodes.
15 // Setup global keycodes and inverse keycodes.
16
16
17 // See http://unixpapa.com/js/key.html for a complete description. The short of
17 // See http://unixpapa.com/js/key.html for a complete description. The short of
18 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
18 // it is that there are different keycode sets. Firefox uses the "Mozilla keycodes"
19 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
19 // and Webkit/IE use the "IE keycodes". These keycode sets are mostly the same
20 // but have minor differences.
20 // but have minor differences.
21
21
22 // These apply to Firefox, (Webkit and IE)
22 // These apply to Firefox, (Webkit and IE)
23 var _keycodes = {
23 var _keycodes = {
24 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
24 'a': 65, 'b': 66, 'c': 67, 'd': 68, 'e': 69, 'f': 70, 'g': 71, 'h': 72, 'i': 73,
25 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
25 'j': 74, 'k': 75, 'l': 76, 'm': 77, 'n': 78, 'o': 79, 'p': 80, 'q': 81, 'r': 82,
26 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
26 's': 83, 't': 84, 'u': 85, 'v': 86, 'w': 87, 'x': 88, 'y': 89, 'z': 90,
27 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
27 '1 !': 49, '2 @': 50, '3 #': 51, '4 $': 52, '5 %': 53, '6 ^': 54,
28 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
28 '7 &': 55, '8 *': 56, '9 (': 57, '0 )': 48,
29 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
29 '[ {': 219, '] }': 221, '` ~': 192, ', <': 188, '. >': 190, '/ ?': 191,
30 '\\ |': 220, '\' "': 222,
30 '\\ |': 220, '\' "': 222,
31 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
31 'numpad0': 96, 'numpad1': 97, 'numpad2': 98, 'numpad3': 99, 'numpad4': 100,
32 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
32 'numpad5': 101, 'numpad6': 102, 'numpad7': 103, 'numpad8': 104, 'numpad9': 105,
33 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
33 'multiply': 106, 'add': 107, 'subtract': 109, 'decimal': 110, 'divide': 111,
34 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
34 'f1': 112, 'f2': 113, 'f3': 114, 'f4': 115, 'f5': 116, 'f6': 117, 'f7': 118,
35 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
35 'f8': 119, 'f9': 120, 'f11': 122, 'f12': 123, 'f13': 124, 'f14': 125, 'f15': 126,
36 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
36 'backspace': 8, 'tab': 9, 'enter': 13, 'shift': 16, 'ctrl': 17, 'alt': 18,
37 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
37 'meta': 91, 'capslock': 20, 'esc': 27, 'space': 32, 'pageup': 33, 'pagedown': 34,
38 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
38 'end': 35, 'home': 36, 'left': 37, 'up': 38, 'right': 39, 'down': 40,
39 'insert': 45, 'delete': 46, 'numlock': 144,
39 'insert': 45, 'delete': 46, 'numlock': 144,
40 };
40 };
41
41
42 // These apply to Firefox and Opera
42 // These apply to Firefox and Opera
43 var _mozilla_keycodes = {
43 var _mozilla_keycodes = {
44 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
44 '; :': 59, '= +': 61, '- _': 173, 'meta': 224
45 }
45 }
46
46
47 // This apply to Webkit and IE
47 // This apply to Webkit and IE
48 var _ie_keycodes = {
48 var _ie_keycodes = {
49 '; :': 186, '= +': 187, '- _': 189,
49 '; :': 186, '= +': 187, '- _': 189,
50 }
50 }
51
51
52 var browser = IPython.utils.browser[0];
52 var browser = IPython.utils.browser[0];
53 var platform = IPython.utils.platform;
53 var platform = IPython.utils.platform;
54
54
55 if (browser === 'Firefox' || browser === 'Opera') {
55 if (browser === 'Firefox' || browser === 'Opera') {
56 $.extend(_keycodes, _mozilla_keycodes);
56 $.extend(_keycodes, _mozilla_keycodes);
57 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
57 } else if (browser === 'Safari' || browser === 'Chrome' || browser === 'MSIE') {
58 $.extend(_keycodes, _ie_keycodes);
58 $.extend(_keycodes, _ie_keycodes);
59 }
59 }
60
60
61 var keycodes = {};
61 var keycodes = {};
62 var inv_keycodes = {};
62 var inv_keycodes = {};
63 for (var name in _keycodes) {
63 for (var name in _keycodes) {
64 var names = name.split(' ');
64 var names = name.split(' ');
65 if (names.length === 1) {
65 if (names.length === 1) {
66 var n = names[0]
66 var n = names[0]
67 keycodes[n] = _keycodes[n]
67 keycodes[n] = _keycodes[n]
68 inv_keycodes[_keycodes[n]] = n
68 inv_keycodes[_keycodes[n]] = n
69 } else {
69 } else {
70 var primary = names[0];
70 var primary = names[0];
71 var secondary = names[1];
71 var secondary = names[1];
72 keycodes[primary] = _keycodes[name]
72 keycodes[primary] = _keycodes[name]
73 keycodes[secondary] = _keycodes[name]
73 keycodes[secondary] = _keycodes[name]
74 inv_keycodes[_keycodes[name]] = primary
74 inv_keycodes[_keycodes[name]] = primary
75 }
75 }
76 }
76 }
77
77
78
78
79 // Default keyboard shortcuts
79 // Default keyboard shortcuts
80
80
81 var default_common_shortcuts = {
81 var default_common_shortcuts = {
82 'shift' : {
82 'shift' : {
83 help : '',
83 help : '',
84 help_index : '',
84 help_index : '',
85 handler : function (event) {
85 handler : function (event) {
86 // ignore shift keydown
86 // ignore shift keydown
87 return true;
87 return true;
88 }
88 }
89 },
89 },
90 'shift+enter' : {
90 'shift+enter' : {
91 help : 'run cell, select below',
91 help : 'run cell, select below',
92 help_index : 'ba',
92 help_index : 'ba',
93 handler : function (event) {
93 handler : function (event) {
94 IPython.notebook.execute_cell_and_select_below();
94 IPython.notebook.execute_cell_and_select_below();
95 return false;
95 return false;
96 }
96 }
97 },
97 },
98 'ctrl+enter' : {
98 'ctrl+enter' : {
99 help : 'run cell',
99 help : 'run cell',
100 help_index : 'bb',
100 help_index : 'bb',
101 handler : function (event) {
101 handler : function (event) {
102 IPython.notebook.execute_cell();
102 IPython.notebook.execute_cell();
103 return false;
103 return false;
104 }
104 }
105 },
105 },
106 'alt+enter' : {
106 'alt+enter' : {
107 help : 'run cell, insert below',
107 help : 'run cell, insert below',
108 help_index : 'bc',
108 help_index : 'bc',
109 handler : function (event) {
109 handler : function (event) {
110 IPython.notebook.execute_cell_and_insert_below();
110 IPython.notebook.execute_cell_and_insert_below();
111 return false;
111 return false;
112 }
112 }
113 }
113 }
114 }
114 }
115
115
116 if (platform === 'MacOS') {
116 if (platform === 'MacOS') {
117 default_common_shortcuts['cmd+s'] =
117 default_common_shortcuts['cmd+s'] =
118 {
118 {
119 help : 'save notebook',
119 help : 'save notebook',
120 help_index : 'fb',
120 help_index : 'fb',
121 handler : function (event) {
121 handler : function (event) {
122 IPython.notebook.save_checkpoint();
122 IPython.notebook.save_checkpoint();
123 event.preventDefault();
123 event.preventDefault();
124 return false;
124 return false;
125 }
125 }
126 };
126 };
127 } else {
127 } else {
128 default_common_shortcuts['ctrl+s'] =
128 default_common_shortcuts['ctrl+s'] =
129 {
129 {
130 help : 'save notebook',
130 help : 'save notebook',
131 help_index : 'fb',
131 help_index : 'fb',
132 handler : function (event) {
132 handler : function (event) {
133 IPython.notebook.save_checkpoint();
133 IPython.notebook.save_checkpoint();
134 event.preventDefault();
134 event.preventDefault();
135 return false;
135 return false;
136 }
136 }
137 };
137 };
138 }
138 }
139
139
140 // Edit mode defaults
140 // Edit mode defaults
141
141
142 var default_edit_shortcuts = {
142 var default_edit_shortcuts = {
143 'esc' : {
143 'esc' : {
144 help : 'command mode',
144 help : 'command mode',
145 help_index : 'aa',
145 help_index : 'aa',
146 handler : function (event) {
146 handler : function (event) {
147 IPython.notebook.command_mode();
147 IPython.notebook.command_mode();
148 IPython.notebook.focus_cell();
148 IPython.notebook.focus_cell();
149 return false;
149 return false;
150 }
150 }
151 },
151 },
152 'ctrl+m' : {
152 'ctrl+m' : {
153 help : 'command mode',
153 help : 'command mode',
154 help_index : 'ab',
154 help_index : 'ab',
155 handler : function (event) {
155 handler : function (event) {
156 IPython.notebook.command_mode();
156 IPython.notebook.command_mode();
157 IPython.notebook.focus_cell();
157 IPython.notebook.focus_cell();
158 return false;
158 return false;
159 }
159 }
160 },
160 },
161 'up' : {
161 'up' : {
162 help : '',
162 help : '',
163 help_index : '',
163 help_index : '',
164 handler : function (event) {
164 handler : function (event) {
165 var cell = IPython.notebook.get_selected_cell();
165 var cell = IPython.notebook.get_selected_cell();
166 if (cell && cell.at_top()) {
166 if (cell && cell.at_top()) {
167 event.preventDefault();
167 event.preventDefault();
168 IPython.notebook.command_mode()
168 IPython.notebook.command_mode()
169 IPython.notebook.select_prev();
169 IPython.notebook.select_prev();
170 IPython.notebook.edit_mode();
170 IPython.notebook.edit_mode();
171 return false;
171 return false;
172 };
172 };
173 }
173 }
174 },
174 },
175 'down' : {
175 'down' : {
176 help : '',
176 help : '',
177 help_index : '',
177 help_index : '',
178 handler : function (event) {
178 handler : function (event) {
179 var cell = IPython.notebook.get_selected_cell();
179 var cell = IPython.notebook.get_selected_cell();
180 if (cell && cell.at_bottom()) {
180 if (cell && cell.at_bottom()) {
181 event.preventDefault();
181 event.preventDefault();
182 IPython.notebook.command_mode()
182 IPython.notebook.command_mode()
183 IPython.notebook.select_next();
183 IPython.notebook.select_next();
184 IPython.notebook.edit_mode();
184 IPython.notebook.edit_mode();
185 return false;
185 return false;
186 };
186 };
187 }
187 }
188 },
188 },
189 'alt+-' : {
189 'alt+-' : {
190 help : 'split cell',
190 help : 'split cell',
191 help_index : 'ea',
191 help_index : 'ea',
192 handler : function (event) {
192 handler : function (event) {
193 IPython.notebook.split_cell();
193 IPython.notebook.split_cell();
194 return false;
194 return false;
195 }
195 }
196 },
196 },
197 'alt+subtract' : {
197 'alt+subtract' : {
198 help : '',
198 help : '',
199 help_index : 'eb',
199 help_index : 'eb',
200 handler : function (event) {
200 handler : function (event) {
201 IPython.notebook.split_cell();
201 IPython.notebook.split_cell();
202 return false;
202 return false;
203 }
203 }
204 },
204 },
205 'tab' : {
205 'tab' : {
206 help : 'indent or complete',
206 help : 'indent or complete',
207 help_index : 'ec',
207 help_index : 'ec',
208 },
208 },
209 'shift+tab' : {
209 'shift+tab' : {
210 help : 'tooltip',
210 help : 'tooltip',
211 help_index : 'ed',
211 help_index : 'ed',
212 },
212 },
213 }
213 }
214
214
215 if (platform === 'MacOS') {
215 if (platform === 'MacOS') {
216 default_edit_shortcuts['cmd+/'] =
216 default_edit_shortcuts['cmd+/'] =
217 {
217 {
218 help : 'toggle comment',
218 help : 'toggle comment',
219 help_index : 'ee'
219 help_index : 'ee'
220 };
220 };
221 default_edit_shortcuts['cmd+]'] =
221 default_edit_shortcuts['cmd+]'] =
222 {
222 {
223 help : 'indent',
223 help : 'indent',
224 help_index : 'ef'
224 help_index : 'ef'
225 };
225 };
226 default_edit_shortcuts['cmd+['] =
226 default_edit_shortcuts['cmd+['] =
227 {
227 {
228 help : 'dedent',
228 help : 'dedent',
229 help_index : 'eg'
229 help_index : 'eg'
230 };
230 };
231 } else {
231 } else {
232 default_edit_shortcuts['ctrl+/'] =
232 default_edit_shortcuts['ctrl+/'] =
233 {
233 {
234 help : 'toggle comment',
234 help : 'toggle comment',
235 help_index : 'ee'
235 help_index : 'ee'
236 };
236 };
237 default_edit_shortcuts['ctrl+]'] =
237 default_edit_shortcuts['ctrl+]'] =
238 {
238 {
239 help : 'indent',
239 help : 'indent',
240 help_index : 'ef'
240 help_index : 'ef'
241 };
241 };
242 default_edit_shortcuts['ctrl+['] =
242 default_edit_shortcuts['ctrl+['] =
243 {
243 {
244 help : 'dedent',
244 help : 'dedent',
245 help_index : 'eg'
245 help_index : 'eg'
246 };
246 };
247 }
247 }
248
248
249 // Command mode defaults
249 // Command mode defaults
250
250
251 var default_command_shortcuts = {
251 var default_command_shortcuts = {
252 'enter' : {
252 'enter' : {
253 help : 'edit mode',
253 help : 'edit mode',
254 help_index : 'aa',
254 help_index : 'aa',
255 handler : function (event) {
255 handler : function (event) {
256 IPython.notebook.edit_mode();
256 IPython.notebook.edit_mode();
257 return false;
257 return false;
258 }
258 }
259 },
259 },
260 'up' : {
260 'up' : {
261 help : 'select previous cell',
261 help : 'select previous cell',
262 help_index : 'da',
262 help_index : 'da',
263 handler : function (event) {
263 handler : function (event) {
264 var index = IPython.notebook.get_selected_index();
264 var index = IPython.notebook.get_selected_index();
265 if (index !== 0 && index !== null) {
265 if (index !== 0 && index !== null) {
266 IPython.notebook.select_prev();
266 IPython.notebook.select_prev();
267 var cell = IPython.notebook.get_selected_cell();
267 var cell = IPython.notebook.get_selected_cell();
268 cell.focus_cell();
268 cell.focus_cell();
269 };
269 };
270 return false;
270 return false;
271 }
271 }
272 },
272 },
273 'down' : {
273 'down' : {
274 help : 'select next cell',
274 help : 'select next cell',
275 help_index : 'db',
275 help_index : 'db',
276 handler : function (event) {
276 handler : function (event) {
277 var index = IPython.notebook.get_selected_index();
277 var index = IPython.notebook.get_selected_index();
278 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
278 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
279 IPython.notebook.select_next();
279 IPython.notebook.select_next();
280 var cell = IPython.notebook.get_selected_cell();
280 var cell = IPython.notebook.get_selected_cell();
281 cell.focus_cell();
281 cell.focus_cell();
282 };
282 };
283 return false;
283 return false;
284 }
284 }
285 },
285 },
286 'k' : {
286 'k' : {
287 help : 'select previous cell',
287 help : 'select previous cell',
288 help_index : 'dc',
288 help_index : 'dc',
289 handler : function (event) {
289 handler : function (event) {
290 var index = IPython.notebook.get_selected_index();
290 var index = IPython.notebook.get_selected_index();
291 if (index !== 0 && index !== null) {
291 if (index !== 0 && index !== null) {
292 IPython.notebook.select_prev();
292 IPython.notebook.select_prev();
293 var cell = IPython.notebook.get_selected_cell();
293 var cell = IPython.notebook.get_selected_cell();
294 cell.focus_cell();
294 cell.focus_cell();
295 };
295 };
296 return false;
296 return false;
297 }
297 }
298 },
298 },
299 'j' : {
299 'j' : {
300 help : 'select next cell',
300 help : 'select next cell',
301 help_index : 'dd',
301 help_index : 'dd',
302 handler : function (event) {
302 handler : function (event) {
303 var index = IPython.notebook.get_selected_index();
303 var index = IPython.notebook.get_selected_index();
304 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
304 if (index !== (IPython.notebook.ncells()-1) && index !== null) {
305 IPython.notebook.select_next();
305 IPython.notebook.select_next();
306 var cell = IPython.notebook.get_selected_cell();
306 var cell = IPython.notebook.get_selected_cell();
307 cell.focus_cell();
307 cell.focus_cell();
308 };
308 };
309 return false;
309 return false;
310 }
310 }
311 },
311 },
312 'x' : {
312 'x' : {
313 help : 'cut cell',
313 help : 'cut cell',
314 help_index : 'ee',
314 help_index : 'ee',
315 handler : function (event) {
315 handler : function (event) {
316 IPython.notebook.cut_cell();
316 IPython.notebook.cut_cell();
317 return false;
317 return false;
318 }
318 }
319 },
319 },
320 'c' : {
320 'c' : {
321 help : 'copy cell',
321 help : 'copy cell',
322 help_index : 'ef',
322 help_index : 'ef',
323 handler : function (event) {
323 handler : function (event) {
324 IPython.notebook.copy_cell();
324 IPython.notebook.copy_cell();
325 return false;
325 return false;
326 }
326 }
327 },
327 },
328 'shift+v' : {
328 'shift+v' : {
329 help : 'paste cell above',
329 help : 'paste cell above',
330 help_index : 'eg',
330 help_index : 'eg',
331 handler : function (event) {
331 handler : function (event) {
332 IPython.notebook.paste_cell_above();
332 IPython.notebook.paste_cell_above();
333 return false;
333 return false;
334 }
334 }
335 },
335 },
336 'v' : {
336 'v' : {
337 help : 'paste cell below',
337 help : 'paste cell below',
338 help_index : 'eh',
338 help_index : 'eh',
339 handler : function (event) {
339 handler : function (event) {
340 IPython.notebook.paste_cell_below();
340 IPython.notebook.paste_cell_below();
341 return false;
341 return false;
342 }
342 }
343 },
343 },
344 'd' : {
344 'd' : {
345 help : 'delete cell (press twice)',
345 help : 'delete cell (press twice)',
346 help_index : 'ej',
346 help_index : 'ej',
347 count: 2,
347 count: 2,
348 handler : function (event) {
348 handler : function (event) {
349 IPython.notebook.delete_cell();
349 IPython.notebook.delete_cell();
350 return false;
350 return false;
351 }
351 }
352 },
352 },
353 'a' : {
353 'a' : {
354 help : 'insert cell above',
354 help : 'insert cell above',
355 help_index : 'ec',
355 help_index : 'ec',
356 handler : function (event) {
356 handler : function (event) {
357 IPython.notebook.insert_cell_above('code');
357 IPython.notebook.insert_cell_above('code');
358 IPython.notebook.select_prev();
358 IPython.notebook.select_prev();
359 IPython.notebook.focus_cell();
359 IPython.notebook.focus_cell();
360 return false;
360 return false;
361 }
361 }
362 },
362 },
363 'b' : {
363 'b' : {
364 help : 'insert cell below',
364 help : 'insert cell below',
365 help_index : 'ed',
365 help_index : 'ed',
366 handler : function (event) {
366 handler : function (event) {
367 IPython.notebook.insert_cell_below('code');
367 IPython.notebook.insert_cell_below('code');
368 IPython.notebook.select_next();
368 IPython.notebook.select_next();
369 IPython.notebook.focus_cell();
369 IPython.notebook.focus_cell();
370 return false;
370 return false;
371 }
371 }
372 },
372 },
373 'y' : {
373 'y' : {
374 help : 'to code',
374 help : 'to code',
375 help_index : 'ca',
375 help_index : 'ca',
376 handler : function (event) {
376 handler : function (event) {
377 IPython.notebook.to_code();
377 IPython.notebook.to_code();
378 return false;
378 return false;
379 }
379 }
380 },
380 },
381 'm' : {
381 'm' : {
382 help : 'to markdown',
382 help : 'to markdown',
383 help_index : 'cb',
383 help_index : 'cb',
384 handler : function (event) {
384 handler : function (event) {
385 IPython.notebook.to_markdown();
385 IPython.notebook.to_markdown();
386 return false;
386 return false;
387 }
387 }
388 },
388 },
389 'r' : {
389 'r' : {
390 help : 'to raw',
390 help : 'to raw',
391 help_index : 'cc',
391 help_index : 'cc',
392 handler : function (event) {
392 handler : function (event) {
393 IPython.notebook.to_raw();
393 IPython.notebook.to_raw();
394 return false;
394 return false;
395 }
395 }
396 },
396 },
397 '1' : {
397 '1' : {
398 help : 'to heading 1',
398 help : 'to heading 1',
399 help_index : 'cd',
399 help_index : 'cd',
400 handler : function (event) {
400 handler : function (event) {
401 IPython.notebook.to_heading(undefined, 1);
401 IPython.notebook.to_heading(undefined, 1);
402 return false;
402 return false;
403 }
403 }
404 },
404 },
405 '2' : {
405 '2' : {
406 help : 'to heading 2',
406 help : 'to heading 2',
407 help_index : 'ce',
407 help_index : 'ce',
408 handler : function (event) {
408 handler : function (event) {
409 IPython.notebook.to_heading(undefined, 2);
409 IPython.notebook.to_heading(undefined, 2);
410 return false;
410 return false;
411 }
411 }
412 },
412 },
413 '3' : {
413 '3' : {
414 help : 'to heading 3',
414 help : 'to heading 3',
415 help_index : 'cf',
415 help_index : 'cf',
416 handler : function (event) {
416 handler : function (event) {
417 IPython.notebook.to_heading(undefined, 3);
417 IPython.notebook.to_heading(undefined, 3);
418 return false;
418 return false;
419 }
419 }
420 },
420 },
421 '4' : {
421 '4' : {
422 help : 'to heading 4',
422 help : 'to heading 4',
423 help_index : 'cg',
423 help_index : 'cg',
424 handler : function (event) {
424 handler : function (event) {
425 IPython.notebook.to_heading(undefined, 4);
425 IPython.notebook.to_heading(undefined, 4);
426 return false;
426 return false;
427 }
427 }
428 },
428 },
429 '5' : {
429 '5' : {
430 help : 'to heading 5',
430 help : 'to heading 5',
431 help_index : 'ch',
431 help_index : 'ch',
432 handler : function (event) {
432 handler : function (event) {
433 IPython.notebook.to_heading(undefined, 5);
433 IPython.notebook.to_heading(undefined, 5);
434 return false;
434 return false;
435 }
435 }
436 },
436 },
437 '6' : {
437 '6' : {
438 help : 'to heading 6',
438 help : 'to heading 6',
439 help_index : 'ci',
439 help_index : 'ci',
440 handler : function (event) {
440 handler : function (event) {
441 IPython.notebook.to_heading(undefined, 6);
441 IPython.notebook.to_heading(undefined, 6);
442 return false;
442 return false;
443 }
443 }
444 },
444 },
445 'o' : {
445 'o' : {
446 help : 'toggle output',
446 help : 'toggle output',
447 help_index : 'gb',
447 help_index : 'gb',
448 handler : function (event) {
448 handler : function (event) {
449 IPython.notebook.toggle_output();
449 IPython.notebook.toggle_output();
450 return false;
450 return false;
451 }
451 }
452 },
452 },
453 'shift+o' : {
453 'shift+o' : {
454 help : 'toggle output scrolling',
454 help : 'toggle output scrolling',
455 help_index : 'gc',
455 help_index : 'gc',
456 handler : function (event) {
456 handler : function (event) {
457 IPython.notebook.toggle_output_scroll();
457 IPython.notebook.toggle_output_scroll();
458 return false;
458 return false;
459 }
459 }
460 },
460 },
461 's' : {
461 's' : {
462 help : 'save notebook',
462 help : 'save notebook',
463 help_index : 'fa',
463 help_index : 'fa',
464 handler : function (event) {
464 handler : function (event) {
465 IPython.notebook.save_checkpoint();
465 IPython.notebook.save_checkpoint();
466 return false;
466 return false;
467 }
467 }
468 },
468 },
469 'ctrl+j' : {
469 'ctrl+j' : {
470 help : 'move cell down',
470 help : 'move cell down',
471 help_index : 'eb',
471 help_index : 'eb',
472 handler : function (event) {
472 handler : function (event) {
473 IPython.notebook.move_cell_down();
473 IPython.notebook.move_cell_down();
474 return false;
474 return false;
475 }
475 }
476 },
476 },
477 'ctrl+k' : {
477 'ctrl+k' : {
478 help : 'move cell up',
478 help : 'move cell up',
479 help_index : 'ea',
479 help_index : 'ea',
480 handler : function (event) {
480 handler : function (event) {
481 IPython.notebook.move_cell_up();
481 IPython.notebook.move_cell_up();
482 return false;
482 return false;
483 }
483 }
484 },
484 },
485 'l' : {
485 'l' : {
486 help : 'toggle line numbers',
486 help : 'toggle line numbers',
487 help_index : 'ga',
487 help_index : 'ga',
488 handler : function (event) {
488 handler : function (event) {
489 IPython.notebook.cell_toggle_line_numbers();
489 IPython.notebook.cell_toggle_line_numbers();
490 return false;
490 return false;
491 }
491 }
492 },
492 },
493 'i' : {
493 'i' : {
494 help : 'interrupt kernel (press twice)',
494 help : 'interrupt kernel (press twice)',
495 help_index : 'ha',
495 help_index : 'ha',
496 count: 2,
496 count: 2,
497 handler : function (event) {
497 handler : function (event) {
498 IPython.notebook.kernel.interrupt();
498 IPython.notebook.kernel.interrupt();
499 return false;
499 return false;
500 }
500 }
501 },
501 },
502 '0' : {
502 '0' : {
503 help : 'restart kernel (press twice)',
503 help : 'restart kernel (press twice)',
504 help_index : 'hb',
504 help_index : 'hb',
505 count: 2,
505 count: 2,
506 handler : function (event) {
506 handler : function (event) {
507 IPython.notebook.restart_kernel();
507 IPython.notebook.restart_kernel();
508 return false;
508 return false;
509 }
509 }
510 },
510 },
511 'h' : {
511 'h' : {
512 help : 'keyboard shortcuts',
512 help : 'keyboard shortcuts',
513 help_index : 'gd',
513 help_index : 'ge',
514 handler : function (event) {
514 handler : function (event) {
515 IPython.quick_help.show_keyboard_shortcuts();
515 IPython.quick_help.show_keyboard_shortcuts();
516 return false;
516 return false;
517 }
517 }
518 },
518 },
519 'z' : {
519 'z' : {
520 help : 'undo last delete',
520 help : 'undo last delete',
521 help_index : 'ei',
521 help_index : 'ei',
522 handler : function (event) {
522 handler : function (event) {
523 IPython.notebook.undelete_cell();
523 IPython.notebook.undelete_cell();
524 return false;
524 return false;
525 }
525 }
526 },
526 },
527 'shift+m' : {
527 'shift+m' : {
528 help : 'merge cell below',
528 help : 'merge cell below',
529 help_index : 'ek',
529 help_index : 'ek',
530 handler : function (event) {
530 handler : function (event) {
531 IPython.notebook.merge_cell_below();
531 IPython.notebook.merge_cell_below();
532 return false;
532 return false;
533 }
533 }
534 },
534 },
535 'q' : {
536 help : 'close pager',
537 help_index : 'gd',
538 handler : function (event) {
539 IPython.pager.collapse();
540 return false;
541 }
542 },
535 }
543 }
536
544
537
545
538 // Shortcut manager class
546 // Shortcut manager class
539
547
540 var ShortcutManager = function (delay) {
548 var ShortcutManager = function (delay) {
541 this._shortcuts = {}
549 this._shortcuts = {}
542 this._counts = {}
550 this._counts = {}
543 this._timers = {}
551 this._timers = {}
544 this.delay = delay || 800; // delay in milliseconds
552 this.delay = delay || 800; // delay in milliseconds
545 }
553 }
546
554
547 ShortcutManager.prototype.help = function () {
555 ShortcutManager.prototype.help = function () {
548 var help = [];
556 var help = [];
549 for (var shortcut in this._shortcuts) {
557 for (var shortcut in this._shortcuts) {
550 var help_string = this._shortcuts[shortcut]['help'];
558 var help_string = this._shortcuts[shortcut]['help'];
551 var help_index = this._shortcuts[shortcut]['help_index'];
559 var help_index = this._shortcuts[shortcut]['help_index'];
552 if (help_string) {
560 if (help_string) {
553 if (platform === 'MacOS') {
561 if (platform === 'MacOS') {
554 shortcut = shortcut.replace('meta', 'cmd');
562 shortcut = shortcut.replace('meta', 'cmd');
555 }
563 }
556 help.push({
564 help.push({
557 shortcut: shortcut,
565 shortcut: shortcut,
558 help: help_string,
566 help: help_string,
559 help_index: help_index}
567 help_index: help_index}
560 );
568 );
561 }
569 }
562 }
570 }
563 help.sort(function (a, b) {
571 help.sort(function (a, b) {
564 if (a.help_index > b.help_index)
572 if (a.help_index > b.help_index)
565 return 1;
573 return 1;
566 if (a.help_index < b.help_index)
574 if (a.help_index < b.help_index)
567 return -1;
575 return -1;
568 return 0;
576 return 0;
569 });
577 });
570 return help;
578 return help;
571 }
579 }
572
580
573 ShortcutManager.prototype.normalize_key = function (key) {
581 ShortcutManager.prototype.normalize_key = function (key) {
574 return inv_keycodes[keycodes[key]];
582 return inv_keycodes[keycodes[key]];
575 }
583 }
576
584
577 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
585 ShortcutManager.prototype.normalize_shortcut = function (shortcut) {
578 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
586 // Sort a sequence of + separated modifiers into the order alt+ctrl+meta+shift
579 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
587 shortcut = shortcut.replace('cmd', 'meta').toLowerCase();
580 var values = shortcut.split("+");
588 var values = shortcut.split("+");
581 if (values.length === 1) {
589 if (values.length === 1) {
582 return this.normalize_key(values[0])
590 return this.normalize_key(values[0])
583 } else {
591 } else {
584 var modifiers = values.slice(0,-1);
592 var modifiers = values.slice(0,-1);
585 var key = this.normalize_key(values[values.length-1]);
593 var key = this.normalize_key(values[values.length-1]);
586 modifiers.sort();
594 modifiers.sort();
587 return modifiers.join('+') + '+' + key;
595 return modifiers.join('+') + '+' + key;
588 }
596 }
589 }
597 }
590
598
591 ShortcutManager.prototype.event_to_shortcut = function (event) {
599 ShortcutManager.prototype.event_to_shortcut = function (event) {
592 // Convert a jQuery keyboard event to a strong based keyboard shortcut
600 // Convert a jQuery keyboard event to a strong based keyboard shortcut
593 var shortcut = '';
601 var shortcut = '';
594 var key = inv_keycodes[event.which]
602 var key = inv_keycodes[event.which]
595 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
603 if (event.altKey && key !== 'alt') {shortcut += 'alt+';}
596 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
604 if (event.ctrlKey && key !== 'ctrl') {shortcut += 'ctrl+';}
597 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
605 if (event.metaKey && key !== 'meta') {shortcut += 'meta+';}
598 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
606 if (event.shiftKey && key !== 'shift') {shortcut += 'shift+';}
599 shortcut += key;
607 shortcut += key;
600 return shortcut
608 return shortcut
601 }
609 }
602
610
603 ShortcutManager.prototype.clear_shortcuts = function () {
611 ShortcutManager.prototype.clear_shortcuts = function () {
604 this._shortcuts = {};
612 this._shortcuts = {};
605 }
613 }
606
614
607 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
615 ShortcutManager.prototype.add_shortcut = function (shortcut, data) {
608 if (typeof(data) === 'function') {
616 if (typeof(data) === 'function') {
609 data = {help: '', help_index: '', handler: data}
617 data = {help: '', help_index: '', handler: data}
610 }
618 }
611 data.help_index = data.help_index || '';
619 data.help_index = data.help_index || '';
612 data.help = data.help || '';
620 data.help = data.help || '';
613 data.count = data.count || 1;
621 data.count = data.count || 1;
614 if (data.help_index === '') {
622 if (data.help_index === '') {
615 data.help_index = 'zz';
623 data.help_index = 'zz';
616 }
624 }
617 shortcut = this.normalize_shortcut(shortcut);
625 shortcut = this.normalize_shortcut(shortcut);
618 this._counts[shortcut] = 0;
626 this._counts[shortcut] = 0;
619 this._shortcuts[shortcut] = data;
627 this._shortcuts[shortcut] = data;
620 }
628 }
621
629
622 ShortcutManager.prototype.add_shortcuts = function (data) {
630 ShortcutManager.prototype.add_shortcuts = function (data) {
623 for (var shortcut in data) {
631 for (var shortcut in data) {
624 this.add_shortcut(shortcut, data[shortcut]);
632 this.add_shortcut(shortcut, data[shortcut]);
625 }
633 }
626 }
634 }
627
635
628 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
636 ShortcutManager.prototype.remove_shortcut = function (shortcut) {
629 shortcut = this.normalize_shortcut(shortcut);
637 shortcut = this.normalize_shortcut(shortcut);
630 delete this._counts[shortcut];
638 delete this._counts[shortcut];
631 delete this._shortcuts[shortcut];
639 delete this._shortcuts[shortcut];
632 }
640 }
633
641
634 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
642 ShortcutManager.prototype.count_handler = function (shortcut, event, data) {
635 var that = this;
643 var that = this;
636 var c = this._counts;
644 var c = this._counts;
637 var t = this._timers;
645 var t = this._timers;
638 var timer = null;
646 var timer = null;
639 if (c[shortcut] === data.count-1) {
647 if (c[shortcut] === data.count-1) {
640 c[shortcut] = 0;
648 c[shortcut] = 0;
641 var timer = t[shortcut];
649 var timer = t[shortcut];
642 if (timer) {clearTimeout(timer); delete t[shortcut];}
650 if (timer) {clearTimeout(timer); delete t[shortcut];}
643 return data.handler(event);
651 return data.handler(event);
644 } else {
652 } else {
645 c[shortcut] = c[shortcut] + 1;
653 c[shortcut] = c[shortcut] + 1;
646 timer = setTimeout(function () {
654 timer = setTimeout(function () {
647 c[shortcut] = 0;
655 c[shortcut] = 0;
648 }, that.delay);
656 }, that.delay);
649 t[shortcut] = timer;
657 t[shortcut] = timer;
650 }
658 }
651 return false;
659 return false;
652 }
660 }
653
661
654 ShortcutManager.prototype.call_handler = function (event) {
662 ShortcutManager.prototype.call_handler = function (event) {
655 var shortcut = this.event_to_shortcut(event);
663 var shortcut = this.event_to_shortcut(event);
656 var data = this._shortcuts[shortcut];
664 var data = this._shortcuts[shortcut];
657 if (data) {
665 if (data) {
658 var handler = data['handler'];
666 var handler = data['handler'];
659 if (handler) {
667 if (handler) {
660 if (data.count === 1) {
668 if (data.count === 1) {
661 return handler(event);
669 return handler(event);
662 } else if (data.count > 1) {
670 } else if (data.count > 1) {
663 return this.count_handler(shortcut, event, data);
671 return this.count_handler(shortcut, event, data);
664 }
672 }
665 }
673 }
666 }
674 }
667 return true;
675 return true;
668 }
676 }
669
677
670
678
671
679
672 // Main keyboard manager for the notebook
680 // Main keyboard manager for the notebook
673
681
674 var KeyboardManager = function () {
682 var KeyboardManager = function () {
675 this.mode = 'command';
683 this.mode = 'command';
676 this.enabled = true;
684 this.enabled = true;
677 this.bind_events();
685 this.bind_events();
678 this.command_shortcuts = new ShortcutManager();
686 this.command_shortcuts = new ShortcutManager();
679 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
687 this.command_shortcuts.add_shortcuts(default_common_shortcuts);
680 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
688 this.command_shortcuts.add_shortcuts(default_command_shortcuts);
681 this.edit_shortcuts = new ShortcutManager();
689 this.edit_shortcuts = new ShortcutManager();
682 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
690 this.edit_shortcuts.add_shortcuts(default_common_shortcuts);
683 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
691 this.edit_shortcuts.add_shortcuts(default_edit_shortcuts);
684 };
692 };
685
693
686 KeyboardManager.prototype.bind_events = function () {
694 KeyboardManager.prototype.bind_events = function () {
687 var that = this;
695 var that = this;
688 $(document).keydown(function (event) {
696 $(document).keydown(function (event) {
689 return that.handle_keydown(event);
697 return that.handle_keydown(event);
690 });
698 });
691 };
699 };
692
700
693 KeyboardManager.prototype.handle_keydown = function (event) {
701 KeyboardManager.prototype.handle_keydown = function (event) {
694 var notebook = IPython.notebook;
702 var notebook = IPython.notebook;
695
703
696 if (event.which === keycodes['esc']) {
704 if (event.which === keycodes['esc']) {
697 // Intercept escape at highest level to avoid closing
705 // Intercept escape at highest level to avoid closing
698 // websocket connection with firefox
706 // websocket connection with firefox
699 event.preventDefault();
707 event.preventDefault();
700 }
708 }
701
709
702 if (!this.enabled) {
710 if (!this.enabled) {
703 if (event.which === keycodes['esc']) {
711 if (event.which === keycodes['esc']) {
704 // ESC
712 // ESC
705 notebook.command_mode();
713 notebook.command_mode();
706 return false;
714 return false;
707 }
715 }
708 return true;
716 return true;
709 }
717 }
710
718
711 if (this.mode === 'edit') {
719 if (this.mode === 'edit') {
712 return this.edit_shortcuts.call_handler(event);
720 return this.edit_shortcuts.call_handler(event);
713 } else if (this.mode === 'command') {
721 } else if (this.mode === 'command') {
714 return this.command_shortcuts.call_handler(event);
722 return this.command_shortcuts.call_handler(event);
715 }
723 }
716 return true;
724 return true;
717 }
725 }
718
726
719 KeyboardManager.prototype.edit_mode = function () {
727 KeyboardManager.prototype.edit_mode = function () {
720 this.last_mode = this.mode;
728 this.last_mode = this.mode;
721 this.mode = 'edit';
729 this.mode = 'edit';
722 }
730 }
723
731
724 KeyboardManager.prototype.command_mode = function () {
732 KeyboardManager.prototype.command_mode = function () {
725 this.last_mode = this.mode;
733 this.last_mode = this.mode;
726 this.mode = 'command';
734 this.mode = 'command';
727 }
735 }
728
736
729 KeyboardManager.prototype.enable = function () {
737 KeyboardManager.prototype.enable = function () {
730 this.enabled = true;
738 this.enabled = true;
731 }
739 }
732
740
733 KeyboardManager.prototype.disable = function () {
741 KeyboardManager.prototype.disable = function () {
734 this.enabled = false;
742 this.enabled = false;
735 }
743 }
736
744
737 KeyboardManager.prototype.register_events = function (e) {
745 KeyboardManager.prototype.register_events = function (e) {
738 var that = this;
746 var that = this;
739 e.on('focusin', function () {
747 e.on('focusin', function () {
740 that.disable();
748 that.disable();
741 });
749 });
742 e.on('focusout', function () {
750 e.on('focusout', function () {
743 that.enable();
751 that.enable();
744 });
752 });
745 // There are times (raw_input) where we remove the element from the DOM before
753 // There are times (raw_input) where we remove the element from the DOM before
746 // focusout is called. In this case we bind to the remove event of jQueryUI,
754 // focusout is called. In this case we bind to the remove event of jQueryUI,
747 // which gets triggered upon removal.
755 // which gets triggered upon removal.
748 e.on('remove', function () {
756 e.on('remove', function () {
749 that.enable();
757 that.enable();
750 });
758 });
751 }
759 }
752
760
753
761
754 IPython.keycodes = keycodes;
762 IPython.keycodes = keycodes;
755 IPython.inv_keycodes = inv_keycodes;
763 IPython.inv_keycodes = inv_keycodes;
756 IPython.default_common_shortcuts = default_common_shortcuts;
764 IPython.default_common_shortcuts = default_common_shortcuts;
757 IPython.default_edit_shortcuts = default_edit_shortcuts;
765 IPython.default_edit_shortcuts = default_edit_shortcuts;
758 IPython.default_command_shortcuts = default_command_shortcuts;
766 IPython.default_command_shortcuts = default_command_shortcuts;
759 IPython.ShortcutManager = ShortcutManager;
767 IPython.ShortcutManager = ShortcutManager;
760 IPython.KeyboardManager = KeyboardManager;
768 IPython.KeyboardManager = KeyboardManager;
761
769
762 return IPython;
770 return IPython;
763
771
764 }(IPython));
772 }(IPython));
@@ -1,128 +1,122 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // On document ready
9 // On document ready
10 //============================================================================
10 //============================================================================
11 "use strict";
12
11
13 // for the time beeing, we have to pass marked as a parameter here,
12 // for the time beeing, we have to pass marked as a parameter here,
14 // as injecting require.js make marked not to put itself in the globals,
13 // as injecting require.js make marked not to put itself in the globals,
15 // which make both this file fail at setting marked configuration, and textcell.js
14 // which make both this file fail at setting marked configuration, and textcell.js
16 // which search marked into global.
15 // which search marked into global.
17 require(['components/marked/lib/marked',
16 require(['components/marked/lib/marked',
18 'notebook/js/widgets/init'],
17 'notebook/js/widgets/init'],
19
18
20 function (marked) {
19 function (marked) {
20 "use strict";
21
21
22 window.marked = marked
22 window.marked = marked;
23
23
24 // monkey patch CM to be able to syntax highlight cell magics
24 // monkey patch CM to be able to syntax highlight cell magics
25 // bug reported upstream,
25 // bug reported upstream,
26 // see https://github.com/marijnh/CodeMirror2/issues/670
26 // see https://github.com/marijnh/CodeMirror2/issues/670
27 if(CodeMirror.getMode(1,'text/plain').indent == undefined ){
27 if(CodeMirror.getMode(1,'text/plain').indent === undefined ){
28 console.log('patching CM for undefined indent');
28 console.log('patching CM for undefined indent');
29 CodeMirror.modes.null = function() {
29 CodeMirror.modes.null = function() {
30 return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0}}
30 return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0;}};
31 }
31 };
32 }
32 }
33
33
34 CodeMirror.patchedGetMode = function(config, mode){
34 CodeMirror.patchedGetMode = function(config, mode){
35 var cmmode = CodeMirror.getMode(config, mode);
35 var cmmode = CodeMirror.getMode(config, mode);
36 if(cmmode.indent == null)
36 if(cmmode.indent === null) {
37 {
38 console.log('patch mode "' , mode, '" on the fly');
37 console.log('patch mode "' , mode, '" on the fly');
39 cmmode.indent = function(){return 0};
38 cmmode.indent = function(){return 0;};
40 }
39 }
41 return cmmode;
40 return cmmode;
42 }
41 };
43 // end monkey patching CodeMirror
42 // end monkey patching CodeMirror
44
43
45 IPython.mathjaxutils.init();
44 IPython.mathjaxutils.init();
46
45
47 $('#ipython-main-app').addClass('border-box-sizing');
46 $('#ipython-main-app').addClass('border-box-sizing');
48 $('div#notebook_panel').addClass('border-box-sizing');
47 $('div#notebook_panel').addClass('border-box-sizing');
49
48
50 var baseProjectUrl = $('body').data('baseProjectUrl');
49 var opts = {
51 var notebookPath = $('body').data('notebookPath');
50 base_url : IPython.utils.get_body_data("baseUrl"),
52 var notebookName = $('body').data('notebookName');
51 base_kernel_url : IPython.utils.get_body_data("baseKernelUrl"),
53 notebookName = decodeURIComponent(notebookName);
52 notebook_path : IPython.utils.get_body_data("notebookPath"),
54 notebookPath = decodeURIComponent(notebookPath);
53 notebook_name : IPython.utils.get_body_data('notebookName')
55 console.log(notebookName);
54 };
56 if (notebookPath == 'None'){
57 notebookPath = "";
58 }
59
55
60 IPython.page = new IPython.Page();
56 IPython.page = new IPython.Page();
61 IPython.layout_manager = new IPython.LayoutManager();
57 IPython.layout_manager = new IPython.LayoutManager();
62 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
58 IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
63 IPython.quick_help = new IPython.QuickHelp();
59 IPython.quick_help = new IPython.QuickHelp();
64 IPython.login_widget = new IPython.LoginWidget('span#login_widget',{baseProjectUrl:baseProjectUrl});
60 IPython.login_widget = new IPython.LoginWidget('span#login_widget', opts);
65 IPython.notebook = new IPython.Notebook('div#notebook',{baseProjectUrl:baseProjectUrl, notebookPath:notebookPath, notebookName:notebookName});
61 IPython.notebook = new IPython.Notebook('div#notebook', opts);
66 IPython.keyboard_manager = new IPython.KeyboardManager();
62 IPython.keyboard_manager = new IPython.KeyboardManager();
67 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
63 IPython.save_widget = new IPython.SaveWidget('span#save_widget');
68 IPython.menubar = new IPython.MenuBar('#menubar',{baseProjectUrl:baseProjectUrl, notebookPath: notebookPath})
64 IPython.menubar = new IPython.MenuBar('#menubar', opts);
69 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container')
65 IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container');
70 IPython.tooltip = new IPython.Tooltip()
66 IPython.tooltip = new IPython.Tooltip();
71 IPython.notification_area = new IPython.NotificationArea('#notification_area')
67 IPython.notification_area = new IPython.NotificationArea('#notification_area');
72 IPython.notification_area.init_notification_widgets();
68 IPython.notification_area.init_notification_widgets();
73
69
74 IPython.layout_manager.do_resize();
70 IPython.layout_manager.do_resize();
75
71
76 $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+
72 $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+
77 '<span id="test2" style="font-weight: bold;">x</span>'+
73 '<span id="test2" style="font-weight: bold;">x</span>'+
78 '<span id="test3" style="font-style: italic;">x</span></pre></div>')
74 '<span id="test3" style="font-style: italic;">x</span></pre></div>');
79 var nh = $('#test1').innerHeight();
75 var nh = $('#test1').innerHeight();
80 var bh = $('#test2').innerHeight();
76 var bh = $('#test2').innerHeight();
81 var ih = $('#test3').innerHeight();
77 var ih = $('#test3').innerHeight();
82 if(nh != bh || nh != ih) {
78 if(nh != bh || nh != ih) {
83 $('head').append('<style>.CodeMirror span { vertical-align: bottom; }</style>');
79 $('head').append('<style>.CodeMirror span { vertical-align: bottom; }</style>');
84 }
80 }
85 $('#fonttest').remove();
81 $('#fonttest').remove();
86
82
87 IPython.page.show();
83 IPython.page.show();
88
84
89 IPython.layout_manager.do_resize();
85 IPython.layout_manager.do_resize();
90 var first_load = function () {
86 var first_load = function () {
91 IPython.layout_manager.do_resize();
87 IPython.layout_manager.do_resize();
92 var hash = document.location.hash;
88 var hash = document.location.hash;
93 if (hash) {
89 if (hash) {
94 document.location.hash = '';
90 document.location.hash = '';
95 document.location.hash = hash;
91 document.location.hash = hash;
96 }
92 }
97 IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval);
93 IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval);
98 // only do this once
94 // only do this once
99 $([IPython.events]).off('notebook_loaded.Notebook', first_load);
95 $([IPython.events]).off('notebook_loaded.Notebook', first_load);
100 };
96 };
101
97
102 $([IPython.events]).on('notebook_loaded.Notebook', first_load);
98 $([IPython.events]).on('notebook_loaded.Notebook', first_load);
103 $([IPython.events]).trigger('app_initialized.NotebookApp');
99 $([IPython.events]).trigger('app_initialized.NotebookApp');
104 IPython.notebook.load_notebook(notebookName, notebookPath);
100 IPython.notebook.load_notebook(opts.notebook_name, opts.notebook_path);
105
101
106 if (marked) {
102 if (marked) {
107 marked.setOptions({
103 marked.setOptions({
108 gfm : true,
104 gfm : true,
109 tables: true,
105 tables: true,
110 langPrefix: "language-",
106 langPrefix: "language-",
111 highlight: function(code, lang) {
107 highlight: function(code, lang) {
112 if (!lang) {
108 if (!lang) {
113 // no language, no highlight
109 // no language, no highlight
114 return code;
110 return code;
115 }
111 }
116 var highlighted;
112 var highlighted;
117 try {
113 try {
118 highlighted = hljs.highlight(lang, code, false);
114 highlighted = hljs.highlight(lang, code, false);
119 } catch(err) {
115 } catch(err) {
120 highlighted = hljs.highlightAuto(code);
116 highlighted = hljs.highlightAuto(code);
121 }
117 }
122 return highlighted.value;
118 return highlighted.value;
123 }
119 }
124 })
120 });
125 }
121 }
126 }
122 });
127
128 );
@@ -1,213 +1,214 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // ToolBar
9 // ToolBar
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var MainToolBar = function (selector) {
15 var MainToolBar = function (selector) {
16 IPython.ToolBar.apply(this, arguments);
16 IPython.ToolBar.apply(this, arguments);
17 this.construct();
17 this.construct();
18 this.add_celltype_list();
18 this.add_celltype_list();
19 this.add_celltoolbar_list();
19 this.add_celltoolbar_list();
20 this.bind_events();
20 this.bind_events();
21 };
21 };
22
22
23 MainToolBar.prototype = new IPython.ToolBar();
23 MainToolBar.prototype = new IPython.ToolBar();
24
24
25 MainToolBar.prototype.construct = function () {
25 MainToolBar.prototype.construct = function () {
26 this.add_buttons_group([
26 this.add_buttons_group([
27 {
27 {
28 id : 'save_b',
28 id : 'save_b',
29 label : 'Save and Checkpoint',
29 label : 'Save and Checkpoint',
30 icon : 'icon-save',
30 icon : 'icon-save',
31 callback : function () {
31 callback : function () {
32 IPython.notebook.save_checkpoint();
32 IPython.notebook.save_checkpoint();
33 }
33 }
34 }
34 }
35 ]);
35 ]);
36
36
37 this.add_buttons_group([
37 this.add_buttons_group([
38 {
38 {
39 id : 'insert_below_b',
39 id : 'insert_below_b',
40 label : 'Insert Cell Below',
40 label : 'Insert Cell Below',
41 icon : 'icon-plus-sign',
41 icon : 'icon-plus-sign',
42 callback : function () {
42 callback : function () {
43 IPython.notebook.insert_cell_below('code');
43 IPython.notebook.insert_cell_below('code');
44 IPython.notebook.select_next();
44 IPython.notebook.select_next();
45 IPython.notebook.focus_cell();
45 IPython.notebook.focus_cell();
46 }
46 }
47 }
47 }
48 ],'insert_above_below');
48 ],'insert_above_below');
49
49
50 this.add_buttons_group([
50 this.add_buttons_group([
51 {
51 {
52 id : 'cut_b',
52 id : 'cut_b',
53 label : 'Cut Cell',
53 label : 'Cut Cell',
54 icon : 'icon-cut',
54 icon : 'icon-cut',
55 callback : function () {
55 callback : function () {
56 IPython.notebook.cut_cell();
56 IPython.notebook.cut_cell();
57 }
57 }
58 },
58 },
59 {
59 {
60 id : 'copy_b',
60 id : 'copy_b',
61 label : 'Copy Cell',
61 label : 'Copy Cell',
62 icon : 'icon-copy',
62 icon : 'icon-copy',
63 callback : function () {
63 callback : function () {
64 IPython.notebook.copy_cell();
64 IPython.notebook.copy_cell();
65 }
65 }
66 },
66 },
67 {
67 {
68 id : 'paste_b',
68 id : 'paste_b',
69 label : 'Paste Cell Below',
69 label : 'Paste Cell Below',
70 icon : 'icon-paste',
70 icon : 'icon-paste',
71 callback : function () {
71 callback : function () {
72 IPython.notebook.paste_cell_below();
72 IPython.notebook.paste_cell_below();
73 }
73 }
74 }
74 }
75 ],'cut_copy_paste');
75 ],'cut_copy_paste');
76
76
77 this.add_buttons_group([
77 this.add_buttons_group([
78 {
78 {
79 id : 'move_up_b',
79 id : 'move_up_b',
80 label : 'Move Cell Up',
80 label : 'Move Cell Up',
81 icon : 'icon-arrow-up',
81 icon : 'icon-arrow-up',
82 callback : function () {
82 callback : function () {
83 IPython.notebook.move_cell_up();
83 IPython.notebook.move_cell_up();
84 }
84 }
85 },
85 },
86 {
86 {
87 id : 'move_down_b',
87 id : 'move_down_b',
88 label : 'Move Cell Down',
88 label : 'Move Cell Down',
89 icon : 'icon-arrow-down',
89 icon : 'icon-arrow-down',
90 callback : function () {
90 callback : function () {
91 IPython.notebook.move_cell_down();
91 IPython.notebook.move_cell_down();
92 }
92 }
93 }
93 }
94 ],'move_up_down');
94 ],'move_up_down');
95
95
96
96
97 this.add_buttons_group([
97 this.add_buttons_group([
98 {
98 {
99 id : 'run_b',
99 id : 'run_b',
100 label : 'Run Cell',
100 label : 'Run Cell',
101 icon : 'icon-play',
101 icon : 'icon-play',
102 callback : function () {
102 callback : function () {
103 IPython.notebook.execute_cell();
103 // emulate default shift-enter behavior
104 }
104 IPython.notebook.execute_cell_and_select_below();
105 }
105 },
106 },
106 {
107 {
107 id : 'interrupt_b',
108 id : 'interrupt_b',
108 label : 'Interrupt',
109 label : 'Interrupt',
109 icon : 'icon-stop',
110 icon : 'icon-stop',
110 callback : function () {
111 callback : function () {
111 IPython.notebook.session.interrupt_kernel();
112 IPython.notebook.session.interrupt_kernel();
112 }
113 }
113 },
114 },
114 {
115 {
115 id : 'repeat_b',
116 id : 'repeat_b',
116 label : 'Restart Kernel',
117 label : 'Restart Kernel',
117 icon : 'icon-repeat',
118 icon : 'icon-repeat',
118 callback : function () {
119 callback : function () {
119 IPython.notebook.restart_kernel();
120 IPython.notebook.restart_kernel();
120 }
121 }
121 }
122 }
122 ],'run_int');
123 ],'run_int');
123 };
124 };
124
125
125 MainToolBar.prototype.add_celltype_list = function () {
126 MainToolBar.prototype.add_celltype_list = function () {
126 this.element
127 this.element
127 .append($('<select/>')
128 .append($('<select/>')
128 .attr('id','cell_type')
129 .attr('id','cell_type')
129 // .addClass('ui-widget-content')
130 // .addClass('ui-widget-content')
130 .append($('<option/>').attr('value','code').text('Code'))
131 .append($('<option/>').attr('value','code').text('Code'))
131 .append($('<option/>').attr('value','markdown').text('Markdown'))
132 .append($('<option/>').attr('value','markdown').text('Markdown'))
132 .append($('<option/>').attr('value','raw').text('Raw NBConvert'))
133 .append($('<option/>').attr('value','raw').text('Raw NBConvert'))
133 .append($('<option/>').attr('value','heading1').text('Heading 1'))
134 .append($('<option/>').attr('value','heading1').text('Heading 1'))
134 .append($('<option/>').attr('value','heading2').text('Heading 2'))
135 .append($('<option/>').attr('value','heading2').text('Heading 2'))
135 .append($('<option/>').attr('value','heading3').text('Heading 3'))
136 .append($('<option/>').attr('value','heading3').text('Heading 3'))
136 .append($('<option/>').attr('value','heading4').text('Heading 4'))
137 .append($('<option/>').attr('value','heading4').text('Heading 4'))
137 .append($('<option/>').attr('value','heading5').text('Heading 5'))
138 .append($('<option/>').attr('value','heading5').text('Heading 5'))
138 .append($('<option/>').attr('value','heading6').text('Heading 6'))
139 .append($('<option/>').attr('value','heading6').text('Heading 6'))
139 );
140 );
140 };
141 };
141
142
142
143
143 MainToolBar.prototype.add_celltoolbar_list = function () {
144 MainToolBar.prototype.add_celltoolbar_list = function () {
144 var label = $('<span/>').addClass("navbar-text").text('Cell Toolbar:');
145 var label = $('<span/>').addClass("navbar-text").text('Cell Toolbar:');
145 var select = $('<select/>')
146 var select = $('<select/>')
146 // .addClass('ui-widget-content')
147 // .addClass('ui-widget-content')
147 .attr('id', 'ctb_select')
148 .attr('id', 'ctb_select')
148 .append($('<option/>').attr('value', '').text('None'));
149 .append($('<option/>').attr('value', '').text('None'));
149 this.element.append(label).append(select);
150 this.element.append(label).append(select);
150 select.change(function() {
151 select.change(function() {
151 var val = $(this).val()
152 var val = $(this).val()
152 if (val =='') {
153 if (val =='') {
153 IPython.CellToolbar.global_hide();
154 IPython.CellToolbar.global_hide();
154 delete IPython.notebook.metadata.celltoolbar;
155 delete IPython.notebook.metadata.celltoolbar;
155 } else {
156 } else {
156 IPython.CellToolbar.global_show();
157 IPython.CellToolbar.global_show();
157 IPython.CellToolbar.activate_preset(val);
158 IPython.CellToolbar.activate_preset(val);
158 IPython.notebook.metadata.celltoolbar = val;
159 IPython.notebook.metadata.celltoolbar = val;
159 }
160 }
160 });
161 });
161 // Setup the currently registered presets.
162 // Setup the currently registered presets.
162 var presets = IPython.CellToolbar.list_presets();
163 var presets = IPython.CellToolbar.list_presets();
163 for (var i=0; i<presets.length; i++) {
164 for (var i=0; i<presets.length; i++) {
164 var name = presets[i];
165 var name = presets[i];
165 select.append($('<option/>').attr('value', name).text(name));
166 select.append($('<option/>').attr('value', name).text(name));
166 }
167 }
167 // Setup future preset registrations.
168 // Setup future preset registrations.
168 $([IPython.events]).on('preset_added.CellToolbar', function (event, data) {
169 $([IPython.events]).on('preset_added.CellToolbar', function (event, data) {
169 var name = data.name;
170 var name = data.name;
170 select.append($('<option/>').attr('value', name).text(name));
171 select.append($('<option/>').attr('value', name).text(name));
171 });
172 });
172 };
173 };
173
174
174
175
175 MainToolBar.prototype.bind_events = function () {
176 MainToolBar.prototype.bind_events = function () {
176 var that = this;
177 var that = this;
177
178
178 this.element.find('#cell_type').change(function () {
179 this.element.find('#cell_type').change(function () {
179 var cell_type = $(this).val();
180 var cell_type = $(this).val();
180 if (cell_type === 'code') {
181 if (cell_type === 'code') {
181 IPython.notebook.to_code();
182 IPython.notebook.to_code();
182 } else if (cell_type === 'markdown') {
183 } else if (cell_type === 'markdown') {
183 IPython.notebook.to_markdown();
184 IPython.notebook.to_markdown();
184 } else if (cell_type === 'raw') {
185 } else if (cell_type === 'raw') {
185 IPython.notebook.to_raw();
186 IPython.notebook.to_raw();
186 } else if (cell_type === 'heading1') {
187 } else if (cell_type === 'heading1') {
187 IPython.notebook.to_heading(undefined, 1);
188 IPython.notebook.to_heading(undefined, 1);
188 } else if (cell_type === 'heading2') {
189 } else if (cell_type === 'heading2') {
189 IPython.notebook.to_heading(undefined, 2);
190 IPython.notebook.to_heading(undefined, 2);
190 } else if (cell_type === 'heading3') {
191 } else if (cell_type === 'heading3') {
191 IPython.notebook.to_heading(undefined, 3);
192 IPython.notebook.to_heading(undefined, 3);
192 } else if (cell_type === 'heading4') {
193 } else if (cell_type === 'heading4') {
193 IPython.notebook.to_heading(undefined, 4);
194 IPython.notebook.to_heading(undefined, 4);
194 } else if (cell_type === 'heading5') {
195 } else if (cell_type === 'heading5') {
195 IPython.notebook.to_heading(undefined, 5);
196 IPython.notebook.to_heading(undefined, 5);
196 } else if (cell_type === 'heading6') {
197 } else if (cell_type === 'heading6') {
197 IPython.notebook.to_heading(undefined, 6);
198 IPython.notebook.to_heading(undefined, 6);
198 }
199 }
199 });
200 });
200 $([IPython.events]).on('selected_cell_type_changed.Notebook', function (event, data) {
201 $([IPython.events]).on('selected_cell_type_changed.Notebook', function (event, data) {
201 if (data.cell_type === 'heading') {
202 if (data.cell_type === 'heading') {
202 that.element.find('#cell_type').val(data.cell_type+data.level);
203 that.element.find('#cell_type').val(data.cell_type+data.level);
203 } else {
204 } else {
204 that.element.find('#cell_type').val(data.cell_type);
205 that.element.find('#cell_type').val(data.cell_type);
205 }
206 }
206 });
207 });
207 };
208 };
208
209
209 IPython.MainToolBar = MainToolBar;
210 IPython.MainToolBar = MainToolBar;
210
211
211 return IPython;
212 return IPython;
212
213
213 }(IPython));
214 }(IPython));
@@ -1,327 +1,318 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 // MenuBar
9 // MenuBar
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule MenuBar
15 * @submodule MenuBar
16 */
16 */
17
17
18
18
19 var IPython = (function (IPython) {
19 var IPython = (function (IPython) {
20 "use strict";
20 "use strict";
21
21
22 var utils = IPython.utils;
22 var utils = IPython.utils;
23
23
24 /**
24 /**
25 * A MenuBar Class to generate the menubar of IPython notebook
25 * A MenuBar Class to generate the menubar of IPython notebook
26 * @Class MenuBar
26 * @Class MenuBar
27 *
27 *
28 * @constructor
28 * @constructor
29 *
29 *
30 *
30 *
31 * @param selector {string} selector for the menubar element in DOM
31 * @param selector {string} selector for the menubar element in DOM
32 * @param {object} [options]
32 * @param {object} [options]
33 * @param [options.baseProjectUrl] {String} String to use for the
33 * @param [options.base_url] {String} String to use for the
34 * Base Project url, default would be to inspect
34 * base project url. Default is to inspect
35 * $('body').data('baseProjectUrl');
35 * $('body').data('baseUrl');
36 * does not support change for now is set through this option
36 * does not support change for now is set through this option
37 */
37 */
38 var MenuBar = function (selector, options) {
38 var MenuBar = function (selector, options) {
39 options = options || {};
39 options = options || {};
40 if (options.baseProjectUrl !== undefined) {
40 this.base_url = options.base_url || IPython.utils.get_body_data("baseUrl");
41 this._baseProjectUrl = options.baseProjectUrl;
42 }
43 this.selector = selector;
41 this.selector = selector;
44 if (this.selector !== undefined) {
42 if (this.selector !== undefined) {
45 this.element = $(selector);
43 this.element = $(selector);
46 this.style();
44 this.style();
47 this.bind_events();
45 this.bind_events();
48 }
46 }
49 };
47 };
50
48
51 MenuBar.prototype.baseProjectUrl = function(){
52 return this._baseProjectUrl || $('body').data('baseProjectUrl');
53 };
54
55 MenuBar.prototype.notebookPath = function() {
56 var path = $('body').data('notebookPath');
57 path = decodeURIComponent(path);
58 return path;
59 };
60
61 MenuBar.prototype.style = function () {
49 MenuBar.prototype.style = function () {
62 this.element.addClass('border-box-sizing');
50 this.element.addClass('border-box-sizing');
63 this.element.find("li").click(function (event, ui) {
51 this.element.find("li").click(function (event, ui) {
64 // The selected cell loses focus when the menu is entered, so we
52 // The selected cell loses focus when the menu is entered, so we
65 // re-select it upon selection.
53 // re-select it upon selection.
66 var i = IPython.notebook.get_selected_index();
54 var i = IPython.notebook.get_selected_index();
67 IPython.notebook.select(i);
55 IPython.notebook.select(i);
68 }
56 }
69 );
57 );
70 };
58 };
71
59
72 MenuBar.prototype._nbconvert = function (format, download) {
60 MenuBar.prototype._nbconvert = function (format, download) {
73 download = download || false;
61 download = download || false;
74 var notebook_name = IPython.notebook.get_notebook_name();
62 var notebook_path = IPython.notebook.notebook_path;
63 var notebook_name = IPython.notebook.notebook_name;
75 if (IPython.notebook.dirty) {
64 if (IPython.notebook.dirty) {
76 IPython.notebook.save_notebook({async : false});
65 IPython.notebook.save_notebook({async : false});
77 }
66 }
78 var url = utils.url_path_join(
67 var url = utils.url_join_encode(
79 this.baseProjectUrl(),
68 this.base_url,
80 'nbconvert',
69 'nbconvert',
81 format,
70 format,
82 this.notebookPath(),
71 notebook_path,
83 notebook_name + '.ipynb'
72 notebook_name
84 ) + "?download=" + download.toString();
73 ) + "?download=" + download.toString();
85
74
86 window.open(url);
75 window.open(url);
87 }
76 };
88
77
89 MenuBar.prototype.bind_events = function () {
78 MenuBar.prototype.bind_events = function () {
90 // File
79 // File
91 var that = this;
80 var that = this;
92 this.element.find('#new_notebook').click(function () {
81 this.element.find('#new_notebook').click(function () {
93 IPython.notebook.new_notebook();
82 IPython.notebook.new_notebook();
94 });
83 });
95 this.element.find('#open_notebook').click(function () {
84 this.element.find('#open_notebook').click(function () {
96 window.open(utils.url_join_encode(
85 window.open(utils.url_join_encode(
97 that.baseProjectUrl(),
86 IPython.notebook.base_url,
98 'tree',
87 'tree',
99 that.notebookPath()
88 IPython.notebook.notebook_path
100 ));
89 ));
101 });
90 });
102 this.element.find('#copy_notebook').click(function () {
91 this.element.find('#copy_notebook').click(function () {
103 IPython.notebook.copy_notebook();
92 IPython.notebook.copy_notebook();
104 return false;
93 return false;
105 });
94 });
106 this.element.find('#download_ipynb').click(function () {
95 this.element.find('#download_ipynb').click(function () {
107 var notebook_name = IPython.notebook.get_notebook_name();
96 var base_url = IPython.notebook.base_url;
97 var notebook_path = IPython.notebook.notebook_path;
98 var notebook_name = IPython.notebook.notebook_name;
108 if (IPython.notebook.dirty) {
99 if (IPython.notebook.dirty) {
109 IPython.notebook.save_notebook({async : false});
100 IPython.notebook.save_notebook({async : false});
110 }
101 }
111
102
112 var url = utils.url_join_encode(
103 var url = utils.url_join_encode(
113 that.baseProjectUrl(),
104 base_url,
114 'files',
105 'files',
115 that.notebookPath(),
106 notebook_path,
116 notebook_name + '.ipynb'
107 notebook_name
117 );
108 );
118 window.location.assign(url);
109 window.location.assign(url);
119 });
110 });
120
111
121 this.element.find('#print_preview').click(function () {
112 this.element.find('#print_preview').click(function () {
122 that._nbconvert('html', false);
113 that._nbconvert('html', false);
123 });
114 });
124
115
125 this.element.find('#download_py').click(function () {
116 this.element.find('#download_py').click(function () {
126 that._nbconvert('python', true);
117 that._nbconvert('python', true);
127 });
118 });
128
119
129 this.element.find('#download_html').click(function () {
120 this.element.find('#download_html').click(function () {
130 that._nbconvert('html', true);
121 that._nbconvert('html', true);
131 });
122 });
132
123
133 this.element.find('#download_rst').click(function () {
124 this.element.find('#download_rst').click(function () {
134 that._nbconvert('rst', true);
125 that._nbconvert('rst', true);
135 });
126 });
136
127
137 this.element.find('#rename_notebook').click(function () {
128 this.element.find('#rename_notebook').click(function () {
138 IPython.save_widget.rename_notebook();
129 IPython.save_widget.rename_notebook();
139 });
130 });
140 this.element.find('#save_checkpoint').click(function () {
131 this.element.find('#save_checkpoint').click(function () {
141 IPython.notebook.save_checkpoint();
132 IPython.notebook.save_checkpoint();
142 });
133 });
143 this.element.find('#restore_checkpoint').click(function () {
134 this.element.find('#restore_checkpoint').click(function () {
144 });
135 });
145 this.element.find('#kill_and_exit').click(function () {
136 this.element.find('#kill_and_exit').click(function () {
146 IPython.notebook.session.delete();
137 IPython.notebook.session.delete();
147 setTimeout(function(){
138 setTimeout(function(){
148 // allow closing of new tabs in Chromium, impossible in FF
139 // allow closing of new tabs in Chromium, impossible in FF
149 window.open('', '_self', '');
140 window.open('', '_self', '');
150 window.close();
141 window.close();
151 }, 500);
142 }, 500);
152 });
143 });
153 // Edit
144 // Edit
154 this.element.find('#cut_cell').click(function () {
145 this.element.find('#cut_cell').click(function () {
155 IPython.notebook.cut_cell();
146 IPython.notebook.cut_cell();
156 });
147 });
157 this.element.find('#copy_cell').click(function () {
148 this.element.find('#copy_cell').click(function () {
158 IPython.notebook.copy_cell();
149 IPython.notebook.copy_cell();
159 });
150 });
160 this.element.find('#delete_cell').click(function () {
151 this.element.find('#delete_cell').click(function () {
161 IPython.notebook.delete_cell();
152 IPython.notebook.delete_cell();
162 });
153 });
163 this.element.find('#undelete_cell').click(function () {
154 this.element.find('#undelete_cell').click(function () {
164 IPython.notebook.undelete_cell();
155 IPython.notebook.undelete_cell();
165 });
156 });
166 this.element.find('#split_cell').click(function () {
157 this.element.find('#split_cell').click(function () {
167 IPython.notebook.split_cell();
158 IPython.notebook.split_cell();
168 });
159 });
169 this.element.find('#merge_cell_above').click(function () {
160 this.element.find('#merge_cell_above').click(function () {
170 IPython.notebook.merge_cell_above();
161 IPython.notebook.merge_cell_above();
171 });
162 });
172 this.element.find('#merge_cell_below').click(function () {
163 this.element.find('#merge_cell_below').click(function () {
173 IPython.notebook.merge_cell_below();
164 IPython.notebook.merge_cell_below();
174 });
165 });
175 this.element.find('#move_cell_up').click(function () {
166 this.element.find('#move_cell_up').click(function () {
176 IPython.notebook.move_cell_up();
167 IPython.notebook.move_cell_up();
177 });
168 });
178 this.element.find('#move_cell_down').click(function () {
169 this.element.find('#move_cell_down').click(function () {
179 IPython.notebook.move_cell_down();
170 IPython.notebook.move_cell_down();
180 });
171 });
181 this.element.find('#edit_nb_metadata').click(function () {
172 this.element.find('#edit_nb_metadata').click(function () {
182 IPython.notebook.edit_metadata();
173 IPython.notebook.edit_metadata();
183 });
174 });
184
175
185 // View
176 // View
186 this.element.find('#toggle_header').click(function () {
177 this.element.find('#toggle_header').click(function () {
187 $('div#header').toggle();
178 $('div#header').toggle();
188 IPython.layout_manager.do_resize();
179 IPython.layout_manager.do_resize();
189 });
180 });
190 this.element.find('#toggle_toolbar').click(function () {
181 this.element.find('#toggle_toolbar').click(function () {
191 $('div#maintoolbar').toggle();
182 $('div#maintoolbar').toggle();
192 IPython.layout_manager.do_resize();
183 IPython.layout_manager.do_resize();
193 });
184 });
194 // Insert
185 // Insert
195 this.element.find('#insert_cell_above').click(function () {
186 this.element.find('#insert_cell_above').click(function () {
196 IPython.notebook.insert_cell_above('code');
187 IPython.notebook.insert_cell_above('code');
197 IPython.notebook.select_prev();
188 IPython.notebook.select_prev();
198 });
189 });
199 this.element.find('#insert_cell_below').click(function () {
190 this.element.find('#insert_cell_below').click(function () {
200 IPython.notebook.insert_cell_below('code');
191 IPython.notebook.insert_cell_below('code');
201 IPython.notebook.select_next();
192 IPython.notebook.select_next();
202 });
193 });
203 // Cell
194 // Cell
204 this.element.find('#run_cell').click(function () {
195 this.element.find('#run_cell').click(function () {
205 IPython.notebook.execute_cell();
196 IPython.notebook.execute_cell();
206 });
197 });
207 this.element.find('#run_cell_select_below').click(function () {
198 this.element.find('#run_cell_select_below').click(function () {
208 IPython.notebook.execute_cell_and_select_below();
199 IPython.notebook.execute_cell_and_select_below();
209 });
200 });
210 this.element.find('#run_cell_insert_below').click(function () {
201 this.element.find('#run_cell_insert_below').click(function () {
211 IPython.notebook.execute_cell_and_insert_below();
202 IPython.notebook.execute_cell_and_insert_below();
212 });
203 });
213 this.element.find('#run_all_cells').click(function () {
204 this.element.find('#run_all_cells').click(function () {
214 IPython.notebook.execute_all_cells();
205 IPython.notebook.execute_all_cells();
215 });
206 });
216 this.element.find('#run_all_cells_above').click(function () {
207 this.element.find('#run_all_cells_above').click(function () {
217 IPython.notebook.execute_cells_above();
208 IPython.notebook.execute_cells_above();
218 });
209 });
219 this.element.find('#run_all_cells_below').click(function () {
210 this.element.find('#run_all_cells_below').click(function () {
220 IPython.notebook.execute_cells_below();
211 IPython.notebook.execute_cells_below();
221 });
212 });
222 this.element.find('#to_code').click(function () {
213 this.element.find('#to_code').click(function () {
223 IPython.notebook.to_code();
214 IPython.notebook.to_code();
224 });
215 });
225 this.element.find('#to_markdown').click(function () {
216 this.element.find('#to_markdown').click(function () {
226 IPython.notebook.to_markdown();
217 IPython.notebook.to_markdown();
227 });
218 });
228 this.element.find('#to_raw').click(function () {
219 this.element.find('#to_raw').click(function () {
229 IPython.notebook.to_raw();
220 IPython.notebook.to_raw();
230 });
221 });
231 this.element.find('#to_heading1').click(function () {
222 this.element.find('#to_heading1').click(function () {
232 IPython.notebook.to_heading(undefined, 1);
223 IPython.notebook.to_heading(undefined, 1);
233 });
224 });
234 this.element.find('#to_heading2').click(function () {
225 this.element.find('#to_heading2').click(function () {
235 IPython.notebook.to_heading(undefined, 2);
226 IPython.notebook.to_heading(undefined, 2);
236 });
227 });
237 this.element.find('#to_heading3').click(function () {
228 this.element.find('#to_heading3').click(function () {
238 IPython.notebook.to_heading(undefined, 3);
229 IPython.notebook.to_heading(undefined, 3);
239 });
230 });
240 this.element.find('#to_heading4').click(function () {
231 this.element.find('#to_heading4').click(function () {
241 IPython.notebook.to_heading(undefined, 4);
232 IPython.notebook.to_heading(undefined, 4);
242 });
233 });
243 this.element.find('#to_heading5').click(function () {
234 this.element.find('#to_heading5').click(function () {
244 IPython.notebook.to_heading(undefined, 5);
235 IPython.notebook.to_heading(undefined, 5);
245 });
236 });
246 this.element.find('#to_heading6').click(function () {
237 this.element.find('#to_heading6').click(function () {
247 IPython.notebook.to_heading(undefined, 6);
238 IPython.notebook.to_heading(undefined, 6);
248 });
239 });
249
240
250 this.element.find('#toggle_current_output').click(function () {
241 this.element.find('#toggle_current_output').click(function () {
251 IPython.notebook.toggle_output();
242 IPython.notebook.toggle_output();
252 });
243 });
253 this.element.find('#toggle_current_output_scroll').click(function () {
244 this.element.find('#toggle_current_output_scroll').click(function () {
254 IPython.notebook.toggle_output_scroll();
245 IPython.notebook.toggle_output_scroll();
255 });
246 });
256 this.element.find('#clear_current_output').click(function () {
247 this.element.find('#clear_current_output').click(function () {
257 IPython.notebook.clear_output();
248 IPython.notebook.clear_output();
258 });
249 });
259
250
260 this.element.find('#toggle_all_output').click(function () {
251 this.element.find('#toggle_all_output').click(function () {
261 IPython.notebook.toggle_all_output();
252 IPython.notebook.toggle_all_output();
262 });
253 });
263 this.element.find('#toggle_all_output_scroll').click(function () {
254 this.element.find('#toggle_all_output_scroll').click(function () {
264 IPython.notebook.toggle_all_output_scroll();
255 IPython.notebook.toggle_all_output_scroll();
265 });
256 });
266 this.element.find('#clear_all_output').click(function () {
257 this.element.find('#clear_all_output').click(function () {
267 IPython.notebook.clear_all_output();
258 IPython.notebook.clear_all_output();
268 });
259 });
269
260
270 // Kernel
261 // Kernel
271 this.element.find('#int_kernel').click(function () {
262 this.element.find('#int_kernel').click(function () {
272 IPython.notebook.session.interrupt_kernel();
263 IPython.notebook.session.interrupt_kernel();
273 });
264 });
274 this.element.find('#restart_kernel').click(function () {
265 this.element.find('#restart_kernel').click(function () {
275 IPython.notebook.restart_kernel();
266 IPython.notebook.restart_kernel();
276 });
267 });
277 // Help
268 // Help
278 this.element.find('#keyboard_shortcuts').click(function () {
269 this.element.find('#keyboard_shortcuts').click(function () {
279 IPython.quick_help.show_keyboard_shortcuts();
270 IPython.quick_help.show_keyboard_shortcuts();
280 });
271 });
281
272
282 this.update_restore_checkpoint(null);
273 this.update_restore_checkpoint(null);
283
274
284 $([IPython.events]).on('checkpoints_listed.Notebook', function (event, data) {
275 $([IPython.events]).on('checkpoints_listed.Notebook', function (event, data) {
285 that.update_restore_checkpoint(IPython.notebook.checkpoints);
276 that.update_restore_checkpoint(IPython.notebook.checkpoints);
286 });
277 });
287
278
288 $([IPython.events]).on('checkpoint_created.Notebook', function (event, data) {
279 $([IPython.events]).on('checkpoint_created.Notebook', function (event, data) {
289 that.update_restore_checkpoint(IPython.notebook.checkpoints);
280 that.update_restore_checkpoint(IPython.notebook.checkpoints);
290 });
281 });
291 };
282 };
292
283
293 MenuBar.prototype.update_restore_checkpoint = function(checkpoints) {
284 MenuBar.prototype.update_restore_checkpoint = function(checkpoints) {
294 var ul = this.element.find("#restore_checkpoint").find("ul");
285 var ul = this.element.find("#restore_checkpoint").find("ul");
295 ul.empty();
286 ul.empty();
296 if (!checkpoints || checkpoints.length === 0) {
287 if (!checkpoints || checkpoints.length === 0) {
297 ul.append(
288 ul.append(
298 $("<li/>")
289 $("<li/>")
299 .addClass("disabled")
290 .addClass("disabled")
300 .append(
291 .append(
301 $("<a/>")
292 $("<a/>")
302 .text("No checkpoints")
293 .text("No checkpoints")
303 )
294 )
304 );
295 );
305 return;
296 return;
306 }
297 }
307
298
308 checkpoints.map(function (checkpoint) {
299 checkpoints.map(function (checkpoint) {
309 var d = new Date(checkpoint.last_modified);
300 var d = new Date(checkpoint.last_modified);
310 ul.append(
301 ul.append(
311 $("<li/>").append(
302 $("<li/>").append(
312 $("<a/>")
303 $("<a/>")
313 .attr("href", "#")
304 .attr("href", "#")
314 .text(d.format("mmm dd HH:MM:ss"))
305 .text(d.format("mmm dd HH:MM:ss"))
315 .click(function () {
306 .click(function () {
316 IPython.notebook.restore_checkpoint_dialog(checkpoint);
307 IPython.notebook.restore_checkpoint_dialog(checkpoint);
317 })
308 })
318 )
309 )
319 );
310 );
320 });
311 });
321 };
312 };
322
313
323 IPython.MenuBar = MenuBar;
314 IPython.MenuBar = MenuBar;
324
315
325 return IPython;
316 return IPython;
326
317
327 }(IPython));
318 }(IPython));
@@ -1,2301 +1,2288 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Notebook
9 // Notebook
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 /**
17 /**
18 * A notebook contains and manages cells.
18 * A notebook contains and manages cells.
19 *
19 *
20 * @class Notebook
20 * @class Notebook
21 * @constructor
21 * @constructor
22 * @param {String} selector A jQuery selector for the notebook's DOM element
22 * @param {String} selector A jQuery selector for the notebook's DOM element
23 * @param {Object} [options] A config object
23 * @param {Object} [options] A config object
24 */
24 */
25 var Notebook = function (selector, options) {
25 var Notebook = function (selector, options) {
26 var options = options || {};
26 this.options = options = options || {};
27 this._baseProjectUrl = options.baseProjectUrl;
27 this.base_url = options.base_url;
28 this.notebook_path = options.notebookPath;
28 this.notebook_path = options.notebook_path;
29 this.notebook_name = options.notebookName;
29 this.notebook_name = options.notebook_name;
30 this.element = $(selector);
30 this.element = $(selector);
31 this.element.scroll();
31 this.element.scroll();
32 this.element.data("notebook", this);
32 this.element.data("notebook", this);
33 this.next_prompt_number = 1;
33 this.next_prompt_number = 1;
34 this.session = null;
34 this.session = null;
35 this.kernel = null;
35 this.kernel = null;
36 this.clipboard = null;
36 this.clipboard = null;
37 this.undelete_backup = null;
37 this.undelete_backup = null;
38 this.undelete_index = null;
38 this.undelete_index = null;
39 this.undelete_below = false;
39 this.undelete_below = false;
40 this.paste_enabled = false;
40 this.paste_enabled = false;
41 // It is important to start out in command mode to match the intial mode
41 // It is important to start out in command mode to match the intial mode
42 // of the KeyboardManager.
42 // of the KeyboardManager.
43 this.mode = 'command';
43 this.mode = 'command';
44 this.set_dirty(false);
44 this.set_dirty(false);
45 this.metadata = {};
45 this.metadata = {};
46 this._checkpoint_after_save = false;
46 this._checkpoint_after_save = false;
47 this.last_checkpoint = null;
47 this.last_checkpoint = null;
48 this.checkpoints = [];
48 this.checkpoints = [];
49 this.autosave_interval = 0;
49 this.autosave_interval = 0;
50 this.autosave_timer = null;
50 this.autosave_timer = null;
51 // autosave *at most* every two minutes
51 // autosave *at most* every two minutes
52 this.minimum_autosave_interval = 120000;
52 this.minimum_autosave_interval = 120000;
53 // single worksheet for now
53 // single worksheet for now
54 this.worksheet_metadata = {};
54 this.worksheet_metadata = {};
55 this.notebook_name_blacklist_re = /[\/\\:]/;
55 this.notebook_name_blacklist_re = /[\/\\:]/;
56 this.nbformat = 3 // Increment this when changing the nbformat
56 this.nbformat = 3; // Increment this when changing the nbformat
57 this.nbformat_minor = 0 // Increment this when changing the nbformat
57 this.nbformat_minor = 0; // Increment this when changing the nbformat
58 this.style();
58 this.style();
59 this.create_elements();
59 this.create_elements();
60 this.bind_events();
60 this.bind_events();
61 };
61 };
62
62
63 /**
63 /**
64 * Tweak the notebook's CSS style.
64 * Tweak the notebook's CSS style.
65 *
65 *
66 * @method style
66 * @method style
67 */
67 */
68 Notebook.prototype.style = function () {
68 Notebook.prototype.style = function () {
69 $('div#notebook').addClass('border-box-sizing');
69 $('div#notebook').addClass('border-box-sizing');
70 };
70 };
71
71
72 /**
72 /**
73 * Get the root URL of the notebook server.
74 *
75 * @method baseProjectUrl
76 * @return {String} The base project URL
77 */
78 Notebook.prototype.baseProjectUrl = function() {
79 return this._baseProjectUrl || $('body').data('baseProjectUrl');
80 };
81
82 Notebook.prototype.notebookName = function() {
83 return $('body').data('notebookName');
84 };
85
86 Notebook.prototype.notebookPath = function() {
87 return $('body').data('notebookPath');
88 };
89
90 /**
91 * Create an HTML and CSS representation of the notebook.
73 * Create an HTML and CSS representation of the notebook.
92 *
74 *
93 * @method create_elements
75 * @method create_elements
94 */
76 */
95 Notebook.prototype.create_elements = function () {
77 Notebook.prototype.create_elements = function () {
96 var that = this;
78 var that = this;
97 this.element.attr('tabindex','-1');
79 this.element.attr('tabindex','-1');
98 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
80 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
99 // We add this end_space div to the end of the notebook div to:
81 // We add this end_space div to the end of the notebook div to:
100 // i) provide a margin between the last cell and the end of the notebook
82 // i) provide a margin between the last cell and the end of the notebook
101 // ii) to prevent the div from scrolling up when the last cell is being
83 // ii) to prevent the div from scrolling up when the last cell is being
102 // edited, but is too low on the page, which browsers will do automatically.
84 // edited, but is too low on the page, which browsers will do automatically.
103 var end_space = $('<div/>').addClass('end_space');
85 var end_space = $('<div/>').addClass('end_space');
104 end_space.dblclick(function (e) {
86 end_space.dblclick(function (e) {
105 var ncells = that.ncells();
87 var ncells = that.ncells();
106 that.insert_cell_below('code',ncells-1);
88 that.insert_cell_below('code',ncells-1);
107 });
89 });
108 this.element.append(this.container);
90 this.element.append(this.container);
109 this.container.append(end_space);
91 this.container.append(end_space);
110 };
92 };
111
93
112 /**
94 /**
113 * Bind JavaScript events: key presses and custom IPython events.
95 * Bind JavaScript events: key presses and custom IPython events.
114 *
96 *
115 * @method bind_events
97 * @method bind_events
116 */
98 */
117 Notebook.prototype.bind_events = function () {
99 Notebook.prototype.bind_events = function () {
118 var that = this;
100 var that = this;
119
101
120 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
102 $([IPython.events]).on('set_next_input.Notebook', function (event, data) {
121 var index = that.find_cell_index(data.cell);
103 var index = that.find_cell_index(data.cell);
122 var new_cell = that.insert_cell_below('code',index);
104 var new_cell = that.insert_cell_below('code',index);
123 new_cell.set_text(data.text);
105 new_cell.set_text(data.text);
124 that.dirty = true;
106 that.dirty = true;
125 });
107 });
126
108
127 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
109 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
128 that.dirty = data.value;
110 that.dirty = data.value;
129 });
111 });
130
112
131 $([IPython.events]).on('select.Cell', function (event, data) {
113 $([IPython.events]).on('select.Cell', function (event, data) {
132 var index = that.find_cell_index(data.cell);
114 var index = that.find_cell_index(data.cell);
133 that.select(index);
115 that.select(index);
134 });
116 });
135
117
136 $([IPython.events]).on('edit_mode.Cell', function (event, data) {
118 $([IPython.events]).on('edit_mode.Cell', function (event, data) {
137 var index = that.find_cell_index(data.cell);
119 var index = that.find_cell_index(data.cell);
138 that.select(index);
120 that.select(index);
139 that.edit_mode();
121 that.edit_mode();
140 });
122 });
141
123
142 $([IPython.events]).on('command_mode.Cell', function (event, data) {
124 $([IPython.events]).on('command_mode.Cell', function (event, data) {
143 that.command_mode();
125 that.command_mode();
144 });
126 });
145
127
146 $([IPython.events]).on('status_autorestarting.Kernel', function () {
128 $([IPython.events]).on('status_autorestarting.Kernel', function () {
147 IPython.dialog.modal({
129 IPython.dialog.modal({
148 title: "Kernel Restarting",
130 title: "Kernel Restarting",
149 body: "The kernel appears to have died. It will restart automatically.",
131 body: "The kernel appears to have died. It will restart automatically.",
150 buttons: {
132 buttons: {
151 OK : {
133 OK : {
152 class : "btn-primary"
134 class : "btn-primary"
153 }
135 }
154 }
136 }
155 });
137 });
156 });
138 });
157
139
158 var collapse_time = function (time) {
140 var collapse_time = function (time) {
159 var app_height = $('#ipython-main-app').height(); // content height
141 var app_height = $('#ipython-main-app').height(); // content height
160 var splitter_height = $('div#pager_splitter').outerHeight(true);
142 var splitter_height = $('div#pager_splitter').outerHeight(true);
161 var new_height = app_height - splitter_height;
143 var new_height = app_height - splitter_height;
162 that.element.animate({height : new_height + 'px'}, time);
144 that.element.animate({height : new_height + 'px'}, time);
163 };
145 };
164
146
165 this.element.bind('collapse_pager', function (event, extrap) {
147 this.element.bind('collapse_pager', function (event, extrap) {
166 var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
148 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
167 collapse_time(time);
149 collapse_time(time);
168 });
150 });
169
151
170 var expand_time = function (time) {
152 var expand_time = function (time) {
171 var app_height = $('#ipython-main-app').height(); // content height
153 var app_height = $('#ipython-main-app').height(); // content height
172 var splitter_height = $('div#pager_splitter').outerHeight(true);
154 var splitter_height = $('div#pager_splitter').outerHeight(true);
173 var pager_height = $('div#pager').outerHeight(true);
155 var pager_height = $('div#pager').outerHeight(true);
174 var new_height = app_height - pager_height - splitter_height;
156 var new_height = app_height - pager_height - splitter_height;
175 that.element.animate({height : new_height + 'px'}, time);
157 that.element.animate({height : new_height + 'px'}, time);
176 };
158 };
177
159
178 this.element.bind('expand_pager', function (event, extrap) {
160 this.element.bind('expand_pager', function (event, extrap) {
179 var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast';
161 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
180 expand_time(time);
162 expand_time(time);
181 });
163 });
182
164
183 // Firefox 22 broke $(window).on("beforeunload")
165 // Firefox 22 broke $(window).on("beforeunload")
184 // I'm not sure why or how.
166 // I'm not sure why or how.
185 window.onbeforeunload = function (e) {
167 window.onbeforeunload = function (e) {
186 // TODO: Make killing the kernel configurable.
168 // TODO: Make killing the kernel configurable.
187 var kill_kernel = false;
169 var kill_kernel = false;
188 if (kill_kernel) {
170 if (kill_kernel) {
189 that.session.kill_kernel();
171 that.session.kill_kernel();
190 }
172 }
191 // if we are autosaving, trigger an autosave on nav-away.
173 // if we are autosaving, trigger an autosave on nav-away.
192 // still warn, because if we don't the autosave may fail.
174 // still warn, because if we don't the autosave may fail.
193 if (that.dirty) {
175 if (that.dirty) {
194 if ( that.autosave_interval ) {
176 if ( that.autosave_interval ) {
195 // schedule autosave in a timeout
177 // schedule autosave in a timeout
196 // this gives you a chance to forcefully discard changes
178 // this gives you a chance to forcefully discard changes
197 // by reloading the page if you *really* want to.
179 // by reloading the page if you *really* want to.
198 // the timer doesn't start until you *dismiss* the dialog.
180 // the timer doesn't start until you *dismiss* the dialog.
199 setTimeout(function () {
181 setTimeout(function () {
200 if (that.dirty) {
182 if (that.dirty) {
201 that.save_notebook();
183 that.save_notebook();
202 }
184 }
203 }, 1000);
185 }, 1000);
204 return "Autosave in progress, latest changes may be lost.";
186 return "Autosave in progress, latest changes may be lost.";
205 } else {
187 } else {
206 return "Unsaved changes will be lost.";
188 return "Unsaved changes will be lost.";
207 }
189 }
208 };
190 }
209 // Null is the *only* return value that will make the browser not
191 // Null is the *only* return value that will make the browser not
210 // pop up the "don't leave" dialog.
192 // pop up the "don't leave" dialog.
211 return null;
193 return null;
212 };
194 };
213 };
195 };
214
196
215 /**
197 /**
216 * Set the dirty flag, and trigger the set_dirty.Notebook event
198 * Set the dirty flag, and trigger the set_dirty.Notebook event
217 *
199 *
218 * @method set_dirty
200 * @method set_dirty
219 */
201 */
220 Notebook.prototype.set_dirty = function (value) {
202 Notebook.prototype.set_dirty = function (value) {
221 if (value === undefined) {
203 if (value === undefined) {
222 value = true;
204 value = true;
223 }
205 }
224 if (this.dirty == value) {
206 if (this.dirty == value) {
225 return;
207 return;
226 }
208 }
227 $([IPython.events]).trigger('set_dirty.Notebook', {value: value});
209 $([IPython.events]).trigger('set_dirty.Notebook', {value: value});
228 };
210 };
229
211
230 /**
212 /**
231 * Scroll the top of the page to a given cell.
213 * Scroll the top of the page to a given cell.
232 *
214 *
233 * @method scroll_to_cell
215 * @method scroll_to_cell
234 * @param {Number} cell_number An index of the cell to view
216 * @param {Number} cell_number An index of the cell to view
235 * @param {Number} time Animation time in milliseconds
217 * @param {Number} time Animation time in milliseconds
236 * @return {Number} Pixel offset from the top of the container
218 * @return {Number} Pixel offset from the top of the container
237 */
219 */
238 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
220 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
239 var cells = this.get_cells();
221 var cells = this.get_cells();
240 var time = time || 0;
222 time = time || 0;
241 cell_number = Math.min(cells.length-1,cell_number);
223 cell_number = Math.min(cells.length-1,cell_number);
242 cell_number = Math.max(0 ,cell_number);
224 cell_number = Math.max(0 ,cell_number);
243 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
225 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
244 this.element.animate({scrollTop:scroll_value}, time);
226 this.element.animate({scrollTop:scroll_value}, time);
245 return scroll_value;
227 return scroll_value;
246 };
228 };
247
229
248 /**
230 /**
249 * Scroll to the bottom of the page.
231 * Scroll to the bottom of the page.
250 *
232 *
251 * @method scroll_to_bottom
233 * @method scroll_to_bottom
252 */
234 */
253 Notebook.prototype.scroll_to_bottom = function () {
235 Notebook.prototype.scroll_to_bottom = function () {
254 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
236 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
255 };
237 };
256
238
257 /**
239 /**
258 * Scroll to the top of the page.
240 * Scroll to the top of the page.
259 *
241 *
260 * @method scroll_to_top
242 * @method scroll_to_top
261 */
243 */
262 Notebook.prototype.scroll_to_top = function () {
244 Notebook.prototype.scroll_to_top = function () {
263 this.element.animate({scrollTop:0}, 0);
245 this.element.animate({scrollTop:0}, 0);
264 };
246 };
265
247
266 // Edit Notebook metadata
248 // Edit Notebook metadata
267
249
268 Notebook.prototype.edit_metadata = function () {
250 Notebook.prototype.edit_metadata = function () {
269 var that = this;
251 var that = this;
270 IPython.dialog.edit_metadata(this.metadata, function (md) {
252 IPython.dialog.edit_metadata(this.metadata, function (md) {
271 that.metadata = md;
253 that.metadata = md;
272 }, 'Notebook');
254 }, 'Notebook');
273 };
255 };
274
256
275 // Cell indexing, retrieval, etc.
257 // Cell indexing, retrieval, etc.
276
258
277 /**
259 /**
278 * Get all cell elements in the notebook.
260 * Get all cell elements in the notebook.
279 *
261 *
280 * @method get_cell_elements
262 * @method get_cell_elements
281 * @return {jQuery} A selector of all cell elements
263 * @return {jQuery} A selector of all cell elements
282 */
264 */
283 Notebook.prototype.get_cell_elements = function () {
265 Notebook.prototype.get_cell_elements = function () {
284 return this.container.children("div.cell");
266 return this.container.children("div.cell");
285 };
267 };
286
268
287 /**
269 /**
288 * Get a particular cell element.
270 * Get a particular cell element.
289 *
271 *
290 * @method get_cell_element
272 * @method get_cell_element
291 * @param {Number} index An index of a cell to select
273 * @param {Number} index An index of a cell to select
292 * @return {jQuery} A selector of the given cell.
274 * @return {jQuery} A selector of the given cell.
293 */
275 */
294 Notebook.prototype.get_cell_element = function (index) {
276 Notebook.prototype.get_cell_element = function (index) {
295 var result = null;
277 var result = null;
296 var e = this.get_cell_elements().eq(index);
278 var e = this.get_cell_elements().eq(index);
297 if (e.length !== 0) {
279 if (e.length !== 0) {
298 result = e;
280 result = e;
299 }
281 }
300 return result;
282 return result;
301 };
283 };
302
284
303 /**
285 /**
304 * Try to get a particular cell by msg_id.
286 * Try to get a particular cell by msg_id.
305 *
287 *
306 * @method get_msg_cell
288 * @method get_msg_cell
307 * @param {String} msg_id A message UUID
289 * @param {String} msg_id A message UUID
308 * @return {Cell} Cell or null if no cell was found.
290 * @return {Cell} Cell or null if no cell was found.
309 */
291 */
310 Notebook.prototype.get_msg_cell = function (msg_id) {
292 Notebook.prototype.get_msg_cell = function (msg_id) {
311 return IPython.CodeCell.msg_cells[msg_id] || null;
293 return IPython.CodeCell.msg_cells[msg_id] || null;
312 };
294 };
313
295
314 /**
296 /**
315 * Count the cells in this notebook.
297 * Count the cells in this notebook.
316 *
298 *
317 * @method ncells
299 * @method ncells
318 * @return {Number} The number of cells in this notebook
300 * @return {Number} The number of cells in this notebook
319 */
301 */
320 Notebook.prototype.ncells = function () {
302 Notebook.prototype.ncells = function () {
321 return this.get_cell_elements().length;
303 return this.get_cell_elements().length;
322 };
304 };
323
305
324 /**
306 /**
325 * Get all Cell objects in this notebook.
307 * Get all Cell objects in this notebook.
326 *
308 *
327 * @method get_cells
309 * @method get_cells
328 * @return {Array} This notebook's Cell objects
310 * @return {Array} This notebook's Cell objects
329 */
311 */
330 // TODO: we are often calling cells as cells()[i], which we should optimize
312 // TODO: we are often calling cells as cells()[i], which we should optimize
331 // to cells(i) or a new method.
313 // to cells(i) or a new method.
332 Notebook.prototype.get_cells = function () {
314 Notebook.prototype.get_cells = function () {
333 return this.get_cell_elements().toArray().map(function (e) {
315 return this.get_cell_elements().toArray().map(function (e) {
334 return $(e).data("cell");
316 return $(e).data("cell");
335 });
317 });
336 };
318 };
337
319
338 /**
320 /**
339 * Get a Cell object from this notebook.
321 * Get a Cell object from this notebook.
340 *
322 *
341 * @method get_cell
323 * @method get_cell
342 * @param {Number} index An index of a cell to retrieve
324 * @param {Number} index An index of a cell to retrieve
343 * @return {Cell} A particular cell
325 * @return {Cell} A particular cell
344 */
326 */
345 Notebook.prototype.get_cell = function (index) {
327 Notebook.prototype.get_cell = function (index) {
346 var result = null;
328 var result = null;
347 var ce = this.get_cell_element(index);
329 var ce = this.get_cell_element(index);
348 if (ce !== null) {
330 if (ce !== null) {
349 result = ce.data('cell');
331 result = ce.data('cell');
350 }
332 }
351 return result;
333 return result;
352 }
334 };
353
335
354 /**
336 /**
355 * Get the cell below a given cell.
337 * Get the cell below a given cell.
356 *
338 *
357 * @method get_next_cell
339 * @method get_next_cell
358 * @param {Cell} cell The provided cell
340 * @param {Cell} cell The provided cell
359 * @return {Cell} The next cell
341 * @return {Cell} The next cell
360 */
342 */
361 Notebook.prototype.get_next_cell = function (cell) {
343 Notebook.prototype.get_next_cell = function (cell) {
362 var result = null;
344 var result = null;
363 var index = this.find_cell_index(cell);
345 var index = this.find_cell_index(cell);
364 if (this.is_valid_cell_index(index+1)) {
346 if (this.is_valid_cell_index(index+1)) {
365 result = this.get_cell(index+1);
347 result = this.get_cell(index+1);
366 }
348 }
367 return result;
349 return result;
368 }
350 };
369
351
370 /**
352 /**
371 * Get the cell above a given cell.
353 * Get the cell above a given cell.
372 *
354 *
373 * @method get_prev_cell
355 * @method get_prev_cell
374 * @param {Cell} cell The provided cell
356 * @param {Cell} cell The provided cell
375 * @return {Cell} The previous cell
357 * @return {Cell} The previous cell
376 */
358 */
377 Notebook.prototype.get_prev_cell = function (cell) {
359 Notebook.prototype.get_prev_cell = function (cell) {
378 // TODO: off-by-one
360 // TODO: off-by-one
379 // nb.get_prev_cell(nb.get_cell(1)) is null
361 // nb.get_prev_cell(nb.get_cell(1)) is null
380 var result = null;
362 var result = null;
381 var index = this.find_cell_index(cell);
363 var index = this.find_cell_index(cell);
382 if (index !== null && index > 1) {
364 if (index !== null && index > 1) {
383 result = this.get_cell(index-1);
365 result = this.get_cell(index-1);
384 }
366 }
385 return result;
367 return result;
386 }
368 };
387
369
388 /**
370 /**
389 * Get the numeric index of a given cell.
371 * Get the numeric index of a given cell.
390 *
372 *
391 * @method find_cell_index
373 * @method find_cell_index
392 * @param {Cell} cell The provided cell
374 * @param {Cell} cell The provided cell
393 * @return {Number} The cell's numeric index
375 * @return {Number} The cell's numeric index
394 */
376 */
395 Notebook.prototype.find_cell_index = function (cell) {
377 Notebook.prototype.find_cell_index = function (cell) {
396 var result = null;
378 var result = null;
397 this.get_cell_elements().filter(function (index) {
379 this.get_cell_elements().filter(function (index) {
398 if ($(this).data("cell") === cell) {
380 if ($(this).data("cell") === cell) {
399 result = index;
381 result = index;
400 };
382 }
401 });
383 });
402 return result;
384 return result;
403 };
385 };
404
386
405 /**
387 /**
406 * Get a given index , or the selected index if none is provided.
388 * Get a given index , or the selected index if none is provided.
407 *
389 *
408 * @method index_or_selected
390 * @method index_or_selected
409 * @param {Number} index A cell's index
391 * @param {Number} index A cell's index
410 * @return {Number} The given index, or selected index if none is provided.
392 * @return {Number} The given index, or selected index if none is provided.
411 */
393 */
412 Notebook.prototype.index_or_selected = function (index) {
394 Notebook.prototype.index_or_selected = function (index) {
413 var i;
395 var i;
414 if (index === undefined || index === null) {
396 if (index === undefined || index === null) {
415 i = this.get_selected_index();
397 i = this.get_selected_index();
416 if (i === null) {
398 if (i === null) {
417 i = 0;
399 i = 0;
418 }
400 }
419 } else {
401 } else {
420 i = index;
402 i = index;
421 }
403 }
422 return i;
404 return i;
423 };
405 };
424
406
425 /**
407 /**
426 * Get the currently selected cell.
408 * Get the currently selected cell.
427 * @method get_selected_cell
409 * @method get_selected_cell
428 * @return {Cell} The selected cell
410 * @return {Cell} The selected cell
429 */
411 */
430 Notebook.prototype.get_selected_cell = function () {
412 Notebook.prototype.get_selected_cell = function () {
431 var index = this.get_selected_index();
413 var index = this.get_selected_index();
432 return this.get_cell(index);
414 return this.get_cell(index);
433 };
415 };
434
416
435 /**
417 /**
436 * Check whether a cell index is valid.
418 * Check whether a cell index is valid.
437 *
419 *
438 * @method is_valid_cell_index
420 * @method is_valid_cell_index
439 * @param {Number} index A cell index
421 * @param {Number} index A cell index
440 * @return True if the index is valid, false otherwise
422 * @return True if the index is valid, false otherwise
441 */
423 */
442 Notebook.prototype.is_valid_cell_index = function (index) {
424 Notebook.prototype.is_valid_cell_index = function (index) {
443 if (index !== null && index >= 0 && index < this.ncells()) {
425 if (index !== null && index >= 0 && index < this.ncells()) {
444 return true;
426 return true;
445 } else {
427 } else {
446 return false;
428 return false;
447 };
429 }
448 }
430 };
449
431
450 /**
432 /**
451 * Get the index of the currently selected cell.
433 * Get the index of the currently selected cell.
452
434
453 * @method get_selected_index
435 * @method get_selected_index
454 * @return {Number} The selected cell's numeric index
436 * @return {Number} The selected cell's numeric index
455 */
437 */
456 Notebook.prototype.get_selected_index = function () {
438 Notebook.prototype.get_selected_index = function () {
457 var result = null;
439 var result = null;
458 this.get_cell_elements().filter(function (index) {
440 this.get_cell_elements().filter(function (index) {
459 if ($(this).data("cell").selected === true) {
441 if ($(this).data("cell").selected === true) {
460 result = index;
442 result = index;
461 };
443 }
462 });
444 });
463 return result;
445 return result;
464 };
446 };
465
447
466
448
467 // Cell selection.
449 // Cell selection.
468
450
469 /**
451 /**
470 * Programmatically select a cell.
452 * Programmatically select a cell.
471 *
453 *
472 * @method select
454 * @method select
473 * @param {Number} index A cell's index
455 * @param {Number} index A cell's index
474 * @return {Notebook} This notebook
456 * @return {Notebook} This notebook
475 */
457 */
476 Notebook.prototype.select = function (index) {
458 Notebook.prototype.select = function (index) {
477 if (this.is_valid_cell_index(index)) {
459 if (this.is_valid_cell_index(index)) {
478 var sindex = this.get_selected_index()
460 var sindex = this.get_selected_index();
479 if (sindex !== null && index !== sindex) {
461 if (sindex !== null && index !== sindex) {
480 this.command_mode();
462 this.command_mode();
481 this.get_cell(sindex).unselect();
463 this.get_cell(sindex).unselect();
482 };
464 }
483 var cell = this.get_cell(index);
465 var cell = this.get_cell(index);
484 cell.select();
466 cell.select();
485 if (cell.cell_type === 'heading') {
467 if (cell.cell_type === 'heading') {
486 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
468 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
487 {'cell_type':cell.cell_type,level:cell.level}
469 {'cell_type':cell.cell_type,level:cell.level}
488 );
470 );
489 } else {
471 } else {
490 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
472 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
491 {'cell_type':cell.cell_type}
473 {'cell_type':cell.cell_type}
492 );
474 );
493 };
475 }
494 };
476 }
495 return this;
477 return this;
496 };
478 };
497
479
498 /**
480 /**
499 * Programmatically select the next cell.
481 * Programmatically select the next cell.
500 *
482 *
501 * @method select_next
483 * @method select_next
502 * @return {Notebook} This notebook
484 * @return {Notebook} This notebook
503 */
485 */
504 Notebook.prototype.select_next = function () {
486 Notebook.prototype.select_next = function () {
505 var index = this.get_selected_index();
487 var index = this.get_selected_index();
506 this.select(index+1);
488 this.select(index+1);
507 return this;
489 return this;
508 };
490 };
509
491
510 /**
492 /**
511 * Programmatically select the previous cell.
493 * Programmatically select the previous cell.
512 *
494 *
513 * @method select_prev
495 * @method select_prev
514 * @return {Notebook} This notebook
496 * @return {Notebook} This notebook
515 */
497 */
516 Notebook.prototype.select_prev = function () {
498 Notebook.prototype.select_prev = function () {
517 var index = this.get_selected_index();
499 var index = this.get_selected_index();
518 this.select(index-1);
500 this.select(index-1);
519 return this;
501 return this;
520 };
502 };
521
503
522
504
523 // Edit/Command mode
505 // Edit/Command mode
524
506
525 Notebook.prototype.get_edit_index = function () {
507 Notebook.prototype.get_edit_index = function () {
526 var result = null;
508 var result = null;
527 this.get_cell_elements().filter(function (index) {
509 this.get_cell_elements().filter(function (index) {
528 if ($(this).data("cell").mode === 'edit') {
510 if ($(this).data("cell").mode === 'edit') {
529 result = index;
511 result = index;
530 };
512 }
531 });
513 });
532 return result;
514 return result;
533 };
515 };
534
516
535 Notebook.prototype.command_mode = function () {
517 Notebook.prototype.command_mode = function () {
536 if (this.mode !== 'command') {
518 if (this.mode !== 'command') {
519 $([IPython.events]).trigger('command_mode.Notebook');
537 var index = this.get_edit_index();
520 var index = this.get_edit_index();
538 var cell = this.get_cell(index);
521 var cell = this.get_cell(index);
539 if (cell) {
522 if (cell) {
540 cell.command_mode();
523 cell.command_mode();
541 };
524 }
542 this.mode = 'command';
525 this.mode = 'command';
543 IPython.keyboard_manager.command_mode();
526 IPython.keyboard_manager.command_mode();
544 };
527 }
545 };
528 };
546
529
547 Notebook.prototype.edit_mode = function () {
530 Notebook.prototype.edit_mode = function () {
548 if (this.mode !== 'edit') {
531 if (this.mode !== 'edit') {
532 $([IPython.events]).trigger('edit_mode.Notebook');
549 var cell = this.get_selected_cell();
533 var cell = this.get_selected_cell();
550 if (cell === null) {return;} // No cell is selected
534 if (cell === null) {return;} // No cell is selected
551 // We need to set the mode to edit to prevent reentering this method
535 // We need to set the mode to edit to prevent reentering this method
552 // when cell.edit_mode() is called below.
536 // when cell.edit_mode() is called below.
553 this.mode = 'edit';
537 this.mode = 'edit';
554 IPython.keyboard_manager.edit_mode();
538 IPython.keyboard_manager.edit_mode();
555 cell.edit_mode();
539 cell.edit_mode();
556 };
540 }
557 };
541 };
558
542
559 Notebook.prototype.focus_cell = function () {
543 Notebook.prototype.focus_cell = function () {
560 var cell = this.get_selected_cell();
544 var cell = this.get_selected_cell();
561 if (cell === null) {return;} // No cell is selected
545 if (cell === null) {return;} // No cell is selected
562 cell.focus_cell();
546 cell.focus_cell();
563 };
547 };
564
548
565 // Cell movement
549 // Cell movement
566
550
567 /**
551 /**
568 * Move given (or selected) cell up and select it.
552 * Move given (or selected) cell up and select it.
569 *
553 *
570 * @method move_cell_up
554 * @method move_cell_up
571 * @param [index] {integer} cell index
555 * @param [index] {integer} cell index
572 * @return {Notebook} This notebook
556 * @return {Notebook} This notebook
573 **/
557 **/
574 Notebook.prototype.move_cell_up = function (index) {
558 Notebook.prototype.move_cell_up = function (index) {
575 var i = this.index_or_selected(index);
559 var i = this.index_or_selected(index);
576 if (this.is_valid_cell_index(i) && i > 0) {
560 if (this.is_valid_cell_index(i) && i > 0) {
577 var pivot = this.get_cell_element(i-1);
561 var pivot = this.get_cell_element(i-1);
578 var tomove = this.get_cell_element(i);
562 var tomove = this.get_cell_element(i);
579 if (pivot !== null && tomove !== null) {
563 if (pivot !== null && tomove !== null) {
580 tomove.detach();
564 tomove.detach();
581 pivot.before(tomove);
565 pivot.before(tomove);
582 this.select(i-1);
566 this.select(i-1);
583 var cell = this.get_selected_cell();
567 var cell = this.get_selected_cell();
584 cell.focus_cell();
568 cell.focus_cell();
585 };
569 }
586 this.set_dirty(true);
570 this.set_dirty(true);
587 };
571 }
588 return this;
572 return this;
589 };
573 };
590
574
591
575
592 /**
576 /**
593 * Move given (or selected) cell down and select it
577 * Move given (or selected) cell down and select it
594 *
578 *
595 * @method move_cell_down
579 * @method move_cell_down
596 * @param [index] {integer} cell index
580 * @param [index] {integer} cell index
597 * @return {Notebook} This notebook
581 * @return {Notebook} This notebook
598 **/
582 **/
599 Notebook.prototype.move_cell_down = function (index) {
583 Notebook.prototype.move_cell_down = function (index) {
600 var i = this.index_or_selected(index);
584 var i = this.index_or_selected(index);
601 if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) {
585 if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) {
602 var pivot = this.get_cell_element(i+1);
586 var pivot = this.get_cell_element(i+1);
603 var tomove = this.get_cell_element(i);
587 var tomove = this.get_cell_element(i);
604 if (pivot !== null && tomove !== null) {
588 if (pivot !== null && tomove !== null) {
605 tomove.detach();
589 tomove.detach();
606 pivot.after(tomove);
590 pivot.after(tomove);
607 this.select(i+1);
591 this.select(i+1);
608 var cell = this.get_selected_cell();
592 var cell = this.get_selected_cell();
609 cell.focus_cell();
593 cell.focus_cell();
610 };
594 }
611 };
595 }
612 this.set_dirty();
596 this.set_dirty();
613 return this;
597 return this;
614 };
598 };
615
599
616
600
617 // Insertion, deletion.
601 // Insertion, deletion.
618
602
619 /**
603 /**
620 * Delete a cell from the notebook.
604 * Delete a cell from the notebook.
621 *
605 *
622 * @method delete_cell
606 * @method delete_cell
623 * @param [index] A cell's numeric index
607 * @param [index] A cell's numeric index
624 * @return {Notebook} This notebook
608 * @return {Notebook} This notebook
625 */
609 */
626 Notebook.prototype.delete_cell = function (index) {
610 Notebook.prototype.delete_cell = function (index) {
627 var i = this.index_or_selected(index);
611 var i = this.index_or_selected(index);
628 var cell = this.get_selected_cell();
612 var cell = this.get_selected_cell();
629 this.undelete_backup = cell.toJSON();
613 this.undelete_backup = cell.toJSON();
630 $('#undelete_cell').removeClass('disabled');
614 $('#undelete_cell').removeClass('disabled');
631 if (this.is_valid_cell_index(i)) {
615 if (this.is_valid_cell_index(i)) {
632 var old_ncells = this.ncells();
616 var old_ncells = this.ncells();
633 var ce = this.get_cell_element(i);
617 var ce = this.get_cell_element(i);
634 ce.remove();
618 ce.remove();
635 if (i === 0) {
619 if (i === 0) {
636 // Always make sure we have at least one cell.
620 // Always make sure we have at least one cell.
637 if (old_ncells === 1) {
621 if (old_ncells === 1) {
638 this.insert_cell_below('code');
622 this.insert_cell_below('code');
639 }
623 }
640 this.select(0);
624 this.select(0);
641 this.undelete_index = 0;
625 this.undelete_index = 0;
642 this.undelete_below = false;
626 this.undelete_below = false;
643 } else if (i === old_ncells-1 && i !== 0) {
627 } else if (i === old_ncells-1 && i !== 0) {
644 this.select(i-1);
628 this.select(i-1);
645 this.undelete_index = i - 1;
629 this.undelete_index = i - 1;
646 this.undelete_below = true;
630 this.undelete_below = true;
647 } else {
631 } else {
648 this.select(i);
632 this.select(i);
649 this.undelete_index = i;
633 this.undelete_index = i;
650 this.undelete_below = false;
634 this.undelete_below = false;
651 };
635 }
652 $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i});
636 $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i});
653 this.set_dirty(true);
637 this.set_dirty(true);
654 };
638 }
655 return this;
639 return this;
656 };
640 };
657
641
658 /**
642 /**
659 * Restore the most recently deleted cell.
643 * Restore the most recently deleted cell.
660 *
644 *
661 * @method undelete
645 * @method undelete
662 */
646 */
663 Notebook.prototype.undelete_cell = function() {
647 Notebook.prototype.undelete_cell = function() {
664 if (this.undelete_backup !== null && this.undelete_index !== null) {
648 if (this.undelete_backup !== null && this.undelete_index !== null) {
665 var current_index = this.get_selected_index();
649 var current_index = this.get_selected_index();
666 if (this.undelete_index < current_index) {
650 if (this.undelete_index < current_index) {
667 current_index = current_index + 1;
651 current_index = current_index + 1;
668 }
652 }
669 if (this.undelete_index >= this.ncells()) {
653 if (this.undelete_index >= this.ncells()) {
670 this.select(this.ncells() - 1);
654 this.select(this.ncells() - 1);
671 }
655 }
672 else {
656 else {
673 this.select(this.undelete_index);
657 this.select(this.undelete_index);
674 }
658 }
675 var cell_data = this.undelete_backup;
659 var cell_data = this.undelete_backup;
676 var new_cell = null;
660 var new_cell = null;
677 if (this.undelete_below) {
661 if (this.undelete_below) {
678 new_cell = this.insert_cell_below(cell_data.cell_type);
662 new_cell = this.insert_cell_below(cell_data.cell_type);
679 } else {
663 } else {
680 new_cell = this.insert_cell_above(cell_data.cell_type);
664 new_cell = this.insert_cell_above(cell_data.cell_type);
681 }
665 }
682 new_cell.fromJSON(cell_data);
666 new_cell.fromJSON(cell_data);
683 if (this.undelete_below) {
667 if (this.undelete_below) {
684 this.select(current_index+1);
668 this.select(current_index+1);
685 } else {
669 } else {
686 this.select(current_index);
670 this.select(current_index);
687 }
671 }
688 this.undelete_backup = null;
672 this.undelete_backup = null;
689 this.undelete_index = null;
673 this.undelete_index = null;
690 }
674 }
691 $('#undelete_cell').addClass('disabled');
675 $('#undelete_cell').addClass('disabled');
692 }
676 };
693
677
694 /**
678 /**
695 * Insert a cell so that after insertion the cell is at given index.
679 * Insert a cell so that after insertion the cell is at given index.
696 *
680 *
697 * Similar to insert_above, but index parameter is mandatory
681 * Similar to insert_above, but index parameter is mandatory
698 *
682 *
699 * Index will be brought back into the accissible range [0,n]
683 * Index will be brought back into the accissible range [0,n]
700 *
684 *
701 * @method insert_cell_at_index
685 * @method insert_cell_at_index
702 * @param type {string} in ['code','markdown','heading']
686 * @param type {string} in ['code','markdown','heading']
703 * @param [index] {int} a valid index where to inser cell
687 * @param [index] {int} a valid index where to inser cell
704 *
688 *
705 * @return cell {cell|null} created cell or null
689 * @return cell {cell|null} created cell or null
706 **/
690 **/
707 Notebook.prototype.insert_cell_at_index = function(type, index){
691 Notebook.prototype.insert_cell_at_index = function(type, index){
708
692
709 var ncells = this.ncells();
693 var ncells = this.ncells();
710 var index = Math.min(index,ncells);
694 index = Math.min(index,ncells);
711 index = Math.max(index,0);
695 index = Math.max(index,0);
712 var cell = null;
696 var cell = null;
713
697
714 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
698 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
715 if (type === 'code') {
699 if (type === 'code') {
716 cell = new IPython.CodeCell(this.kernel);
700 cell = new IPython.CodeCell(this.kernel);
717 cell.set_input_prompt();
701 cell.set_input_prompt();
718 } else if (type === 'markdown') {
702 } else if (type === 'markdown') {
719 cell = new IPython.MarkdownCell();
703 cell = new IPython.MarkdownCell();
720 } else if (type === 'raw') {
704 } else if (type === 'raw') {
721 cell = new IPython.RawCell();
705 cell = new IPython.RawCell();
722 } else if (type === 'heading') {
706 } else if (type === 'heading') {
723 cell = new IPython.HeadingCell();
707 cell = new IPython.HeadingCell();
724 }
708 }
725
709
726 if(this._insert_element_at_index(cell.element,index)) {
710 if(this._insert_element_at_index(cell.element,index)) {
727 cell.render();
711 cell.render();
728 $([IPython.events]).trigger('create.Cell', {'cell': cell, 'index': index});
712 $([IPython.events]).trigger('create.Cell', {'cell': cell, 'index': index});
729 cell.refresh();
713 cell.refresh();
730 // We used to select the cell after we refresh it, but there
714 // We used to select the cell after we refresh it, but there
731 // are now cases were this method is called where select is
715 // are now cases were this method is called where select is
732 // not appropriate. The selection logic should be handled by the
716 // not appropriate. The selection logic should be handled by the
733 // caller of the the top level insert_cell methods.
717 // caller of the the top level insert_cell methods.
734 this.set_dirty(true);
718 this.set_dirty(true);
735 }
719 }
736 }
720 }
737 return cell;
721 return cell;
738
722
739 };
723 };
740
724
741 /**
725 /**
742 * Insert an element at given cell index.
726 * Insert an element at given cell index.
743 *
727 *
744 * @method _insert_element_at_index
728 * @method _insert_element_at_index
745 * @param element {dom element} a cell element
729 * @param element {dom element} a cell element
746 * @param [index] {int} a valid index where to inser cell
730 * @param [index] {int} a valid index where to inser cell
747 * @private
731 * @private
748 *
732 *
749 * return true if everything whent fine.
733 * return true if everything whent fine.
750 **/
734 **/
751 Notebook.prototype._insert_element_at_index = function(element, index){
735 Notebook.prototype._insert_element_at_index = function(element, index){
752 if (element === undefined){
736 if (element === undefined){
753 return false;
737 return false;
754 }
738 }
755
739
756 var ncells = this.ncells();
740 var ncells = this.ncells();
757
741
758 if (ncells === 0) {
742 if (ncells === 0) {
759 // special case append if empty
743 // special case append if empty
760 this.element.find('div.end_space').before(element);
744 this.element.find('div.end_space').before(element);
761 } else if ( ncells === index ) {
745 } else if ( ncells === index ) {
762 // special case append it the end, but not empty
746 // special case append it the end, but not empty
763 this.get_cell_element(index-1).after(element);
747 this.get_cell_element(index-1).after(element);
764 } else if (this.is_valid_cell_index(index)) {
748 } else if (this.is_valid_cell_index(index)) {
765 // otherwise always somewhere to append to
749 // otherwise always somewhere to append to
766 this.get_cell_element(index).before(element);
750 this.get_cell_element(index).before(element);
767 } else {
751 } else {
768 return false;
752 return false;
769 }
753 }
770
754
771 if (this.undelete_index !== null && index <= this.undelete_index) {
755 if (this.undelete_index !== null && index <= this.undelete_index) {
772 this.undelete_index = this.undelete_index + 1;
756 this.undelete_index = this.undelete_index + 1;
773 this.set_dirty(true);
757 this.set_dirty(true);
774 }
758 }
775 return true;
759 return true;
776 };
760 };
777
761
778 /**
762 /**
779 * Insert a cell of given type above given index, or at top
763 * Insert a cell of given type above given index, or at top
780 * of notebook if index smaller than 0.
764 * of notebook if index smaller than 0.
781 *
765 *
782 * default index value is the one of currently selected cell
766 * default index value is the one of currently selected cell
783 *
767 *
784 * @method insert_cell_above
768 * @method insert_cell_above
785 * @param type {string} cell type
769 * @param type {string} cell type
786 * @param [index] {integer}
770 * @param [index] {integer}
787 *
771 *
788 * @return handle to created cell or null
772 * @return handle to created cell or null
789 **/
773 **/
790 Notebook.prototype.insert_cell_above = function (type, index) {
774 Notebook.prototype.insert_cell_above = function (type, index) {
791 index = this.index_or_selected(index);
775 index = this.index_or_selected(index);
792 return this.insert_cell_at_index(type, index);
776 return this.insert_cell_at_index(type, index);
793 };
777 };
794
778
795 /**
779 /**
796 * Insert a cell of given type below given index, or at bottom
780 * Insert a cell of given type below given index, or at bottom
797 * of notebook if index greater thatn number of cell
781 * of notebook if index greater thatn number of cell
798 *
782 *
799 * default index value is the one of currently selected cell
783 * default index value is the one of currently selected cell
800 *
784 *
801 * @method insert_cell_below
785 * @method insert_cell_below
802 * @param type {string} cell type
786 * @param type {string} cell type
803 * @param [index] {integer}
787 * @param [index] {integer}
804 *
788 *
805 * @return handle to created cell or null
789 * @return handle to created cell or null
806 *
790 *
807 **/
791 **/
808 Notebook.prototype.insert_cell_below = function (type, index) {
792 Notebook.prototype.insert_cell_below = function (type, index) {
809 index = this.index_or_selected(index);
793 index = this.index_or_selected(index);
810 return this.insert_cell_at_index(type, index+1);
794 return this.insert_cell_at_index(type, index+1);
811 };
795 };
812
796
813
797
814 /**
798 /**
815 * Insert cell at end of notebook
799 * Insert cell at end of notebook
816 *
800 *
817 * @method insert_cell_at_bottom
801 * @method insert_cell_at_bottom
818 * @param {String} type cell type
802 * @param {String} type cell type
819 *
803 *
820 * @return the added cell; or null
804 * @return the added cell; or null
821 **/
805 **/
822 Notebook.prototype.insert_cell_at_bottom = function (type){
806 Notebook.prototype.insert_cell_at_bottom = function (type){
823 var len = this.ncells();
807 var len = this.ncells();
824 return this.insert_cell_below(type,len-1);
808 return this.insert_cell_below(type,len-1);
825 };
809 };
826
810
827 /**
811 /**
828 * Turn a cell into a code cell.
812 * Turn a cell into a code cell.
829 *
813 *
830 * @method to_code
814 * @method to_code
831 * @param {Number} [index] A cell's index
815 * @param {Number} [index] A cell's index
832 */
816 */
833 Notebook.prototype.to_code = function (index) {
817 Notebook.prototype.to_code = function (index) {
834 var i = this.index_or_selected(index);
818 var i = this.index_or_selected(index);
835 if (this.is_valid_cell_index(i)) {
819 if (this.is_valid_cell_index(i)) {
836 var source_element = this.get_cell_element(i);
820 var source_element = this.get_cell_element(i);
837 var source_cell = source_element.data("cell");
821 var source_cell = source_element.data("cell");
838 if (!(source_cell instanceof IPython.CodeCell)) {
822 if (!(source_cell instanceof IPython.CodeCell)) {
839 var target_cell = this.insert_cell_below('code',i);
823 var target_cell = this.insert_cell_below('code',i);
840 var text = source_cell.get_text();
824 var text = source_cell.get_text();
841 if (text === source_cell.placeholder) {
825 if (text === source_cell.placeholder) {
842 text = '';
826 text = '';
843 }
827 }
844 target_cell.set_text(text);
828 target_cell.set_text(text);
845 // make this value the starting point, so that we can only undo
829 // make this value the starting point, so that we can only undo
846 // to this state, instead of a blank cell
830 // to this state, instead of a blank cell
847 target_cell.code_mirror.clearHistory();
831 target_cell.code_mirror.clearHistory();
848 source_element.remove();
832 source_element.remove();
849 this.select(i);
833 this.select(i);
850 this.set_dirty(true);
834 this.set_dirty(true);
851 };
835 }
852 };
836 }
853 };
837 };
854
838
855 /**
839 /**
856 * Turn a cell into a Markdown cell.
840 * Turn a cell into a Markdown cell.
857 *
841 *
858 * @method to_markdown
842 * @method to_markdown
859 * @param {Number} [index] A cell's index
843 * @param {Number} [index] A cell's index
860 */
844 */
861 Notebook.prototype.to_markdown = function (index) {
845 Notebook.prototype.to_markdown = function (index) {
862 var i = this.index_or_selected(index);
846 var i = this.index_or_selected(index);
863 if (this.is_valid_cell_index(i)) {
847 if (this.is_valid_cell_index(i)) {
864 var source_element = this.get_cell_element(i);
848 var source_element = this.get_cell_element(i);
865 var source_cell = source_element.data("cell");
849 var source_cell = source_element.data("cell");
866 if (!(source_cell instanceof IPython.MarkdownCell)) {
850 if (!(source_cell instanceof IPython.MarkdownCell)) {
867 var target_cell = this.insert_cell_below('markdown',i);
851 var target_cell = this.insert_cell_below('markdown',i);
868 var text = source_cell.get_text();
852 var text = source_cell.get_text();
869 if (text === source_cell.placeholder) {
853 if (text === source_cell.placeholder) {
870 text = '';
854 text = '';
871 };
855 }
872 // We must show the editor before setting its contents
856 // We must show the editor before setting its contents
873 target_cell.unrender();
857 target_cell.unrender();
874 target_cell.set_text(text);
858 target_cell.set_text(text);
875 // make this value the starting point, so that we can only undo
859 // make this value the starting point, so that we can only undo
876 // to this state, instead of a blank cell
860 // to this state, instead of a blank cell
877 target_cell.code_mirror.clearHistory();
861 target_cell.code_mirror.clearHistory();
878 source_element.remove();
862 source_element.remove();
879 this.select(i);
863 this.select(i);
880 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
864 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
881 target_cell.render();
865 target_cell.render();
882 }
866 }
883 this.set_dirty(true);
867 this.set_dirty(true);
884 };
868 }
885 };
869 }
886 };
870 };
887
871
888 /**
872 /**
889 * Turn a cell into a raw text cell.
873 * Turn a cell into a raw text cell.
890 *
874 *
891 * @method to_raw
875 * @method to_raw
892 * @param {Number} [index] A cell's index
876 * @param {Number} [index] A cell's index
893 */
877 */
894 Notebook.prototype.to_raw = function (index) {
878 Notebook.prototype.to_raw = function (index) {
895 var i = this.index_or_selected(index);
879 var i = this.index_or_selected(index);
896 if (this.is_valid_cell_index(i)) {
880 if (this.is_valid_cell_index(i)) {
897 var source_element = this.get_cell_element(i);
881 var source_element = this.get_cell_element(i);
898 var source_cell = source_element.data("cell");
882 var source_cell = source_element.data("cell");
899 var target_cell = null;
883 var target_cell = null;
900 if (!(source_cell instanceof IPython.RawCell)) {
884 if (!(source_cell instanceof IPython.RawCell)) {
901 target_cell = this.insert_cell_below('raw',i);
885 target_cell = this.insert_cell_below('raw',i);
902 var text = source_cell.get_text();
886 var text = source_cell.get_text();
903 if (text === source_cell.placeholder) {
887 if (text === source_cell.placeholder) {
904 text = '';
888 text = '';
905 };
889 }
906 // We must show the editor before setting its contents
890 // We must show the editor before setting its contents
907 target_cell.unrender();
891 target_cell.unrender();
908 target_cell.set_text(text);
892 target_cell.set_text(text);
909 // make this value the starting point, so that we can only undo
893 // make this value the starting point, so that we can only undo
910 // to this state, instead of a blank cell
894 // to this state, instead of a blank cell
911 target_cell.code_mirror.clearHistory();
895 target_cell.code_mirror.clearHistory();
912 source_element.remove();
896 source_element.remove();
913 this.select(i);
897 this.select(i);
914 this.set_dirty(true);
898 this.set_dirty(true);
915 };
899 }
916 };
900 }
917 };
901 };
918
902
919 /**
903 /**
920 * Turn a cell into a heading cell.
904 * Turn a cell into a heading cell.
921 *
905 *
922 * @method to_heading
906 * @method to_heading
923 * @param {Number} [index] A cell's index
907 * @param {Number} [index] A cell's index
924 * @param {Number} [level] A heading level (e.g., 1 becomes &lt;h1&gt;)
908 * @param {Number} [level] A heading level (e.g., 1 becomes &lt;h1&gt;)
925 */
909 */
926 Notebook.prototype.to_heading = function (index, level) {
910 Notebook.prototype.to_heading = function (index, level) {
927 level = level || 1;
911 level = level || 1;
928 var i = this.index_or_selected(index);
912 var i = this.index_or_selected(index);
929 if (this.is_valid_cell_index(i)) {
913 if (this.is_valid_cell_index(i)) {
930 var source_element = this.get_cell_element(i);
914 var source_element = this.get_cell_element(i);
931 var source_cell = source_element.data("cell");
915 var source_cell = source_element.data("cell");
932 var target_cell = null;
916 var target_cell = null;
933 if (source_cell instanceof IPython.HeadingCell) {
917 if (source_cell instanceof IPython.HeadingCell) {
934 source_cell.set_level(level);
918 source_cell.set_level(level);
935 } else {
919 } else {
936 target_cell = this.insert_cell_below('heading',i);
920 target_cell = this.insert_cell_below('heading',i);
937 var text = source_cell.get_text();
921 var text = source_cell.get_text();
938 if (text === source_cell.placeholder) {
922 if (text === source_cell.placeholder) {
939 text = '';
923 text = '';
940 };
924 }
941 // We must show the editor before setting its contents
925 // We must show the editor before setting its contents
942 target_cell.set_level(level);
926 target_cell.set_level(level);
943 target_cell.unrender();
927 target_cell.unrender();
944 target_cell.set_text(text);
928 target_cell.set_text(text);
945 // make this value the starting point, so that we can only undo
929 // make this value the starting point, so that we can only undo
946 // to this state, instead of a blank cell
930 // to this state, instead of a blank cell
947 target_cell.code_mirror.clearHistory();
931 target_cell.code_mirror.clearHistory();
948 source_element.remove();
932 source_element.remove();
949 this.select(i);
933 this.select(i);
950 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
934 if ((source_cell instanceof IPython.TextCell) && source_cell.rendered) {
951 target_cell.render();
935 target_cell.render();
952 }
936 }
953 };
937 }
954 this.set_dirty(true);
938 this.set_dirty(true);
955 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
939 $([IPython.events]).trigger('selected_cell_type_changed.Notebook',
956 {'cell_type':'heading',level:level}
940 {'cell_type':'heading',level:level}
957 );
941 );
958 };
942 }
959 };
943 };
960
944
961
945
962 // Cut/Copy/Paste
946 // Cut/Copy/Paste
963
947
964 /**
948 /**
965 * Enable UI elements for pasting cells.
949 * Enable UI elements for pasting cells.
966 *
950 *
967 * @method enable_paste
951 * @method enable_paste
968 */
952 */
969 Notebook.prototype.enable_paste = function () {
953 Notebook.prototype.enable_paste = function () {
970 var that = this;
954 var that = this;
971 if (!this.paste_enabled) {
955 if (!this.paste_enabled) {
972 $('#paste_cell_replace').removeClass('disabled')
956 $('#paste_cell_replace').removeClass('disabled')
973 .on('click', function () {that.paste_cell_replace();});
957 .on('click', function () {that.paste_cell_replace();});
974 $('#paste_cell_above').removeClass('disabled')
958 $('#paste_cell_above').removeClass('disabled')
975 .on('click', function () {that.paste_cell_above();});
959 .on('click', function () {that.paste_cell_above();});
976 $('#paste_cell_below').removeClass('disabled')
960 $('#paste_cell_below').removeClass('disabled')
977 .on('click', function () {that.paste_cell_below();});
961 .on('click', function () {that.paste_cell_below();});
978 this.paste_enabled = true;
962 this.paste_enabled = true;
979 };
963 }
980 };
964 };
981
965
982 /**
966 /**
983 * Disable UI elements for pasting cells.
967 * Disable UI elements for pasting cells.
984 *
968 *
985 * @method disable_paste
969 * @method disable_paste
986 */
970 */
987 Notebook.prototype.disable_paste = function () {
971 Notebook.prototype.disable_paste = function () {
988 if (this.paste_enabled) {
972 if (this.paste_enabled) {
989 $('#paste_cell_replace').addClass('disabled').off('click');
973 $('#paste_cell_replace').addClass('disabled').off('click');
990 $('#paste_cell_above').addClass('disabled').off('click');
974 $('#paste_cell_above').addClass('disabled').off('click');
991 $('#paste_cell_below').addClass('disabled').off('click');
975 $('#paste_cell_below').addClass('disabled').off('click');
992 this.paste_enabled = false;
976 this.paste_enabled = false;
993 };
977 }
994 };
978 };
995
979
996 /**
980 /**
997 * Cut a cell.
981 * Cut a cell.
998 *
982 *
999 * @method cut_cell
983 * @method cut_cell
1000 */
984 */
1001 Notebook.prototype.cut_cell = function () {
985 Notebook.prototype.cut_cell = function () {
1002 this.copy_cell();
986 this.copy_cell();
1003 this.delete_cell();
987 this.delete_cell();
1004 }
988 };
1005
989
1006 /**
990 /**
1007 * Copy a cell.
991 * Copy a cell.
1008 *
992 *
1009 * @method copy_cell
993 * @method copy_cell
1010 */
994 */
1011 Notebook.prototype.copy_cell = function () {
995 Notebook.prototype.copy_cell = function () {
1012 var cell = this.get_selected_cell();
996 var cell = this.get_selected_cell();
1013 this.clipboard = cell.toJSON();
997 this.clipboard = cell.toJSON();
1014 this.enable_paste();
998 this.enable_paste();
1015 };
999 };
1016
1000
1017 /**
1001 /**
1018 * Replace the selected cell with a cell in the clipboard.
1002 * Replace the selected cell with a cell in the clipboard.
1019 *
1003 *
1020 * @method paste_cell_replace
1004 * @method paste_cell_replace
1021 */
1005 */
1022 Notebook.prototype.paste_cell_replace = function () {
1006 Notebook.prototype.paste_cell_replace = function () {
1023 if (this.clipboard !== null && this.paste_enabled) {
1007 if (this.clipboard !== null && this.paste_enabled) {
1024 var cell_data = this.clipboard;
1008 var cell_data = this.clipboard;
1025 var new_cell = this.insert_cell_above(cell_data.cell_type);
1009 var new_cell = this.insert_cell_above(cell_data.cell_type);
1026 new_cell.fromJSON(cell_data);
1010 new_cell.fromJSON(cell_data);
1027 var old_cell = this.get_next_cell(new_cell);
1011 var old_cell = this.get_next_cell(new_cell);
1028 this.delete_cell(this.find_cell_index(old_cell));
1012 this.delete_cell(this.find_cell_index(old_cell));
1029 this.select(this.find_cell_index(new_cell));
1013 this.select(this.find_cell_index(new_cell));
1030 };
1014 }
1031 };
1015 };
1032
1016
1033 /**
1017 /**
1034 * Paste a cell from the clipboard above the selected cell.
1018 * Paste a cell from the clipboard above the selected cell.
1035 *
1019 *
1036 * @method paste_cell_above
1020 * @method paste_cell_above
1037 */
1021 */
1038 Notebook.prototype.paste_cell_above = function () {
1022 Notebook.prototype.paste_cell_above = function () {
1039 if (this.clipboard !== null && this.paste_enabled) {
1023 if (this.clipboard !== null && this.paste_enabled) {
1040 var cell_data = this.clipboard;
1024 var cell_data = this.clipboard;
1041 var new_cell = this.insert_cell_above(cell_data.cell_type);
1025 var new_cell = this.insert_cell_above(cell_data.cell_type);
1042 new_cell.fromJSON(cell_data);
1026 new_cell.fromJSON(cell_data);
1043 new_cell.focus_cell();
1027 new_cell.focus_cell();
1044 };
1028 }
1045 };
1029 };
1046
1030
1047 /**
1031 /**
1048 * Paste a cell from the clipboard below the selected cell.
1032 * Paste a cell from the clipboard below the selected cell.
1049 *
1033 *
1050 * @method paste_cell_below
1034 * @method paste_cell_below
1051 */
1035 */
1052 Notebook.prototype.paste_cell_below = function () {
1036 Notebook.prototype.paste_cell_below = function () {
1053 if (this.clipboard !== null && this.paste_enabled) {
1037 if (this.clipboard !== null && this.paste_enabled) {
1054 var cell_data = this.clipboard;
1038 var cell_data = this.clipboard;
1055 var new_cell = this.insert_cell_below(cell_data.cell_type);
1039 var new_cell = this.insert_cell_below(cell_data.cell_type);
1056 new_cell.fromJSON(cell_data);
1040 new_cell.fromJSON(cell_data);
1057 new_cell.focus_cell();
1041 new_cell.focus_cell();
1058 };
1042 }
1059 };
1043 };
1060
1044
1061 // Split/merge
1045 // Split/merge
1062
1046
1063 /**
1047 /**
1064 * Split the selected cell into two, at the cursor.
1048 * Split the selected cell into two, at the cursor.
1065 *
1049 *
1066 * @method split_cell
1050 * @method split_cell
1067 */
1051 */
1068 Notebook.prototype.split_cell = function () {
1052 Notebook.prototype.split_cell = function () {
1069 var mdc = IPython.MarkdownCell;
1053 var mdc = IPython.MarkdownCell;
1070 var rc = IPython.RawCell;
1054 var rc = IPython.RawCell;
1071 var cell = this.get_selected_cell();
1055 var cell = this.get_selected_cell();
1072 if (cell.is_splittable()) {
1056 if (cell.is_splittable()) {
1073 var texta = cell.get_pre_cursor();
1057 var texta = cell.get_pre_cursor();
1074 var textb = cell.get_post_cursor();
1058 var textb = cell.get_post_cursor();
1075 if (cell instanceof IPython.CodeCell) {
1059 if (cell instanceof IPython.CodeCell) {
1076 // In this case the operations keep the notebook in its existing mode
1060 // In this case the operations keep the notebook in its existing mode
1077 // so we don't need to do any post-op mode changes.
1061 // so we don't need to do any post-op mode changes.
1078 cell.set_text(textb);
1062 cell.set_text(textb);
1079 var new_cell = this.insert_cell_above('code');
1063 var new_cell = this.insert_cell_above('code');
1080 new_cell.set_text(texta);
1064 new_cell.set_text(texta);
1081 } else if ((cell instanceof mdc && !cell.rendered) || (cell instanceof rc)) {
1065 } else if ((cell instanceof mdc && !cell.rendered) || (cell instanceof rc)) {
1082 // We know cell is !rendered so we can use set_text.
1066 // We know cell is !rendered so we can use set_text.
1083 cell.set_text(textb);
1067 cell.set_text(textb);
1084 var new_cell = this.insert_cell_above(cell.cell_type);
1068 var new_cell = this.insert_cell_above(cell.cell_type);
1085 // Unrender the new cell so we can call set_text.
1069 // Unrender the new cell so we can call set_text.
1086 new_cell.unrender();
1070 new_cell.unrender();
1087 new_cell.set_text(texta);
1071 new_cell.set_text(texta);
1088 }
1072 }
1089 };
1073 }
1090 };
1074 };
1091
1075
1092 /**
1076 /**
1093 * Combine the selected cell into the cell above it.
1077 * Combine the selected cell into the cell above it.
1094 *
1078 *
1095 * @method merge_cell_above
1079 * @method merge_cell_above
1096 */
1080 */
1097 Notebook.prototype.merge_cell_above = function () {
1081 Notebook.prototype.merge_cell_above = function () {
1098 var mdc = IPython.MarkdownCell;
1082 var mdc = IPython.MarkdownCell;
1099 var rc = IPython.RawCell;
1083 var rc = IPython.RawCell;
1100 var index = this.get_selected_index();
1084 var index = this.get_selected_index();
1101 var cell = this.get_cell(index);
1085 var cell = this.get_cell(index);
1102 var render = cell.rendered;
1086 var render = cell.rendered;
1103 if (!cell.is_mergeable()) {
1087 if (!cell.is_mergeable()) {
1104 return;
1088 return;
1105 }
1089 }
1106 if (index > 0) {
1090 if (index > 0) {
1107 var upper_cell = this.get_cell(index-1);
1091 var upper_cell = this.get_cell(index-1);
1108 if (!upper_cell.is_mergeable()) {
1092 if (!upper_cell.is_mergeable()) {
1109 return;
1093 return;
1110 }
1094 }
1111 var upper_text = upper_cell.get_text();
1095 var upper_text = upper_cell.get_text();
1112 var text = cell.get_text();
1096 var text = cell.get_text();
1113 if (cell instanceof IPython.CodeCell) {
1097 if (cell instanceof IPython.CodeCell) {
1114 cell.set_text(upper_text+'\n'+text);
1098 cell.set_text(upper_text+'\n'+text);
1115 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1099 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1116 cell.unrender(); // Must unrender before we set_text.
1100 cell.unrender(); // Must unrender before we set_text.
1117 cell.set_text(upper_text+'\n\n'+text);
1101 cell.set_text(upper_text+'\n\n'+text);
1118 if (render) {
1102 if (render) {
1119 // The rendered state of the final cell should match
1103 // The rendered state of the final cell should match
1120 // that of the original selected cell;
1104 // that of the original selected cell;
1121 cell.render();
1105 cell.render();
1122 }
1106 }
1123 };
1107 }
1124 this.delete_cell(index-1);
1108 this.delete_cell(index-1);
1125 this.select(this.find_cell_index(cell));
1109 this.select(this.find_cell_index(cell));
1126 };
1110 }
1127 };
1111 };
1128
1112
1129 /**
1113 /**
1130 * Combine the selected cell into the cell below it.
1114 * Combine the selected cell into the cell below it.
1131 *
1115 *
1132 * @method merge_cell_below
1116 * @method merge_cell_below
1133 */
1117 */
1134 Notebook.prototype.merge_cell_below = function () {
1118 Notebook.prototype.merge_cell_below = function () {
1135 var mdc = IPython.MarkdownCell;
1119 var mdc = IPython.MarkdownCell;
1136 var rc = IPython.RawCell;
1120 var rc = IPython.RawCell;
1137 var index = this.get_selected_index();
1121 var index = this.get_selected_index();
1138 var cell = this.get_cell(index);
1122 var cell = this.get_cell(index);
1139 var render = cell.rendered;
1123 var render = cell.rendered;
1140 if (!cell.is_mergeable()) {
1124 if (!cell.is_mergeable()) {
1141 return;
1125 return;
1142 }
1126 }
1143 if (index < this.ncells()-1) {
1127 if (index < this.ncells()-1) {
1144 var lower_cell = this.get_cell(index+1);
1128 var lower_cell = this.get_cell(index+1);
1145 if (!lower_cell.is_mergeable()) {
1129 if (!lower_cell.is_mergeable()) {
1146 return;
1130 return;
1147 }
1131 }
1148 var lower_text = lower_cell.get_text();
1132 var lower_text = lower_cell.get_text();
1149 var text = cell.get_text();
1133 var text = cell.get_text();
1150 if (cell instanceof IPython.CodeCell) {
1134 if (cell instanceof IPython.CodeCell) {
1151 cell.set_text(text+'\n'+lower_text);
1135 cell.set_text(text+'\n'+lower_text);
1152 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1136 } else if ((cell instanceof mdc) || (cell instanceof rc)) {
1153 cell.unrender(); // Must unrender before we set_text.
1137 cell.unrender(); // Must unrender before we set_text.
1154 cell.set_text(text+'\n\n'+lower_text);
1138 cell.set_text(text+'\n\n'+lower_text);
1155 if (render) {
1139 if (render) {
1156 // The rendered state of the final cell should match
1140 // The rendered state of the final cell should match
1157 // that of the original selected cell;
1141 // that of the original selected cell;
1158 cell.render();
1142 cell.render();
1159 }
1143 }
1160 };
1144 }
1161 this.delete_cell(index+1);
1145 this.delete_cell(index+1);
1162 this.select(this.find_cell_index(cell));
1146 this.select(this.find_cell_index(cell));
1163 };
1147 }
1164 };
1148 };
1165
1149
1166
1150
1167 // Cell collapsing and output clearing
1151 // Cell collapsing and output clearing
1168
1152
1169 /**
1153 /**
1170 * Hide a cell's output.
1154 * Hide a cell's output.
1171 *
1155 *
1172 * @method collapse_output
1156 * @method collapse_output
1173 * @param {Number} index A cell's numeric index
1157 * @param {Number} index A cell's numeric index
1174 */
1158 */
1175 Notebook.prototype.collapse_output = function (index) {
1159 Notebook.prototype.collapse_output = function (index) {
1176 var i = this.index_or_selected(index);
1160 var i = this.index_or_selected(index);
1177 var cell = this.get_cell(i);
1161 var cell = this.get_cell(i);
1178 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1162 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1179 cell.collapse_output();
1163 cell.collapse_output();
1180 this.set_dirty(true);
1164 this.set_dirty(true);
1181 }
1165 }
1182 };
1166 };
1183
1167
1184 /**
1168 /**
1185 * Hide each code cell's output area.
1169 * Hide each code cell's output area.
1186 *
1170 *
1187 * @method collapse_all_output
1171 * @method collapse_all_output
1188 */
1172 */
1189 Notebook.prototype.collapse_all_output = function () {
1173 Notebook.prototype.collapse_all_output = function () {
1190 $.map(this.get_cells(), function (cell, i) {
1174 $.map(this.get_cells(), function (cell, i) {
1191 if (cell instanceof IPython.CodeCell) {
1175 if (cell instanceof IPython.CodeCell) {
1192 cell.collapse_output();
1176 cell.collapse_output();
1193 }
1177 }
1194 });
1178 });
1195 // this should not be set if the `collapse` key is removed from nbformat
1179 // this should not be set if the `collapse` key is removed from nbformat
1196 this.set_dirty(true);
1180 this.set_dirty(true);
1197 };
1181 };
1198
1182
1199 /**
1183 /**
1200 * Show a cell's output.
1184 * Show a cell's output.
1201 *
1185 *
1202 * @method expand_output
1186 * @method expand_output
1203 * @param {Number} index A cell's numeric index
1187 * @param {Number} index A cell's numeric index
1204 */
1188 */
1205 Notebook.prototype.expand_output = function (index) {
1189 Notebook.prototype.expand_output = function (index) {
1206 var i = this.index_or_selected(index);
1190 var i = this.index_or_selected(index);
1207 var cell = this.get_cell(i);
1191 var cell = this.get_cell(i);
1208 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1192 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1209 cell.expand_output();
1193 cell.expand_output();
1210 this.set_dirty(true);
1194 this.set_dirty(true);
1211 }
1195 }
1212 };
1196 };
1213
1197
1214 /**
1198 /**
1215 * Expand each code cell's output area, and remove scrollbars.
1199 * Expand each code cell's output area, and remove scrollbars.
1216 *
1200 *
1217 * @method expand_all_output
1201 * @method expand_all_output
1218 */
1202 */
1219 Notebook.prototype.expand_all_output = function () {
1203 Notebook.prototype.expand_all_output = function () {
1220 $.map(this.get_cells(), function (cell, i) {
1204 $.map(this.get_cells(), function (cell, i) {
1221 if (cell instanceof IPython.CodeCell) {
1205 if (cell instanceof IPython.CodeCell) {
1222 cell.expand_output();
1206 cell.expand_output();
1223 }
1207 }
1224 });
1208 });
1225 // this should not be set if the `collapse` key is removed from nbformat
1209 // this should not be set if the `collapse` key is removed from nbformat
1226 this.set_dirty(true);
1210 this.set_dirty(true);
1227 };
1211 };
1228
1212
1229 /**
1213 /**
1230 * Clear the selected CodeCell's output area.
1214 * Clear the selected CodeCell's output area.
1231 *
1215 *
1232 * @method clear_output
1216 * @method clear_output
1233 * @param {Number} index A cell's numeric index
1217 * @param {Number} index A cell's numeric index
1234 */
1218 */
1235 Notebook.prototype.clear_output = function (index) {
1219 Notebook.prototype.clear_output = function (index) {
1236 var i = this.index_or_selected(index);
1220 var i = this.index_or_selected(index);
1237 var cell = this.get_cell(i);
1221 var cell = this.get_cell(i);
1238 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1222 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1239 cell.clear_output();
1223 cell.clear_output();
1240 this.set_dirty(true);
1224 this.set_dirty(true);
1241 }
1225 }
1242 };
1226 };
1243
1227
1244 /**
1228 /**
1245 * Clear each code cell's output area.
1229 * Clear each code cell's output area.
1246 *
1230 *
1247 * @method clear_all_output
1231 * @method clear_all_output
1248 */
1232 */
1249 Notebook.prototype.clear_all_output = function () {
1233 Notebook.prototype.clear_all_output = function () {
1250 $.map(this.get_cells(), function (cell, i) {
1234 $.map(this.get_cells(), function (cell, i) {
1251 if (cell instanceof IPython.CodeCell) {
1235 if (cell instanceof IPython.CodeCell) {
1252 cell.clear_output();
1236 cell.clear_output();
1253 }
1237 }
1254 });
1238 });
1255 this.set_dirty(true);
1239 this.set_dirty(true);
1256 };
1240 };
1257
1241
1258 /**
1242 /**
1259 * Scroll the selected CodeCell's output area.
1243 * Scroll the selected CodeCell's output area.
1260 *
1244 *
1261 * @method scroll_output
1245 * @method scroll_output
1262 * @param {Number} index A cell's numeric index
1246 * @param {Number} index A cell's numeric index
1263 */
1247 */
1264 Notebook.prototype.scroll_output = function (index) {
1248 Notebook.prototype.scroll_output = function (index) {
1265 var i = this.index_or_selected(index);
1249 var i = this.index_or_selected(index);
1266 var cell = this.get_cell(i);
1250 var cell = this.get_cell(i);
1267 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1251 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1268 cell.scroll_output();
1252 cell.scroll_output();
1269 this.set_dirty(true);
1253 this.set_dirty(true);
1270 }
1254 }
1271 };
1255 };
1272
1256
1273 /**
1257 /**
1274 * Expand each code cell's output area, and add a scrollbar for long output.
1258 * Expand each code cell's output area, and add a scrollbar for long output.
1275 *
1259 *
1276 * @method scroll_all_output
1260 * @method scroll_all_output
1277 */
1261 */
1278 Notebook.prototype.scroll_all_output = function () {
1262 Notebook.prototype.scroll_all_output = function () {
1279 $.map(this.get_cells(), function (cell, i) {
1263 $.map(this.get_cells(), function (cell, i) {
1280 if (cell instanceof IPython.CodeCell) {
1264 if (cell instanceof IPython.CodeCell) {
1281 cell.scroll_output();
1265 cell.scroll_output();
1282 }
1266 }
1283 });
1267 });
1284 // this should not be set if the `collapse` key is removed from nbformat
1268 // this should not be set if the `collapse` key is removed from nbformat
1285 this.set_dirty(true);
1269 this.set_dirty(true);
1286 };
1270 };
1287
1271
1288 /** Toggle whether a cell's output is collapsed or expanded.
1272 /** Toggle whether a cell's output is collapsed or expanded.
1289 *
1273 *
1290 * @method toggle_output
1274 * @method toggle_output
1291 * @param {Number} index A cell's numeric index
1275 * @param {Number} index A cell's numeric index
1292 */
1276 */
1293 Notebook.prototype.toggle_output = function (index) {
1277 Notebook.prototype.toggle_output = function (index) {
1294 var i = this.index_or_selected(index);
1278 var i = this.index_or_selected(index);
1295 var cell = this.get_cell(i);
1279 var cell = this.get_cell(i);
1296 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1280 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1297 cell.toggle_output();
1281 cell.toggle_output();
1298 this.set_dirty(true);
1282 this.set_dirty(true);
1299 }
1283 }
1300 };
1284 };
1301
1285
1302 /**
1286 /**
1303 * Hide/show the output of all cells.
1287 * Hide/show the output of all cells.
1304 *
1288 *
1305 * @method toggle_all_output
1289 * @method toggle_all_output
1306 */
1290 */
1307 Notebook.prototype.toggle_all_output = function () {
1291 Notebook.prototype.toggle_all_output = function () {
1308 $.map(this.get_cells(), function (cell, i) {
1292 $.map(this.get_cells(), function (cell, i) {
1309 if (cell instanceof IPython.CodeCell) {
1293 if (cell instanceof IPython.CodeCell) {
1310 cell.toggle_output();
1294 cell.toggle_output();
1311 }
1295 }
1312 });
1296 });
1313 // this should not be set if the `collapse` key is removed from nbformat
1297 // this should not be set if the `collapse` key is removed from nbformat
1314 this.set_dirty(true);
1298 this.set_dirty(true);
1315 };
1299 };
1316
1300
1317 /**
1301 /**
1318 * Toggle a scrollbar for long cell outputs.
1302 * Toggle a scrollbar for long cell outputs.
1319 *
1303 *
1320 * @method toggle_output_scroll
1304 * @method toggle_output_scroll
1321 * @param {Number} index A cell's numeric index
1305 * @param {Number} index A cell's numeric index
1322 */
1306 */
1323 Notebook.prototype.toggle_output_scroll = function (index) {
1307 Notebook.prototype.toggle_output_scroll = function (index) {
1324 var i = this.index_or_selected(index);
1308 var i = this.index_or_selected(index);
1325 var cell = this.get_cell(i);
1309 var cell = this.get_cell(i);
1326 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1310 if (cell !== null && (cell instanceof IPython.CodeCell)) {
1327 cell.toggle_output_scroll();
1311 cell.toggle_output_scroll();
1328 this.set_dirty(true);
1312 this.set_dirty(true);
1329 }
1313 }
1330 };
1314 };
1331
1315
1332 /**
1316 /**
1333 * Toggle the scrolling of long output on all cells.
1317 * Toggle the scrolling of long output on all cells.
1334 *
1318 *
1335 * @method toggle_all_output_scrolling
1319 * @method toggle_all_output_scrolling
1336 */
1320 */
1337 Notebook.prototype.toggle_all_output_scroll = function () {
1321 Notebook.prototype.toggle_all_output_scroll = function () {
1338 $.map(this.get_cells(), function (cell, i) {
1322 $.map(this.get_cells(), function (cell, i) {
1339 if (cell instanceof IPython.CodeCell) {
1323 if (cell instanceof IPython.CodeCell) {
1340 cell.toggle_output_scroll();
1324 cell.toggle_output_scroll();
1341 }
1325 }
1342 });
1326 });
1343 // this should not be set if the `collapse` key is removed from nbformat
1327 // this should not be set if the `collapse` key is removed from nbformat
1344 this.set_dirty(true);
1328 this.set_dirty(true);
1345 };
1329 };
1346
1330
1347 // Other cell functions: line numbers, ...
1331 // Other cell functions: line numbers, ...
1348
1332
1349 /**
1333 /**
1350 * Toggle line numbers in the selected cell's input area.
1334 * Toggle line numbers in the selected cell's input area.
1351 *
1335 *
1352 * @method cell_toggle_line_numbers
1336 * @method cell_toggle_line_numbers
1353 */
1337 */
1354 Notebook.prototype.cell_toggle_line_numbers = function() {
1338 Notebook.prototype.cell_toggle_line_numbers = function() {
1355 this.get_selected_cell().toggle_line_numbers();
1339 this.get_selected_cell().toggle_line_numbers();
1356 };
1340 };
1357
1341
1358 // Session related things
1342 // Session related things
1359
1343
1360 /**
1344 /**
1361 * Start a new session and set it on each code cell.
1345 * Start a new session and set it on each code cell.
1362 *
1346 *
1363 * @method start_session
1347 * @method start_session
1364 */
1348 */
1365 Notebook.prototype.start_session = function () {
1349 Notebook.prototype.start_session = function () {
1366 this.session = new IPython.Session(this.notebook_name, this.notebook_path, this);
1350 this.session = new IPython.Session(this, this.options);
1367 this.session.start($.proxy(this._session_started, this));
1351 this.session.start($.proxy(this._session_started, this));
1368 };
1352 };
1369
1353
1370
1354
1371 /**
1355 /**
1372 * Once a session is started, link the code cells to the kernel and pass the
1356 * Once a session is started, link the code cells to the kernel and pass the
1373 * comm manager to the widget manager
1357 * comm manager to the widget manager
1374 *
1358 *
1375 */
1359 */
1376 Notebook.prototype._session_started = function(){
1360 Notebook.prototype._session_started = function(){
1377 this.kernel = this.session.kernel;
1361 this.kernel = this.session.kernel;
1378 var ncells = this.ncells();
1362 var ncells = this.ncells();
1379 for (var i=0; i<ncells; i++) {
1363 for (var i=0; i<ncells; i++) {
1380 var cell = this.get_cell(i);
1364 var cell = this.get_cell(i);
1381 if (cell instanceof IPython.CodeCell) {
1365 if (cell instanceof IPython.CodeCell) {
1382 cell.set_kernel(this.session.kernel);
1366 cell.set_kernel(this.session.kernel);
1383 };
1367 }
1384 };
1368 }
1385 };
1369 };
1386
1370
1387 /**
1371 /**
1388 * Prompt the user to restart the IPython kernel.
1372 * Prompt the user to restart the IPython kernel.
1389 *
1373 *
1390 * @method restart_kernel
1374 * @method restart_kernel
1391 */
1375 */
1392 Notebook.prototype.restart_kernel = function () {
1376 Notebook.prototype.restart_kernel = function () {
1393 var that = this;
1377 var that = this;
1394 IPython.dialog.modal({
1378 IPython.dialog.modal({
1395 title : "Restart kernel or continue running?",
1379 title : "Restart kernel or continue running?",
1396 body : $("<p/>").text(
1380 body : $("<p/>").text(
1397 'Do you want to restart the current kernel? You will lose all variables defined in it.'
1381 'Do you want to restart the current kernel? You will lose all variables defined in it.'
1398 ),
1382 ),
1399 buttons : {
1383 buttons : {
1400 "Continue running" : {},
1384 "Continue running" : {},
1401 "Restart" : {
1385 "Restart" : {
1402 "class" : "btn-danger",
1386 "class" : "btn-danger",
1403 "click" : function() {
1387 "click" : function() {
1404 that.session.restart_kernel();
1388 that.session.restart_kernel();
1405 }
1389 }
1406 }
1390 }
1407 }
1391 }
1408 });
1392 });
1409 };
1393 };
1410
1394
1411 /**
1395 /**
1412 * Execute or render cell outputs and go into command mode.
1396 * Execute or render cell outputs and go into command mode.
1413 *
1397 *
1414 * @method execute_cell
1398 * @method execute_cell
1415 */
1399 */
1416 Notebook.prototype.execute_cell = function () {
1400 Notebook.prototype.execute_cell = function () {
1417 // mode = shift, ctrl, alt
1401 // mode = shift, ctrl, alt
1418 var cell = this.get_selected_cell();
1402 var cell = this.get_selected_cell();
1419 var cell_index = this.find_cell_index(cell);
1403 var cell_index = this.find_cell_index(cell);
1420
1404
1421 cell.execute();
1405 cell.execute();
1422 this.command_mode();
1406 this.command_mode();
1423 cell.focus_cell();
1407 cell.focus_cell();
1424 this.set_dirty(true);
1408 this.set_dirty(true);
1425 }
1409 };
1426
1410
1427 /**
1411 /**
1428 * Execute or render cell outputs and insert a new cell below.
1412 * Execute or render cell outputs and insert a new cell below.
1429 *
1413 *
1430 * @method execute_cell_and_insert_below
1414 * @method execute_cell_and_insert_below
1431 */
1415 */
1432 Notebook.prototype.execute_cell_and_insert_below = function () {
1416 Notebook.prototype.execute_cell_and_insert_below = function () {
1433 var cell = this.get_selected_cell();
1417 var cell = this.get_selected_cell();
1434 var cell_index = this.find_cell_index(cell);
1418 var cell_index = this.find_cell_index(cell);
1435
1419
1436 cell.execute();
1420 cell.execute();
1437
1421
1438 // If we are at the end always insert a new cell and return
1422 // If we are at the end always insert a new cell and return
1439 if (cell_index === (this.ncells()-1)) {
1423 if (cell_index === (this.ncells()-1)) {
1440 this.insert_cell_below('code');
1424 this.insert_cell_below('code');
1441 this.select(cell_index+1);
1425 this.select(cell_index+1);
1442 this.edit_mode();
1426 this.edit_mode();
1443 this.scroll_to_bottom();
1427 this.scroll_to_bottom();
1444 this.set_dirty(true);
1428 this.set_dirty(true);
1445 return;
1429 return;
1446 }
1430 }
1447
1431
1448 this.insert_cell_below('code');
1432 this.insert_cell_below('code');
1449 this.select(cell_index+1);
1433 this.select(cell_index+1);
1450 this.edit_mode();
1434 this.edit_mode();
1451 this.set_dirty(true);
1435 this.set_dirty(true);
1452 };
1436 };
1453
1437
1454 /**
1438 /**
1455 * Execute or render cell outputs and select the next cell.
1439 * Execute or render cell outputs and select the next cell.
1456 *
1440 *
1457 * @method execute_cell_and_select_below
1441 * @method execute_cell_and_select_below
1458 */
1442 */
1459 Notebook.prototype.execute_cell_and_select_below = function () {
1443 Notebook.prototype.execute_cell_and_select_below = function () {
1460
1444
1461 var cell = this.get_selected_cell();
1445 var cell = this.get_selected_cell();
1462 var cell_index = this.find_cell_index(cell);
1446 var cell_index = this.find_cell_index(cell);
1463
1447
1464 cell.execute();
1448 cell.execute();
1465
1449
1466 // If we are at the end always insert a new cell and return
1450 // If we are at the end always insert a new cell and return
1467 if (cell_index === (this.ncells()-1)) {
1451 if (cell_index === (this.ncells()-1)) {
1468 this.insert_cell_below('code');
1452 this.insert_cell_below('code');
1469 this.select(cell_index+1);
1453 this.select(cell_index+1);
1470 this.edit_mode();
1454 this.edit_mode();
1471 this.scroll_to_bottom();
1455 this.scroll_to_bottom();
1472 this.set_dirty(true);
1456 this.set_dirty(true);
1473 return;
1457 return;
1474 }
1458 }
1475
1459
1476 this.select(cell_index+1);
1460 this.select(cell_index+1);
1477 this.get_cell(cell_index+1).focus_cell();
1461 this.get_cell(cell_index+1).focus_cell();
1478 this.set_dirty(true);
1462 this.set_dirty(true);
1479 };
1463 };
1480
1464
1481 /**
1465 /**
1482 * Execute all cells below the selected cell.
1466 * Execute all cells below the selected cell.
1483 *
1467 *
1484 * @method execute_cells_below
1468 * @method execute_cells_below
1485 */
1469 */
1486 Notebook.prototype.execute_cells_below = function () {
1470 Notebook.prototype.execute_cells_below = function () {
1487 this.execute_cell_range(this.get_selected_index(), this.ncells());
1471 this.execute_cell_range(this.get_selected_index(), this.ncells());
1488 this.scroll_to_bottom();
1472 this.scroll_to_bottom();
1489 };
1473 };
1490
1474
1491 /**
1475 /**
1492 * Execute all cells above the selected cell.
1476 * Execute all cells above the selected cell.
1493 *
1477 *
1494 * @method execute_cells_above
1478 * @method execute_cells_above
1495 */
1479 */
1496 Notebook.prototype.execute_cells_above = function () {
1480 Notebook.prototype.execute_cells_above = function () {
1497 this.execute_cell_range(0, this.get_selected_index());
1481 this.execute_cell_range(0, this.get_selected_index());
1498 };
1482 };
1499
1483
1500 /**
1484 /**
1501 * Execute all cells.
1485 * Execute all cells.
1502 *
1486 *
1503 * @method execute_all_cells
1487 * @method execute_all_cells
1504 */
1488 */
1505 Notebook.prototype.execute_all_cells = function () {
1489 Notebook.prototype.execute_all_cells = function () {
1506 this.execute_cell_range(0, this.ncells());
1490 this.execute_cell_range(0, this.ncells());
1507 this.scroll_to_bottom();
1491 this.scroll_to_bottom();
1508 };
1492 };
1509
1493
1510 /**
1494 /**
1511 * Execute a contiguous range of cells.
1495 * Execute a contiguous range of cells.
1512 *
1496 *
1513 * @method execute_cell_range
1497 * @method execute_cell_range
1514 * @param {Number} start Index of the first cell to execute (inclusive)
1498 * @param {Number} start Index of the first cell to execute (inclusive)
1515 * @param {Number} end Index of the last cell to execute (exclusive)
1499 * @param {Number} end Index of the last cell to execute (exclusive)
1516 */
1500 */
1517 Notebook.prototype.execute_cell_range = function (start, end) {
1501 Notebook.prototype.execute_cell_range = function (start, end) {
1518 for (var i=start; i<end; i++) {
1502 for (var i=start; i<end; i++) {
1519 this.select(i);
1503 this.select(i);
1520 this.execute_cell();
1504 this.execute_cell();
1521 };
1505 }
1522 };
1506 };
1523
1507
1524 // Persistance and loading
1508 // Persistance and loading
1525
1509
1526 /**
1510 /**
1527 * Getter method for this notebook's name.
1511 * Getter method for this notebook's name.
1528 *
1512 *
1529 * @method get_notebook_name
1513 * @method get_notebook_name
1530 * @return {String} This notebook's name
1514 * @return {String} This notebook's name (excluding file extension)
1531 */
1515 */
1532 Notebook.prototype.get_notebook_name = function () {
1516 Notebook.prototype.get_notebook_name = function () {
1533 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
1517 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
1534 return nbname;
1518 return nbname;
1535 };
1519 };
1536
1520
1537 /**
1521 /**
1538 * Setter method for this notebook's name.
1522 * Setter method for this notebook's name.
1539 *
1523 *
1540 * @method set_notebook_name
1524 * @method set_notebook_name
1541 * @param {String} name A new name for this notebook
1525 * @param {String} name A new name for this notebook
1542 */
1526 */
1543 Notebook.prototype.set_notebook_name = function (name) {
1527 Notebook.prototype.set_notebook_name = function (name) {
1544 this.notebook_name = name;
1528 this.notebook_name = name;
1545 };
1529 };
1546
1530
1547 /**
1531 /**
1548 * Check that a notebook's name is valid.
1532 * Check that a notebook's name is valid.
1549 *
1533 *
1550 * @method test_notebook_name
1534 * @method test_notebook_name
1551 * @param {String} nbname A name for this notebook
1535 * @param {String} nbname A name for this notebook
1552 * @return {Boolean} True if the name is valid, false if invalid
1536 * @return {Boolean} True if the name is valid, false if invalid
1553 */
1537 */
1554 Notebook.prototype.test_notebook_name = function (nbname) {
1538 Notebook.prototype.test_notebook_name = function (nbname) {
1555 nbname = nbname || '';
1539 nbname = nbname || '';
1556 if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) {
1540 if (nbname.length>0 && !this.notebook_name_blacklist_re.test(nbname)) {
1557 return true;
1541 return true;
1558 } else {
1542 } else {
1559 return false;
1543 return false;
1560 };
1544 }
1561 };
1545 };
1562
1546
1563 /**
1547 /**
1564 * Load a notebook from JSON (.ipynb).
1548 * Load a notebook from JSON (.ipynb).
1565 *
1549 *
1566 * This currently handles one worksheet: others are deleted.
1550 * This currently handles one worksheet: others are deleted.
1567 *
1551 *
1568 * @method fromJSON
1552 * @method fromJSON
1569 * @param {Object} data JSON representation of a notebook
1553 * @param {Object} data JSON representation of a notebook
1570 */
1554 */
1571 Notebook.prototype.fromJSON = function (data) {
1555 Notebook.prototype.fromJSON = function (data) {
1572 var content = data.content;
1556 var content = data.content;
1573 var ncells = this.ncells();
1557 var ncells = this.ncells();
1574 var i;
1558 var i;
1575 for (i=0; i<ncells; i++) {
1559 for (i=0; i<ncells; i++) {
1576 // Always delete cell 0 as they get renumbered as they are deleted.
1560 // Always delete cell 0 as they get renumbered as they are deleted.
1577 this.delete_cell(0);
1561 this.delete_cell(0);
1578 };
1562 }
1579 // Save the metadata and name.
1563 // Save the metadata and name.
1580 this.metadata = content.metadata;
1564 this.metadata = content.metadata;
1581 this.notebook_name = data.name;
1565 this.notebook_name = data.name;
1582 // Only handle 1 worksheet for now.
1566 // Only handle 1 worksheet for now.
1583 var worksheet = content.worksheets[0];
1567 var worksheet = content.worksheets[0];
1584 if (worksheet !== undefined) {
1568 if (worksheet !== undefined) {
1585 if (worksheet.metadata) {
1569 if (worksheet.metadata) {
1586 this.worksheet_metadata = worksheet.metadata;
1570 this.worksheet_metadata = worksheet.metadata;
1587 }
1571 }
1588 var new_cells = worksheet.cells;
1572 var new_cells = worksheet.cells;
1589 ncells = new_cells.length;
1573 ncells = new_cells.length;
1590 var cell_data = null;
1574 var cell_data = null;
1591 var new_cell = null;
1575 var new_cell = null;
1592 for (i=0; i<ncells; i++) {
1576 for (i=0; i<ncells; i++) {
1593 cell_data = new_cells[i];
1577 cell_data = new_cells[i];
1594 // VERSIONHACK: plaintext -> raw
1578 // VERSIONHACK: plaintext -> raw
1595 // handle never-released plaintext name for raw cells
1579 // handle never-released plaintext name for raw cells
1596 if (cell_data.cell_type === 'plaintext'){
1580 if (cell_data.cell_type === 'plaintext'){
1597 cell_data.cell_type = 'raw';
1581 cell_data.cell_type = 'raw';
1598 }
1582 }
1599
1583
1600 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1584 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1601 new_cell.fromJSON(cell_data);
1585 new_cell.fromJSON(cell_data);
1602 };
1586 }
1603 };
1587 }
1604 if (content.worksheets.length > 1) {
1588 if (content.worksheets.length > 1) {
1605 IPython.dialog.modal({
1589 IPython.dialog.modal({
1606 title : "Multiple worksheets",
1590 title : "Multiple worksheets",
1607 body : "This notebook has " + data.worksheets.length + " worksheets, " +
1591 body : "This notebook has " + data.worksheets.length + " worksheets, " +
1608 "but this version of IPython can only handle the first. " +
1592 "but this version of IPython can only handle the first. " +
1609 "If you save this notebook, worksheets after the first will be lost.",
1593 "If you save this notebook, worksheets after the first will be lost.",
1610 buttons : {
1594 buttons : {
1611 OK : {
1595 OK : {
1612 class : "btn-danger"
1596 class : "btn-danger"
1613 }
1597 }
1614 }
1598 }
1615 });
1599 });
1616 }
1600 }
1617 };
1601 };
1618
1602
1619 /**
1603 /**
1620 * Dump this notebook into a JSON-friendly object.
1604 * Dump this notebook into a JSON-friendly object.
1621 *
1605 *
1622 * @method toJSON
1606 * @method toJSON
1623 * @return {Object} A JSON-friendly representation of this notebook.
1607 * @return {Object} A JSON-friendly representation of this notebook.
1624 */
1608 */
1625 Notebook.prototype.toJSON = function () {
1609 Notebook.prototype.toJSON = function () {
1626 var cells = this.get_cells();
1610 var cells = this.get_cells();
1627 var ncells = cells.length;
1611 var ncells = cells.length;
1628 var cell_array = new Array(ncells);
1612 var cell_array = new Array(ncells);
1629 for (var i=0; i<ncells; i++) {
1613 for (var i=0; i<ncells; i++) {
1630 cell_array[i] = cells[i].toJSON();
1614 cell_array[i] = cells[i].toJSON();
1631 };
1615 }
1632 var data = {
1616 var data = {
1633 // Only handle 1 worksheet for now.
1617 // Only handle 1 worksheet for now.
1634 worksheets : [{
1618 worksheets : [{
1635 cells: cell_array,
1619 cells: cell_array,
1636 metadata: this.worksheet_metadata
1620 metadata: this.worksheet_metadata
1637 }],
1621 }],
1638 metadata : this.metadata
1622 metadata : this.metadata
1639 };
1623 };
1640 return data;
1624 return data;
1641 };
1625 };
1642
1626
1643 /**
1627 /**
1644 * Start an autosave timer, for periodically saving the notebook.
1628 * Start an autosave timer, for periodically saving the notebook.
1645 *
1629 *
1646 * @method set_autosave_interval
1630 * @method set_autosave_interval
1647 * @param {Integer} interval the autosave interval in milliseconds
1631 * @param {Integer} interval the autosave interval in milliseconds
1648 */
1632 */
1649 Notebook.prototype.set_autosave_interval = function (interval) {
1633 Notebook.prototype.set_autosave_interval = function (interval) {
1650 var that = this;
1634 var that = this;
1651 // clear previous interval, so we don't get simultaneous timers
1635 // clear previous interval, so we don't get simultaneous timers
1652 if (this.autosave_timer) {
1636 if (this.autosave_timer) {
1653 clearInterval(this.autosave_timer);
1637 clearInterval(this.autosave_timer);
1654 }
1638 }
1655
1639
1656 this.autosave_interval = this.minimum_autosave_interval = interval;
1640 this.autosave_interval = this.minimum_autosave_interval = interval;
1657 if (interval) {
1641 if (interval) {
1658 this.autosave_timer = setInterval(function() {
1642 this.autosave_timer = setInterval(function() {
1659 if (that.dirty) {
1643 if (that.dirty) {
1660 that.save_notebook();
1644 that.save_notebook();
1661 }
1645 }
1662 }, interval);
1646 }, interval);
1663 $([IPython.events]).trigger("autosave_enabled.Notebook", interval);
1647 $([IPython.events]).trigger("autosave_enabled.Notebook", interval);
1664 } else {
1648 } else {
1665 this.autosave_timer = null;
1649 this.autosave_timer = null;
1666 $([IPython.events]).trigger("autosave_disabled.Notebook");
1650 $([IPython.events]).trigger("autosave_disabled.Notebook");
1667 };
1651 }
1668 };
1652 };
1669
1653
1670 /**
1654 /**
1671 * Save this notebook on the server.
1655 * Save this notebook on the server.
1672 *
1656 *
1673 * @method save_notebook
1657 * @method save_notebook
1674 */
1658 */
1675 Notebook.prototype.save_notebook = function (extra_settings) {
1659 Notebook.prototype.save_notebook = function (extra_settings) {
1676 // Create a JSON model to be sent to the server.
1660 // Create a JSON model to be sent to the server.
1677 var model = {};
1661 var model = {};
1678 model.name = this.notebook_name;
1662 model.name = this.notebook_name;
1679 model.path = this.notebook_path;
1663 model.path = this.notebook_path;
1680 model.content = this.toJSON();
1664 model.content = this.toJSON();
1681 model.content.nbformat = this.nbformat;
1665 model.content.nbformat = this.nbformat;
1682 model.content.nbformat_minor = this.nbformat_minor;
1666 model.content.nbformat_minor = this.nbformat_minor;
1683 // time the ajax call for autosave tuning purposes.
1667 // time the ajax call for autosave tuning purposes.
1684 var start = new Date().getTime();
1668 var start = new Date().getTime();
1685 // We do the call with settings so we can set cache to false.
1669 // We do the call with settings so we can set cache to false.
1686 var settings = {
1670 var settings = {
1687 processData : false,
1671 processData : false,
1688 cache : false,
1672 cache : false,
1689 type : "PUT",
1673 type : "PUT",
1690 data : JSON.stringify(model),
1674 data : JSON.stringify(model),
1691 headers : {'Content-Type': 'application/json'},
1675 headers : {'Content-Type': 'application/json'},
1692 success : $.proxy(this.save_notebook_success, this, start),
1676 success : $.proxy(this.save_notebook_success, this, start),
1693 error : $.proxy(this.save_notebook_error, this)
1677 error : $.proxy(this.save_notebook_error, this)
1694 };
1678 };
1695 if (extra_settings) {
1679 if (extra_settings) {
1696 for (var key in extra_settings) {
1680 for (var key in extra_settings) {
1697 settings[key] = extra_settings[key];
1681 settings[key] = extra_settings[key];
1698 }
1682 }
1699 }
1683 }
1700 $([IPython.events]).trigger('notebook_saving.Notebook');
1684 $([IPython.events]).trigger('notebook_saving.Notebook');
1701 var url = utils.url_join_encode(
1685 var url = utils.url_join_encode(
1702 this._baseProjectUrl,
1686 this.base_url,
1703 'api/notebooks',
1687 'api/notebooks',
1704 this.notebook_path,
1688 this.notebook_path,
1705 this.notebook_name
1689 this.notebook_name
1706 );
1690 );
1707 $.ajax(url, settings);
1691 $.ajax(url, settings);
1708 };
1692 };
1709
1693
1710 /**
1694 /**
1711 * Success callback for saving a notebook.
1695 * Success callback for saving a notebook.
1712 *
1696 *
1713 * @method save_notebook_success
1697 * @method save_notebook_success
1714 * @param {Integer} start the time when the save request started
1698 * @param {Integer} start the time when the save request started
1715 * @param {Object} data JSON representation of a notebook
1699 * @param {Object} data JSON representation of a notebook
1716 * @param {String} status Description of response status
1700 * @param {String} status Description of response status
1717 * @param {jqXHR} xhr jQuery Ajax object
1701 * @param {jqXHR} xhr jQuery Ajax object
1718 */
1702 */
1719 Notebook.prototype.save_notebook_success = function (start, data, status, xhr) {
1703 Notebook.prototype.save_notebook_success = function (start, data, status, xhr) {
1720 this.set_dirty(false);
1704 this.set_dirty(false);
1721 $([IPython.events]).trigger('notebook_saved.Notebook');
1705 $([IPython.events]).trigger('notebook_saved.Notebook');
1722 this._update_autosave_interval(start);
1706 this._update_autosave_interval(start);
1723 if (this._checkpoint_after_save) {
1707 if (this._checkpoint_after_save) {
1724 this.create_checkpoint();
1708 this.create_checkpoint();
1725 this._checkpoint_after_save = false;
1709 this._checkpoint_after_save = false;
1726 };
1710 }
1727 };
1711 };
1728
1712
1729 /**
1713 /**
1730 * update the autosave interval based on how long the last save took
1714 * update the autosave interval based on how long the last save took
1731 *
1715 *
1732 * @method _update_autosave_interval
1716 * @method _update_autosave_interval
1733 * @param {Integer} timestamp when the save request started
1717 * @param {Integer} timestamp when the save request started
1734 */
1718 */
1735 Notebook.prototype._update_autosave_interval = function (start) {
1719 Notebook.prototype._update_autosave_interval = function (start) {
1736 var duration = (new Date().getTime() - start);
1720 var duration = (new Date().getTime() - start);
1737 if (this.autosave_interval) {
1721 if (this.autosave_interval) {
1738 // new save interval: higher of 10x save duration or parameter (default 30 seconds)
1722 // new save interval: higher of 10x save duration or parameter (default 30 seconds)
1739 var interval = Math.max(10 * duration, this.minimum_autosave_interval);
1723 var interval = Math.max(10 * duration, this.minimum_autosave_interval);
1740 // round to 10 seconds, otherwise we will be setting a new interval too often
1724 // round to 10 seconds, otherwise we will be setting a new interval too often
1741 interval = 10000 * Math.round(interval / 10000);
1725 interval = 10000 * Math.round(interval / 10000);
1742 // set new interval, if it's changed
1726 // set new interval, if it's changed
1743 if (interval != this.autosave_interval) {
1727 if (interval != this.autosave_interval) {
1744 this.set_autosave_interval(interval);
1728 this.set_autosave_interval(interval);
1745 }
1729 }
1746 }
1730 }
1747 };
1731 };
1748
1732
1749 /**
1733 /**
1750 * Failure callback for saving a notebook.
1734 * Failure callback for saving a notebook.
1751 *
1735 *
1752 * @method save_notebook_error
1736 * @method save_notebook_error
1753 * @param {jqXHR} xhr jQuery Ajax object
1737 * @param {jqXHR} xhr jQuery Ajax object
1754 * @param {String} status Description of response status
1738 * @param {String} status Description of response status
1755 * @param {String} error HTTP error message
1739 * @param {String} error HTTP error message
1756 */
1740 */
1757 Notebook.prototype.save_notebook_error = function (xhr, status, error) {
1741 Notebook.prototype.save_notebook_error = function (xhr, status, error) {
1758 $([IPython.events]).trigger('notebook_save_failed.Notebook', [xhr, status, error]);
1742 $([IPython.events]).trigger('notebook_save_failed.Notebook', [xhr, status, error]);
1759 };
1743 };
1760
1744
1761 Notebook.prototype.new_notebook = function(){
1745 Notebook.prototype.new_notebook = function(){
1762 var path = this.notebook_path;
1746 var path = this.notebook_path;
1763 var base_project_url = this._baseProjectUrl;
1747 var base_url = this.base_url;
1764 var settings = {
1748 var settings = {
1765 processData : false,
1749 processData : false,
1766 cache : false,
1750 cache : false,
1767 type : "POST",
1751 type : "POST",
1768 dataType : "json",
1752 dataType : "json",
1769 async : false,
1753 async : false,
1770 success : function (data, status, xhr){
1754 success : function (data, status, xhr){
1771 var notebook_name = data.name;
1755 var notebook_name = data.name;
1772 window.open(
1756 window.open(
1773 utils.url_join_encode(
1757 utils.url_join_encode(
1774 base_project_url,
1758 base_url,
1775 'notebooks',
1759 'notebooks',
1776 path,
1760 path,
1777 notebook_name
1761 notebook_name
1778 ),
1762 ),
1779 '_blank'
1763 '_blank'
1780 );
1764 );
1781 }
1765 }
1782 };
1766 };
1783 var url = utils.url_join_encode(
1767 var url = utils.url_join_encode(
1784 base_project_url,
1768 base_url,
1785 'api/notebooks',
1769 'api/notebooks',
1786 path
1770 path
1787 );
1771 );
1788 $.ajax(url,settings);
1772 $.ajax(url,settings);
1789 };
1773 };
1790
1774
1791
1775
1792 Notebook.prototype.copy_notebook = function(){
1776 Notebook.prototype.copy_notebook = function(){
1793 var path = this.notebook_path;
1777 var path = this.notebook_path;
1794 var base_project_url = this._baseProjectUrl;
1778 var base_url = this.base_url;
1795 var settings = {
1779 var settings = {
1796 processData : false,
1780 processData : false,
1797 cache : false,
1781 cache : false,
1798 type : "POST",
1782 type : "POST",
1799 dataType : "json",
1783 dataType : "json",
1800 data : JSON.stringify({copy_from : this.notebook_name}),
1784 data : JSON.stringify({copy_from : this.notebook_name}),
1801 async : false,
1785 async : false,
1802 success : function (data, status, xhr) {
1786 success : function (data, status, xhr) {
1803 window.open(utils.url_join_encode(
1787 window.open(utils.url_join_encode(
1804 base_project_url,
1788 base_url,
1805 'notebooks',
1789 'notebooks',
1806 data.path,
1790 data.path,
1807 data.name
1791 data.name
1808 ), '_blank');
1792 ), '_blank');
1809 }
1793 }
1810 };
1794 };
1811 var url = utils.url_join_encode(
1795 var url = utils.url_join_encode(
1812 base_project_url,
1796 base_url,
1813 'api/notebooks',
1797 'api/notebooks',
1814 path
1798 path
1815 );
1799 );
1816 $.ajax(url,settings);
1800 $.ajax(url,settings);
1817 };
1801 };
1818
1802
1819 Notebook.prototype.rename = function (nbname) {
1803 Notebook.prototype.rename = function (nbname) {
1820 var that = this;
1804 var that = this;
1821 var data = {name: nbname + '.ipynb'};
1805 if (!nbname.match(/\.ipynb$/)) {
1806 nbname = nbname + ".ipynb";
1807 }
1808 var data = {name: nbname};
1822 var settings = {
1809 var settings = {
1823 processData : false,
1810 processData : false,
1824 cache : false,
1811 cache : false,
1825 type : "PATCH",
1812 type : "PATCH",
1826 data : JSON.stringify(data),
1813 data : JSON.stringify(data),
1827 dataType: "json",
1814 dataType: "json",
1828 headers : {'Content-Type': 'application/json'},
1815 headers : {'Content-Type': 'application/json'},
1829 success : $.proxy(that.rename_success, this),
1816 success : $.proxy(that.rename_success, this),
1830 error : $.proxy(that.rename_error, this)
1817 error : $.proxy(that.rename_error, this)
1831 };
1818 };
1832 $([IPython.events]).trigger('rename_notebook.Notebook', data);
1819 $([IPython.events]).trigger('rename_notebook.Notebook', data);
1833 var url = utils.url_join_encode(
1820 var url = utils.url_join_encode(
1834 this._baseProjectUrl,
1821 this.base_url,
1835 'api/notebooks',
1822 'api/notebooks',
1836 this.notebook_path,
1823 this.notebook_path,
1837 this.notebook_name
1824 this.notebook_name
1838 );
1825 );
1839 $.ajax(url, settings);
1826 $.ajax(url, settings);
1840 };
1827 };
1841
1828
1842 Notebook.prototype.delete = function () {
1829 Notebook.prototype.delete = function () {
1843 var that = this;
1830 var that = this;
1844 var settings = {
1831 var settings = {
1845 processData : false,
1832 processData : false,
1846 cache : false,
1833 cache : false,
1847 type : "DELETE",
1834 type : "DELETE",
1848 dataType: "json",
1835 dataType: "json",
1849 };
1836 };
1850 var url = utils.url_join_encode(
1837 var url = utils.url_join_encode(
1851 this._baseProjectUrl,
1838 this.base_url,
1852 'api/notebooks',
1839 'api/notebooks',
1853 this.notebook_path,
1840 this.notebook_path,
1854 this.notebook_name
1841 this.notebook_name
1855 );
1842 );
1856 $.ajax(url, settings);
1843 $.ajax(url, settings);
1857 };
1844 };
1858
1845
1859
1846
1860 Notebook.prototype.rename_success = function (json, status, xhr) {
1847 Notebook.prototype.rename_success = function (json, status, xhr) {
1861 this.notebook_name = json.name;
1848 var name = this.notebook_name = json.name;
1862 var name = this.notebook_name;
1863 var path = json.path;
1849 var path = json.path;
1864 this.session.rename_notebook(name, path);
1850 this.session.rename_notebook(name, path);
1865 $([IPython.events]).trigger('notebook_renamed.Notebook', json);
1851 $([IPython.events]).trigger('notebook_renamed.Notebook', json);
1866 }
1852 };
1867
1853
1868 Notebook.prototype.rename_error = function (xhr, status, error) {
1854 Notebook.prototype.rename_error = function (xhr, status, error) {
1869 var that = this;
1855 var that = this;
1870 var dialog = $('<div/>').append(
1856 var dialog = $('<div/>').append(
1871 $("<p/>").addClass("rename-message")
1857 $("<p/>").addClass("rename-message")
1872 .text('This notebook name already exists.')
1858 .text('This notebook name already exists.')
1873 )
1859 );
1874 $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]);
1860 $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]);
1875 IPython.dialog.modal({
1861 IPython.dialog.modal({
1876 title: "Notebook Rename Error!",
1862 title: "Notebook Rename Error!",
1877 body: dialog,
1863 body: dialog,
1878 buttons : {
1864 buttons : {
1879 "Cancel": {},
1865 "Cancel": {},
1880 "OK": {
1866 "OK": {
1881 class: "btn-primary",
1867 class: "btn-primary",
1882 click: function () {
1868 click: function () {
1883 IPython.save_widget.rename_notebook();
1869 IPython.save_widget.rename_notebook();
1884 }}
1870 }}
1885 },
1871 },
1886 open : function (event, ui) {
1872 open : function (event, ui) {
1887 var that = $(this);
1873 var that = $(this);
1888 // Upon ENTER, click the OK button.
1874 // Upon ENTER, click the OK button.
1889 that.find('input[type="text"]').keydown(function (event, ui) {
1875 that.find('input[type="text"]').keydown(function (event, ui) {
1890 if (event.which === utils.keycodes.ENTER) {
1876 if (event.which === utils.keycodes.ENTER) {
1891 that.find('.btn-primary').first().click();
1877 that.find('.btn-primary').first().click();
1892 }
1878 }
1893 });
1879 });
1894 that.find('input[type="text"]').focus();
1880 that.find('input[type="text"]').focus();
1895 }
1881 }
1896 });
1882 });
1897 }
1883 };
1898
1884
1899 /**
1885 /**
1900 * Request a notebook's data from the server.
1886 * Request a notebook's data from the server.
1901 *
1887 *
1902 * @method load_notebook
1888 * @method load_notebook
1903 * @param {String} notebook_name and path A notebook to load
1889 * @param {String} notebook_name and path A notebook to load
1904 */
1890 */
1905 Notebook.prototype.load_notebook = function (notebook_name, notebook_path) {
1891 Notebook.prototype.load_notebook = function (notebook_name, notebook_path) {
1906 var that = this;
1892 var that = this;
1907 this.notebook_name = notebook_name;
1893 this.notebook_name = notebook_name;
1908 this.notebook_path = notebook_path;
1894 this.notebook_path = notebook_path;
1909 // We do the call with settings so we can set cache to false.
1895 // We do the call with settings so we can set cache to false.
1910 var settings = {
1896 var settings = {
1911 processData : false,
1897 processData : false,
1912 cache : false,
1898 cache : false,
1913 type : "GET",
1899 type : "GET",
1914 dataType : "json",
1900 dataType : "json",
1915 success : $.proxy(this.load_notebook_success,this),
1901 success : $.proxy(this.load_notebook_success,this),
1916 error : $.proxy(this.load_notebook_error,this),
1902 error : $.proxy(this.load_notebook_error,this),
1917 };
1903 };
1918 $([IPython.events]).trigger('notebook_loading.Notebook');
1904 $([IPython.events]).trigger('notebook_loading.Notebook');
1919 var url = utils.url_join_encode(
1905 var url = utils.url_join_encode(
1920 this._baseProjectUrl,
1906 this.base_url,
1921 'api/notebooks',
1907 'api/notebooks',
1922 this.notebook_path,
1908 this.notebook_path,
1923 this.notebook_name
1909 this.notebook_name
1924 );
1910 );
1925 $.ajax(url, settings);
1911 $.ajax(url, settings);
1926 };
1912 };
1927
1913
1928 /**
1914 /**
1929 * Success callback for loading a notebook from the server.
1915 * Success callback for loading a notebook from the server.
1930 *
1916 *
1931 * Load notebook data from the JSON response.
1917 * Load notebook data from the JSON response.
1932 *
1918 *
1933 * @method load_notebook_success
1919 * @method load_notebook_success
1934 * @param {Object} data JSON representation of a notebook
1920 * @param {Object} data JSON representation of a notebook
1935 * @param {String} status Description of response status
1921 * @param {String} status Description of response status
1936 * @param {jqXHR} xhr jQuery Ajax object
1922 * @param {jqXHR} xhr jQuery Ajax object
1937 */
1923 */
1938 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1924 Notebook.prototype.load_notebook_success = function (data, status, xhr) {
1939 this.fromJSON(data);
1925 this.fromJSON(data);
1940 if (this.ncells() === 0) {
1926 if (this.ncells() === 0) {
1941 this.insert_cell_below('code');
1927 this.insert_cell_below('code');
1942 this.select(0);
1928 this.select(0);
1943 this.edit_mode();
1929 this.edit_mode();
1944 } else {
1930 } else {
1945 this.select(0);
1931 this.select(0);
1946 this.command_mode();
1932 this.command_mode();
1947 };
1933 }
1948 this.set_dirty(false);
1934 this.set_dirty(false);
1949 this.scroll_to_top();
1935 this.scroll_to_top();
1950 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1936 if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) {
1951 var msg = "This notebook has been converted from an older " +
1937 var msg = "This notebook has been converted from an older " +
1952 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1938 "notebook format (v"+data.orig_nbformat+") to the current notebook " +
1953 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1939 "format (v"+data.nbformat+"). The next time you save this notebook, the " +
1954 "newer notebook format will be used and older versions of IPython " +
1940 "newer notebook format will be used and older versions of IPython " +
1955 "may not be able to read it. To keep the older version, close the " +
1941 "may not be able to read it. To keep the older version, close the " +
1956 "notebook without saving it.";
1942 "notebook without saving it.";
1957 IPython.dialog.modal({
1943 IPython.dialog.modal({
1958 title : "Notebook converted",
1944 title : "Notebook converted",
1959 body : msg,
1945 body : msg,
1960 buttons : {
1946 buttons : {
1961 OK : {
1947 OK : {
1962 class : "btn-primary"
1948 class : "btn-primary"
1963 }
1949 }
1964 }
1950 }
1965 });
1951 });
1966 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1952 } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) {
1967 var that = this;
1953 var that = this;
1968 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1954 var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor;
1969 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1955 var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor;
1970 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1956 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
1971 this_vs + ". You can still work with this notebook, but some features " +
1957 this_vs + ". You can still work with this notebook, but some features " +
1972 "introduced in later notebook versions may not be available."
1958 "introduced in later notebook versions may not be available.";
1973
1959
1974 IPython.dialog.modal({
1960 IPython.dialog.modal({
1975 title : "Newer Notebook",
1961 title : "Newer Notebook",
1976 body : msg,
1962 body : msg,
1977 buttons : {
1963 buttons : {
1978 OK : {
1964 OK : {
1979 class : "btn-danger"
1965 class : "btn-danger"
1980 }
1966 }
1981 }
1967 }
1982 });
1968 });
1983
1969
1984 }
1970 }
1985
1971
1986 // Create the session after the notebook is completely loaded to prevent
1972 // Create the session after the notebook is completely loaded to prevent
1987 // code execution upon loading, which is a security risk.
1973 // code execution upon loading, which is a security risk.
1988 if (this.session == null) {
1974 if (this.session === null) {
1989 this.start_session();
1975 this.start_session();
1990 }
1976 }
1991 // load our checkpoint list
1977 // load our checkpoint list
1992 this.list_checkpoints();
1978 this.list_checkpoints();
1993
1979
1994 // load toolbar state
1980 // load toolbar state
1995 if (this.metadata.celltoolbar) {
1981 if (this.metadata.celltoolbar) {
1996 IPython.CellToolbar.global_show();
1982 IPython.CellToolbar.global_show();
1997 IPython.CellToolbar.activate_preset(this.metadata.celltoolbar);
1983 IPython.CellToolbar.activate_preset(this.metadata.celltoolbar);
1998 }
1984 }
1999
1985
2000 $([IPython.events]).trigger('notebook_loaded.Notebook');
1986 $([IPython.events]).trigger('notebook_loaded.Notebook');
2001 };
1987 };
2002
1988
2003 /**
1989 /**
2004 * Failure callback for loading a notebook from the server.
1990 * Failure callback for loading a notebook from the server.
2005 *
1991 *
2006 * @method load_notebook_error
1992 * @method load_notebook_error
2007 * @param {jqXHR} xhr jQuery Ajax object
1993 * @param {jqXHR} xhr jQuery Ajax object
2008 * @param {String} status Description of response status
1994 * @param {String} status Description of response status
2009 * @param {String} error HTTP error message
1995 * @param {String} error HTTP error message
2010 */
1996 */
2011 Notebook.prototype.load_notebook_error = function (xhr, status, error) {
1997 Notebook.prototype.load_notebook_error = function (xhr, status, error) {
2012 $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]);
1998 $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]);
1999 var msg;
2013 if (xhr.status === 400) {
2000 if (xhr.status === 400) {
2014 var msg = error;
2001 msg = error;
2015 } else if (xhr.status === 500) {
2002 } else if (xhr.status === 500) {
2016 var msg = "An unknown error occurred while loading this notebook. " +
2003 msg = "An unknown error occurred while loading this notebook. " +
2017 "This version can load notebook formats " +
2004 "This version can load notebook formats " +
2018 "v" + this.nbformat + " or earlier.";
2005 "v" + this.nbformat + " or earlier.";
2019 }
2006 }
2020 IPython.dialog.modal({
2007 IPython.dialog.modal({
2021 title: "Error loading notebook",
2008 title: "Error loading notebook",
2022 body : msg,
2009 body : msg,
2023 buttons : {
2010 buttons : {
2024 "OK": {}
2011 "OK": {}
2025 }
2012 }
2026 });
2013 });
2027 }
2014 };
2028
2015
2029 /********************* checkpoint-related *********************/
2016 /********************* checkpoint-related *********************/
2030
2017
2031 /**
2018 /**
2032 * Save the notebook then immediately create a checkpoint.
2019 * Save the notebook then immediately create a checkpoint.
2033 *
2020 *
2034 * @method save_checkpoint
2021 * @method save_checkpoint
2035 */
2022 */
2036 Notebook.prototype.save_checkpoint = function () {
2023 Notebook.prototype.save_checkpoint = function () {
2037 this._checkpoint_after_save = true;
2024 this._checkpoint_after_save = true;
2038 this.save_notebook();
2025 this.save_notebook();
2039 };
2026 };
2040
2027
2041 /**
2028 /**
2042 * Add a checkpoint for this notebook.
2029 * Add a checkpoint for this notebook.
2043 * for use as a callback from checkpoint creation.
2030 * for use as a callback from checkpoint creation.
2044 *
2031 *
2045 * @method add_checkpoint
2032 * @method add_checkpoint
2046 */
2033 */
2047 Notebook.prototype.add_checkpoint = function (checkpoint) {
2034 Notebook.prototype.add_checkpoint = function (checkpoint) {
2048 var found = false;
2035 var found = false;
2049 for (var i = 0; i < this.checkpoints.length; i++) {
2036 for (var i = 0; i < this.checkpoints.length; i++) {
2050 var existing = this.checkpoints[i];
2037 var existing = this.checkpoints[i];
2051 if (existing.id == checkpoint.id) {
2038 if (existing.id == checkpoint.id) {
2052 found = true;
2039 found = true;
2053 this.checkpoints[i] = checkpoint;
2040 this.checkpoints[i] = checkpoint;
2054 break;
2041 break;
2055 }
2042 }
2056 }
2043 }
2057 if (!found) {
2044 if (!found) {
2058 this.checkpoints.push(checkpoint);
2045 this.checkpoints.push(checkpoint);
2059 }
2046 }
2060 this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1];
2047 this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1];
2061 };
2048 };
2062
2049
2063 /**
2050 /**
2064 * List checkpoints for this notebook.
2051 * List checkpoints for this notebook.
2065 *
2052 *
2066 * @method list_checkpoints
2053 * @method list_checkpoints
2067 */
2054 */
2068 Notebook.prototype.list_checkpoints = function () {
2055 Notebook.prototype.list_checkpoints = function () {
2069 var url = utils.url_join_encode(
2056 var url = utils.url_join_encode(
2070 this._baseProjectUrl,
2057 this.base_url,
2071 'api/notebooks',
2058 'api/notebooks',
2072 this.notebook_path,
2059 this.notebook_path,
2073 this.notebook_name,
2060 this.notebook_name,
2074 'checkpoints'
2061 'checkpoints'
2075 );
2062 );
2076 $.get(url).done(
2063 $.get(url).done(
2077 $.proxy(this.list_checkpoints_success, this)
2064 $.proxy(this.list_checkpoints_success, this)
2078 ).fail(
2065 ).fail(
2079 $.proxy(this.list_checkpoints_error, this)
2066 $.proxy(this.list_checkpoints_error, this)
2080 );
2067 );
2081 };
2068 };
2082
2069
2083 /**
2070 /**
2084 * Success callback for listing checkpoints.
2071 * Success callback for listing checkpoints.
2085 *
2072 *
2086 * @method list_checkpoint_success
2073 * @method list_checkpoint_success
2087 * @param {Object} data JSON representation of a checkpoint
2074 * @param {Object} data JSON representation of a checkpoint
2088 * @param {String} status Description of response status
2075 * @param {String} status Description of response status
2089 * @param {jqXHR} xhr jQuery Ajax object
2076 * @param {jqXHR} xhr jQuery Ajax object
2090 */
2077 */
2091 Notebook.prototype.list_checkpoints_success = function (data, status, xhr) {
2078 Notebook.prototype.list_checkpoints_success = function (data, status, xhr) {
2092 var data = $.parseJSON(data);
2079 data = $.parseJSON(data);
2093 this.checkpoints = data;
2080 this.checkpoints = data;
2094 if (data.length) {
2081 if (data.length) {
2095 this.last_checkpoint = data[data.length - 1];
2082 this.last_checkpoint = data[data.length - 1];
2096 } else {
2083 } else {
2097 this.last_checkpoint = null;
2084 this.last_checkpoint = null;
2098 }
2085 }
2099 $([IPython.events]).trigger('checkpoints_listed.Notebook', [data]);
2086 $([IPython.events]).trigger('checkpoints_listed.Notebook', [data]);
2100 };
2087 };
2101
2088
2102 /**
2089 /**
2103 * Failure callback for listing a checkpoint.
2090 * Failure callback for listing a checkpoint.
2104 *
2091 *
2105 * @method list_checkpoint_error
2092 * @method list_checkpoint_error
2106 * @param {jqXHR} xhr jQuery Ajax object
2093 * @param {jqXHR} xhr jQuery Ajax object
2107 * @param {String} status Description of response status
2094 * @param {String} status Description of response status
2108 * @param {String} error_msg HTTP error message
2095 * @param {String} error_msg HTTP error message
2109 */
2096 */
2110 Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) {
2097 Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) {
2111 $([IPython.events]).trigger('list_checkpoints_failed.Notebook');
2098 $([IPython.events]).trigger('list_checkpoints_failed.Notebook');
2112 };
2099 };
2113
2100
2114 /**
2101 /**
2115 * Create a checkpoint of this notebook on the server from the most recent save.
2102 * Create a checkpoint of this notebook on the server from the most recent save.
2116 *
2103 *
2117 * @method create_checkpoint
2104 * @method create_checkpoint
2118 */
2105 */
2119 Notebook.prototype.create_checkpoint = function () {
2106 Notebook.prototype.create_checkpoint = function () {
2120 var url = utils.url_join_encode(
2107 var url = utils.url_join_encode(
2121 this._baseProjectUrl,
2108 this.base_url,
2122 'api/notebooks',
2109 'api/notebooks',
2123 this.notebookPath(),
2110 this.notebook_path,
2124 this.notebook_name,
2111 this.notebook_name,
2125 'checkpoints'
2112 'checkpoints'
2126 );
2113 );
2127 $.post(url).done(
2114 $.post(url).done(
2128 $.proxy(this.create_checkpoint_success, this)
2115 $.proxy(this.create_checkpoint_success, this)
2129 ).fail(
2116 ).fail(
2130 $.proxy(this.create_checkpoint_error, this)
2117 $.proxy(this.create_checkpoint_error, this)
2131 );
2118 );
2132 };
2119 };
2133
2120
2134 /**
2121 /**
2135 * Success callback for creating a checkpoint.
2122 * Success callback for creating a checkpoint.
2136 *
2123 *
2137 * @method create_checkpoint_success
2124 * @method create_checkpoint_success
2138 * @param {Object} data JSON representation of a checkpoint
2125 * @param {Object} data JSON representation of a checkpoint
2139 * @param {String} status Description of response status
2126 * @param {String} status Description of response status
2140 * @param {jqXHR} xhr jQuery Ajax object
2127 * @param {jqXHR} xhr jQuery Ajax object
2141 */
2128 */
2142 Notebook.prototype.create_checkpoint_success = function (data, status, xhr) {
2129 Notebook.prototype.create_checkpoint_success = function (data, status, xhr) {
2143 var data = $.parseJSON(data);
2130 data = $.parseJSON(data);
2144 this.add_checkpoint(data);
2131 this.add_checkpoint(data);
2145 $([IPython.events]).trigger('checkpoint_created.Notebook', data);
2132 $([IPython.events]).trigger('checkpoint_created.Notebook', data);
2146 };
2133 };
2147
2134
2148 /**
2135 /**
2149 * Failure callback for creating a checkpoint.
2136 * Failure callback for creating a checkpoint.
2150 *
2137 *
2151 * @method create_checkpoint_error
2138 * @method create_checkpoint_error
2152 * @param {jqXHR} xhr jQuery Ajax object
2139 * @param {jqXHR} xhr jQuery Ajax object
2153 * @param {String} status Description of response status
2140 * @param {String} status Description of response status
2154 * @param {String} error_msg HTTP error message
2141 * @param {String} error_msg HTTP error message
2155 */
2142 */
2156 Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) {
2143 Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) {
2157 $([IPython.events]).trigger('checkpoint_failed.Notebook');
2144 $([IPython.events]).trigger('checkpoint_failed.Notebook');
2158 };
2145 };
2159
2146
2160 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2147 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2161 var that = this;
2148 var that = this;
2162 var checkpoint = checkpoint || this.last_checkpoint;
2149 checkpoint = checkpoint || this.last_checkpoint;
2163 if ( ! checkpoint ) {
2150 if ( ! checkpoint ) {
2164 console.log("restore dialog, but no checkpoint to restore to!");
2151 console.log("restore dialog, but no checkpoint to restore to!");
2165 return;
2152 return;
2166 }
2153 }
2167 var body = $('<div/>').append(
2154 var body = $('<div/>').append(
2168 $('<p/>').addClass("p-space").text(
2155 $('<p/>').addClass("p-space").text(
2169 "Are you sure you want to revert the notebook to " +
2156 "Are you sure you want to revert the notebook to " +
2170 "the latest checkpoint?"
2157 "the latest checkpoint?"
2171 ).append(
2158 ).append(
2172 $("<strong/>").text(
2159 $("<strong/>").text(
2173 " This cannot be undone."
2160 " This cannot be undone."
2174 )
2161 )
2175 )
2162 )
2176 ).append(
2163 ).append(
2177 $('<p/>').addClass("p-space").text("The checkpoint was last updated at:")
2164 $('<p/>').addClass("p-space").text("The checkpoint was last updated at:")
2178 ).append(
2165 ).append(
2179 $('<p/>').addClass("p-space").text(
2166 $('<p/>').addClass("p-space").text(
2180 Date(checkpoint.last_modified)
2167 Date(checkpoint.last_modified)
2181 ).css("text-align", "center")
2168 ).css("text-align", "center")
2182 );
2169 );
2183
2170
2184 IPython.dialog.modal({
2171 IPython.dialog.modal({
2185 title : "Revert notebook to checkpoint",
2172 title : "Revert notebook to checkpoint",
2186 body : body,
2173 body : body,
2187 buttons : {
2174 buttons : {
2188 Revert : {
2175 Revert : {
2189 class : "btn-danger",
2176 class : "btn-danger",
2190 click : function () {
2177 click : function () {
2191 that.restore_checkpoint(checkpoint.id);
2178 that.restore_checkpoint(checkpoint.id);
2192 }
2179 }
2193 },
2180 },
2194 Cancel : {}
2181 Cancel : {}
2195 }
2182 }
2196 });
2183 });
2197 }
2184 };
2198
2185
2199 /**
2186 /**
2200 * Restore the notebook to a checkpoint state.
2187 * Restore the notebook to a checkpoint state.
2201 *
2188 *
2202 * @method restore_checkpoint
2189 * @method restore_checkpoint
2203 * @param {String} checkpoint ID
2190 * @param {String} checkpoint ID
2204 */
2191 */
2205 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2192 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2206 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2193 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2207 var url = utils.url_join_encode(
2194 var url = utils.url_join_encode(
2208 this._baseProjectUrl,
2195 this.base_url,
2209 'api/notebooks',
2196 'api/notebooks',
2210 this.notebookPath(),
2197 this.notebook_path,
2211 this.notebook_name,
2198 this.notebook_name,
2212 'checkpoints',
2199 'checkpoints',
2213 checkpoint
2200 checkpoint
2214 );
2201 );
2215 $.post(url).done(
2202 $.post(url).done(
2216 $.proxy(this.restore_checkpoint_success, this)
2203 $.proxy(this.restore_checkpoint_success, this)
2217 ).fail(
2204 ).fail(
2218 $.proxy(this.restore_checkpoint_error, this)
2205 $.proxy(this.restore_checkpoint_error, this)
2219 );
2206 );
2220 };
2207 };
2221
2208
2222 /**
2209 /**
2223 * Success callback for restoring a notebook to a checkpoint.
2210 * Success callback for restoring a notebook to a checkpoint.
2224 *
2211 *
2225 * @method restore_checkpoint_success
2212 * @method restore_checkpoint_success
2226 * @param {Object} data (ignored, should be empty)
2213 * @param {Object} data (ignored, should be empty)
2227 * @param {String} status Description of response status
2214 * @param {String} status Description of response status
2228 * @param {jqXHR} xhr jQuery Ajax object
2215 * @param {jqXHR} xhr jQuery Ajax object
2229 */
2216 */
2230 Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) {
2217 Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) {
2231 $([IPython.events]).trigger('checkpoint_restored.Notebook');
2218 $([IPython.events]).trigger('checkpoint_restored.Notebook');
2232 this.load_notebook(this.notebook_name, this.notebook_path);
2219 this.load_notebook(this.notebook_name, this.notebook_path);
2233 };
2220 };
2234
2221
2235 /**
2222 /**
2236 * Failure callback for restoring a notebook to a checkpoint.
2223 * Failure callback for restoring a notebook to a checkpoint.
2237 *
2224 *
2238 * @method restore_checkpoint_error
2225 * @method restore_checkpoint_error
2239 * @param {jqXHR} xhr jQuery Ajax object
2226 * @param {jqXHR} xhr jQuery Ajax object
2240 * @param {String} status Description of response status
2227 * @param {String} status Description of response status
2241 * @param {String} error_msg HTTP error message
2228 * @param {String} error_msg HTTP error message
2242 */
2229 */
2243 Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) {
2230 Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) {
2244 $([IPython.events]).trigger('checkpoint_restore_failed.Notebook');
2231 $([IPython.events]).trigger('checkpoint_restore_failed.Notebook');
2245 };
2232 };
2246
2233
2247 /**
2234 /**
2248 * Delete a notebook checkpoint.
2235 * Delete a notebook checkpoint.
2249 *
2236 *
2250 * @method delete_checkpoint
2237 * @method delete_checkpoint
2251 * @param {String} checkpoint ID
2238 * @param {String} checkpoint ID
2252 */
2239 */
2253 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2240 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2254 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2241 $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint);
2255 var url = utils.url_join_encode(
2242 var url = utils.url_join_encode(
2256 this._baseProjectUrl,
2243 this.base_url,
2257 'api/notebooks',
2244 'api/notebooks',
2258 this.notebookPath(),
2245 this.notebook_path,
2259 this.notebook_name,
2246 this.notebook_name,
2260 'checkpoints',
2247 'checkpoints',
2261 checkpoint
2248 checkpoint
2262 );
2249 );
2263 $.ajax(url, {
2250 $.ajax(url, {
2264 type: 'DELETE',
2251 type: 'DELETE',
2265 success: $.proxy(this.delete_checkpoint_success, this),
2252 success: $.proxy(this.delete_checkpoint_success, this),
2266 error: $.proxy(this.delete_notebook_error,this)
2253 error: $.proxy(this.delete_notebook_error,this)
2267 });
2254 });
2268 };
2255 };
2269
2256
2270 /**
2257 /**
2271 * Success callback for deleting a notebook checkpoint
2258 * Success callback for deleting a notebook checkpoint
2272 *
2259 *
2273 * @method delete_checkpoint_success
2260 * @method delete_checkpoint_success
2274 * @param {Object} data (ignored, should be empty)
2261 * @param {Object} data (ignored, should be empty)
2275 * @param {String} status Description of response status
2262 * @param {String} status Description of response status
2276 * @param {jqXHR} xhr jQuery Ajax object
2263 * @param {jqXHR} xhr jQuery Ajax object
2277 */
2264 */
2278 Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) {
2265 Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) {
2279 $([IPython.events]).trigger('checkpoint_deleted.Notebook', data);
2266 $([IPython.events]).trigger('checkpoint_deleted.Notebook', data);
2280 this.load_notebook(this.notebook_name, this.notebook_path);
2267 this.load_notebook(this.notebook_name, this.notebook_path);
2281 };
2268 };
2282
2269
2283 /**
2270 /**
2284 * Failure callback for deleting a notebook checkpoint.
2271 * Failure callback for deleting a notebook checkpoint.
2285 *
2272 *
2286 * @method delete_checkpoint_error
2273 * @method delete_checkpoint_error
2287 * @param {jqXHR} xhr jQuery Ajax object
2274 * @param {jqXHR} xhr jQuery Ajax object
2288 * @param {String} status Description of response status
2275 * @param {String} status Description of response status
2289 * @param {String} error_msg HTTP error message
2276 * @param {String} error_msg HTTP error message
2290 */
2277 */
2291 Notebook.prototype.delete_checkpoint_error = function (xhr, status, error_msg) {
2278 Notebook.prototype.delete_checkpoint_error = function (xhr, status, error_msg) {
2292 $([IPython.events]).trigger('checkpoint_delete_failed.Notebook');
2279 $([IPython.events]).trigger('checkpoint_delete_failed.Notebook');
2293 };
2280 };
2294
2281
2295
2282
2296 IPython.Notebook = Notebook;
2283 IPython.Notebook = Notebook;
2297
2284
2298
2285
2299 return IPython;
2286 return IPython;
2300
2287
2301 }(IPython));
2288 }(IPython));
@@ -1,210 +1,222 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2012 The IPython Development Team
2 // Copyright (C) 2012 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Notification widget
9 // Notification widget
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14 var utils = IPython.utils;
14 var utils = IPython.utils;
15
15
16
16
17 var NotificationArea = function (selector) {
17 var NotificationArea = function (selector) {
18 this.selector = selector;
18 this.selector = selector;
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
21 }
21 }
22 this.widget_dict = {};
22 this.widget_dict = {};
23 };
23 };
24
24
25 NotificationArea.prototype.temp_message = function (msg, timeout, css_class) {
25 NotificationArea.prototype.temp_message = function (msg, timeout, css_class) {
26 var uuid = utils.uuid();
26 var uuid = utils.uuid();
27 if( css_class == 'danger') {css_class = 'ui-state-error';}
27 if( css_class == 'danger') {css_class = 'ui-state-error';}
28 if( css_class == 'warning') {css_class = 'ui-state-highlight';}
28 if( css_class == 'warning') {css_class = 'ui-state-highlight';}
29 var tdiv = $('<div>')
29 var tdiv = $('<div>')
30 .attr('id',uuid)
30 .attr('id',uuid)
31 .addClass('notification_widget ui-widget ui-widget-content ui-corner-all')
31 .addClass('notification_widget ui-widget ui-widget-content ui-corner-all')
32 .addClass('border-box-sizing')
32 .addClass('border-box-sizing')
33 .addClass(css_class)
33 .addClass(css_class)
34 .hide()
34 .hide()
35 .text(msg);
35 .text(msg);
36
36
37 $(this.selector).append(tdiv);
37 $(this.selector).append(tdiv);
38 var tmout = Math.max(1500,(timeout||1500));
38 var tmout = Math.max(1500,(timeout||1500));
39 tdiv.fadeIn(100);
39 tdiv.fadeIn(100);
40
40
41 setTimeout(function () {
41 setTimeout(function () {
42 tdiv.fadeOut(100, function () {tdiv.remove();});
42 tdiv.fadeOut(100, function () {tdiv.remove();});
43 }, tmout);
43 }, tmout);
44 };
44 };
45
45
46 NotificationArea.prototype.widget = function(name) {
46 NotificationArea.prototype.widget = function(name) {
47 if(this.widget_dict[name] == undefined) {
47 if(this.widget_dict[name] == undefined) {
48 return this.new_notification_widget(name);
48 return this.new_notification_widget(name);
49 }
49 }
50 return this.get_widget(name);
50 return this.get_widget(name);
51 };
51 };
52
52
53 NotificationArea.prototype.get_widget = function(name) {
53 NotificationArea.prototype.get_widget = function(name) {
54 if(this.widget_dict[name] == undefined) {
54 if(this.widget_dict[name] == undefined) {
55 throw('no widgets with this name');
55 throw('no widgets with this name');
56 }
56 }
57 return this.widget_dict[name];
57 return this.widget_dict[name];
58 };
58 };
59
59
60 NotificationArea.prototype.new_notification_widget = function(name) {
60 NotificationArea.prototype.new_notification_widget = function(name) {
61 if(this.widget_dict[name] != undefined) {
61 if(this.widget_dict[name] != undefined) {
62 throw('widget with that name already exists ! ');
62 throw('widget with that name already exists ! ');
63 }
63 }
64 var div = $('<div/>').attr('id','notification_'+name);
64 var div = $('<div/>').attr('id','notification_'+name);
65 $(this.selector).append(div);
65 $(this.selector).append(div);
66 this.widget_dict[name] = new IPython.NotificationWidget('#notification_'+name);
66 this.widget_dict[name] = new IPython.NotificationWidget('#notification_'+name);
67 return this.widget_dict[name];
67 return this.widget_dict[name];
68 };
68 };
69
69
70 NotificationArea.prototype.init_notification_widgets = function() {
70 NotificationArea.prototype.init_notification_widgets = function() {
71 var knw = this.new_notification_widget('kernel');
71 var knw = this.new_notification_widget('kernel');
72 var $kernel_indic = $("#kernel_indicator");
72 var $kernel_ind_icon = $("#kernel_indicator_icon");
73 var $modal_ind_icon = $("#modal_indicator_icon");
74
75 // Command/Edit mode
76 $([IPython.events]).on('edit_mode.Notebook',function () {
77 IPython.save_widget.update_document_title();
78 $modal_ind_icon.attr('class','icon-pencil').attr('title','Edit Mode');
79 });
80
81 $([IPython.events]).on('command_mode.Notebook',function () {
82 IPython.save_widget.update_document_title();
83 $modal_ind_icon.attr('class','').attr('title','Command Mode');
84 });
73
85
74 // Kernel events
86 // Kernel events
75 $([IPython.events]).on('status_idle.Kernel',function () {
87 $([IPython.events]).on('status_idle.Kernel',function () {
76 IPython.save_widget.update_document_title();
88 IPython.save_widget.update_document_title();
77 $kernel_indic.attr('class','icon-circle-blank').attr('title','Kernel Idle');
89 $kernel_ind_icon.attr('class','icon-circle-blank').attr('title','Kernel Idle');
78 });
90 });
79
91
80 $([IPython.events]).on('status_busy.Kernel',function () {
92 $([IPython.events]).on('status_busy.Kernel',function () {
81 window.document.title='(Busy) '+window.document.title;
93 window.document.title='(Busy) '+window.document.title;
82 $kernel_indic.attr('class','icon-circle').attr('title','Kernel Busy');
94 $kernel_ind_icon.attr('class','icon-circle').attr('title','Kernel Busy');
83 });
95 });
84
96
85 $([IPython.events]).on('status_restarting.Kernel',function () {
97 $([IPython.events]).on('status_restarting.Kernel',function () {
86 IPython.save_widget.update_document_title();
98 IPython.save_widget.update_document_title();
87 knw.set_message("Restarting kernel", 2000);
99 knw.set_message("Restarting kernel", 2000);
88 });
100 });
89
101
90 $([IPython.events]).on('status_interrupting.Kernel',function () {
102 $([IPython.events]).on('status_interrupting.Kernel',function () {
91 knw.set_message("Interrupting kernel", 2000);
103 knw.set_message("Interrupting kernel", 2000);
92 });
104 });
93
105
94 $([IPython.events]).on('status_dead.Kernel',function () {
106 $([IPython.events]).on('status_dead.Kernel',function () {
95 var msg = 'The kernel has died, and the automatic restart has failed.' +
107 var msg = 'The kernel has died, and the automatic restart has failed.' +
96 ' It is possible the kernel cannot be restarted.' +
108 ' It is possible the kernel cannot be restarted.' +
97 ' If you are not able to restart the kernel, you will still be able to save' +
109 ' If you are not able to restart the kernel, you will still be able to save' +
98 ' the notebook, but running code will no longer work until the notebook' +
110 ' the notebook, but running code will no longer work until the notebook' +
99 ' is reopened.';
111 ' is reopened.';
100
112
101 IPython.dialog.modal({
113 IPython.dialog.modal({
102 title: "Dead kernel",
114 title: "Dead kernel",
103 body : msg,
115 body : msg,
104 buttons : {
116 buttons : {
105 "Manual Restart": {
117 "Manual Restart": {
106 class: "btn-danger",
118 class: "btn-danger",
107 click: function () {
119 click: function () {
108 $([IPython.events]).trigger('status_restarting.Kernel');
120 $([IPython.events]).trigger('status_restarting.Kernel');
109 IPython.notebook.start_kernel();
121 IPython.notebook.start_kernel();
110 }
122 }
111 },
123 },
112 "Don't restart": {}
124 "Don't restart": {}
113 }
125 }
114 });
126 });
115 });
127 });
116
128
117 $([IPython.events]).on('websocket_closed.Kernel', function (event, data) {
129 $([IPython.events]).on('websocket_closed.Kernel', function (event, data) {
118 var kernel = data.kernel;
130 var kernel = data.kernel;
119 var ws_url = data.ws_url;
131 var ws_url = data.ws_url;
120 var early = data.early;
132 var early = data.early;
121 var msg;
133 var msg;
122 if (!early) {
134 if (!early) {
123 knw.set_message('Reconnecting WebSockets', 1000);
135 knw.set_message('Reconnecting WebSockets', 1000);
124 setTimeout(function () {
136 setTimeout(function () {
125 kernel.start_channels();
137 kernel.start_channels();
126 }, 5000);
138 }, 5000);
127 return;
139 return;
128 }
140 }
129 console.log('WebSocket connection failed: ', ws_url)
141 console.log('WebSocket connection failed: ', ws_url)
130 msg = "A WebSocket connection could not be established." +
142 msg = "A WebSocket connection could not be established." +
131 " You will NOT be able to run code. Check your" +
143 " You will NOT be able to run code. Check your" +
132 " network connection or notebook server configuration.";
144 " network connection or notebook server configuration.";
133 IPython.dialog.modal({
145 IPython.dialog.modal({
134 title: "WebSocket connection failed",
146 title: "WebSocket connection failed",
135 body: msg,
147 body: msg,
136 buttons : {
148 buttons : {
137 "OK": {},
149 "OK": {},
138 "Reconnect": {
150 "Reconnect": {
139 click: function () {
151 click: function () {
140 knw.set_message('Reconnecting WebSockets', 1000);
152 knw.set_message('Reconnecting WebSockets', 1000);
141 setTimeout(function () {
153 setTimeout(function () {
142 kernel.start_channels();
154 kernel.start_channels();
143 }, 5000);
155 }, 5000);
144 }
156 }
145 }
157 }
146 }
158 }
147 });
159 });
148 });
160 });
149
161
150
162
151 var nnw = this.new_notification_widget('notebook');
163 var nnw = this.new_notification_widget('notebook');
152
164
153 // Notebook events
165 // Notebook events
154 $([IPython.events]).on('notebook_loading.Notebook', function () {
166 $([IPython.events]).on('notebook_loading.Notebook', function () {
155 nnw.set_message("Loading notebook",500);
167 nnw.set_message("Loading notebook",500);
156 });
168 });
157 $([IPython.events]).on('notebook_loaded.Notebook', function () {
169 $([IPython.events]).on('notebook_loaded.Notebook', function () {
158 nnw.set_message("Notebook loaded",500);
170 nnw.set_message("Notebook loaded",500);
159 });
171 });
160 $([IPython.events]).on('notebook_saving.Notebook', function () {
172 $([IPython.events]).on('notebook_saving.Notebook', function () {
161 nnw.set_message("Saving notebook",500);
173 nnw.set_message("Saving notebook",500);
162 });
174 });
163 $([IPython.events]).on('notebook_saved.Notebook', function () {
175 $([IPython.events]).on('notebook_saved.Notebook', function () {
164 nnw.set_message("Notebook saved",2000);
176 nnw.set_message("Notebook saved",2000);
165 });
177 });
166 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
178 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
167 nnw.set_message("Notebook save failed");
179 nnw.set_message("Notebook save failed");
168 });
180 });
169
181
170 // Checkpoint events
182 // Checkpoint events
171 $([IPython.events]).on('checkpoint_created.Notebook', function (evt, data) {
183 $([IPython.events]).on('checkpoint_created.Notebook', function (evt, data) {
172 var msg = "Checkpoint created";
184 var msg = "Checkpoint created";
173 if (data.last_modified) {
185 if (data.last_modified) {
174 var d = new Date(data.last_modified);
186 var d = new Date(data.last_modified);
175 msg = msg + ": " + d.format("HH:MM:ss");
187 msg = msg + ": " + d.format("HH:MM:ss");
176 }
188 }
177 nnw.set_message(msg, 2000);
189 nnw.set_message(msg, 2000);
178 });
190 });
179 $([IPython.events]).on('checkpoint_failed.Notebook', function () {
191 $([IPython.events]).on('checkpoint_failed.Notebook', function () {
180 nnw.set_message("Checkpoint failed");
192 nnw.set_message("Checkpoint failed");
181 });
193 });
182 $([IPython.events]).on('checkpoint_deleted.Notebook', function () {
194 $([IPython.events]).on('checkpoint_deleted.Notebook', function () {
183 nnw.set_message("Checkpoint deleted", 500);
195 nnw.set_message("Checkpoint deleted", 500);
184 });
196 });
185 $([IPython.events]).on('checkpoint_delete_failed.Notebook', function () {
197 $([IPython.events]).on('checkpoint_delete_failed.Notebook', function () {
186 nnw.set_message("Checkpoint delete failed");
198 nnw.set_message("Checkpoint delete failed");
187 });
199 });
188 $([IPython.events]).on('checkpoint_restoring.Notebook', function () {
200 $([IPython.events]).on('checkpoint_restoring.Notebook', function () {
189 nnw.set_message("Restoring to checkpoint...", 500);
201 nnw.set_message("Restoring to checkpoint...", 500);
190 });
202 });
191 $([IPython.events]).on('checkpoint_restore_failed.Notebook', function () {
203 $([IPython.events]).on('checkpoint_restore_failed.Notebook', function () {
192 nnw.set_message("Checkpoint restore failed");
204 nnw.set_message("Checkpoint restore failed");
193 });
205 });
194
206
195 // Autosave events
207 // Autosave events
196 $([IPython.events]).on('autosave_disabled.Notebook', function () {
208 $([IPython.events]).on('autosave_disabled.Notebook', function () {
197 nnw.set_message("Autosave disabled", 2000);
209 nnw.set_message("Autosave disabled", 2000);
198 });
210 });
199 $([IPython.events]).on('autosave_enabled.Notebook', function (evt, interval) {
211 $([IPython.events]).on('autosave_enabled.Notebook', function (evt, interval) {
200 nnw.set_message("Saving every " + interval / 1000 + "s", 1000);
212 nnw.set_message("Saving every " + interval / 1000 + "s", 1000);
201 });
213 });
202
214
203 };
215 };
204
216
205 IPython.NotificationArea = NotificationArea;
217 IPython.NotificationArea = NotificationArea;
206
218
207 return IPython;
219 return IPython;
208
220
209 }(IPython));
221 }(IPython));
210
222
@@ -1,851 +1,867 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008 The IPython Development Team
2 // Copyright (C) 2008 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // OutputArea
9 // OutputArea
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule OutputArea
15 * @submodule OutputArea
16 */
16 */
17 var IPython = (function (IPython) {
17 var IPython = (function (IPython) {
18 "use strict";
18 "use strict";
19
19
20 var utils = IPython.utils;
20 var utils = IPython.utils;
21
21
22 /**
22 /**
23 * @class OutputArea
23 * @class OutputArea
24 *
24 *
25 * @constructor
25 * @constructor
26 */
26 */
27
27
28 var OutputArea = function (selector, prompt_area) {
28 var OutputArea = function (selector, prompt_area) {
29 this.selector = selector;
29 this.selector = selector;
30 this.wrapper = $(selector);
30 this.wrapper = $(selector);
31 this.outputs = [];
31 this.outputs = [];
32 this.collapsed = false;
32 this.collapsed = false;
33 this.scrolled = false;
33 this.scrolled = false;
34 this.trusted = true;
34 this.trusted = true;
35 this.clear_queued = null;
35 this.clear_queued = null;
36 if (prompt_area === undefined) {
36 if (prompt_area === undefined) {
37 this.prompt_area = true;
37 this.prompt_area = true;
38 } else {
38 } else {
39 this.prompt_area = prompt_area;
39 this.prompt_area = prompt_area;
40 }
40 }
41 this.create_elements();
41 this.create_elements();
42 this.style();
42 this.style();
43 this.bind_events();
43 this.bind_events();
44 };
44 };
45
45
46
46
47 /**
47 /**
48 * Class prototypes
48 * Class prototypes
49 **/
49 **/
50
50
51 OutputArea.prototype.create_elements = function () {
51 OutputArea.prototype.create_elements = function () {
52 this.element = $("<div/>");
52 this.element = $("<div/>");
53 this.collapse_button = $("<div/>");
53 this.collapse_button = $("<div/>");
54 this.prompt_overlay = $("<div/>");
54 this.prompt_overlay = $("<div/>");
55 this.wrapper.append(this.prompt_overlay);
55 this.wrapper.append(this.prompt_overlay);
56 this.wrapper.append(this.element);
56 this.wrapper.append(this.element);
57 this.wrapper.append(this.collapse_button);
57 this.wrapper.append(this.collapse_button);
58 };
58 };
59
59
60
60
61 OutputArea.prototype.style = function () {
61 OutputArea.prototype.style = function () {
62 this.collapse_button.hide();
62 this.collapse_button.hide();
63 this.prompt_overlay.hide();
63 this.prompt_overlay.hide();
64
64
65 this.wrapper.addClass('output_wrapper');
65 this.wrapper.addClass('output_wrapper');
66 this.element.addClass('output');
66 this.element.addClass('output');
67
67
68 this.collapse_button.addClass("btn output_collapsed");
68 this.collapse_button.addClass("btn output_collapsed");
69 this.collapse_button.attr('title', 'click to expand output');
69 this.collapse_button.attr('title', 'click to expand output');
70 this.collapse_button.text('. . .');
70 this.collapse_button.text('. . .');
71
71
72 this.prompt_overlay.addClass('out_prompt_overlay prompt');
72 this.prompt_overlay.addClass('out_prompt_overlay prompt');
73 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
73 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
74
74
75 this.collapse();
75 this.collapse();
76 };
76 };
77
77
78 /**
78 /**
79 * Should the OutputArea scroll?
79 * Should the OutputArea scroll?
80 * Returns whether the height (in lines) exceeds a threshold.
80 * Returns whether the height (in lines) exceeds a threshold.
81 *
81 *
82 * @private
82 * @private
83 * @method _should_scroll
83 * @method _should_scroll
84 * @param [lines=100]{Integer}
84 * @param [lines=100]{Integer}
85 * @return {Bool}
85 * @return {Bool}
86 *
86 *
87 */
87 */
88 OutputArea.prototype._should_scroll = function (lines) {
88 OutputArea.prototype._should_scroll = function (lines) {
89 if (lines <=0 ){ return }
89 if (lines <=0 ){ return }
90 if (!lines) {
90 if (!lines) {
91 lines = 100;
91 lines = 100;
92 }
92 }
93 // line-height from http://stackoverflow.com/questions/1185151
93 // line-height from http://stackoverflow.com/questions/1185151
94 var fontSize = this.element.css('font-size');
94 var fontSize = this.element.css('font-size');
95 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
95 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
96
96
97 return (this.element.height() > lines * lineHeight);
97 return (this.element.height() > lines * lineHeight);
98 };
98 };
99
99
100
100
101 OutputArea.prototype.bind_events = function () {
101 OutputArea.prototype.bind_events = function () {
102 var that = this;
102 var that = this;
103 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
103 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
104 this.prompt_overlay.click(function () { that.toggle_scroll(); });
104 this.prompt_overlay.click(function () { that.toggle_scroll(); });
105
105
106 this.element.resize(function () {
106 this.element.resize(function () {
107 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
107 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
108 if ( IPython.utils.browser[0] === "Firefox" ) {
108 if ( IPython.utils.browser[0] === "Firefox" ) {
109 return;
109 return;
110 }
110 }
111 // maybe scroll output,
111 // maybe scroll output,
112 // if it's grown large enough and hasn't already been scrolled.
112 // if it's grown large enough and hasn't already been scrolled.
113 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
113 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
114 that.scroll_area();
114 that.scroll_area();
115 }
115 }
116 });
116 });
117 this.collapse_button.click(function () {
117 this.collapse_button.click(function () {
118 that.expand();
118 that.expand();
119 });
119 });
120 };
120 };
121
121
122
122
123 OutputArea.prototype.collapse = function () {
123 OutputArea.prototype.collapse = function () {
124 if (!this.collapsed) {
124 if (!this.collapsed) {
125 this.element.hide();
125 this.element.hide();
126 this.prompt_overlay.hide();
126 this.prompt_overlay.hide();
127 if (this.element.html()){
127 if (this.element.html()){
128 this.collapse_button.show();
128 this.collapse_button.show();
129 }
129 }
130 this.collapsed = true;
130 this.collapsed = true;
131 }
131 }
132 };
132 };
133
133
134
134
135 OutputArea.prototype.expand = function () {
135 OutputArea.prototype.expand = function () {
136 if (this.collapsed) {
136 if (this.collapsed) {
137 this.collapse_button.hide();
137 this.collapse_button.hide();
138 this.element.show();
138 this.element.show();
139 this.prompt_overlay.show();
139 this.prompt_overlay.show();
140 this.collapsed = false;
140 this.collapsed = false;
141 }
141 }
142 };
142 };
143
143
144
144
145 OutputArea.prototype.toggle_output = function () {
145 OutputArea.prototype.toggle_output = function () {
146 if (this.collapsed) {
146 if (this.collapsed) {
147 this.expand();
147 this.expand();
148 } else {
148 } else {
149 this.collapse();
149 this.collapse();
150 }
150 }
151 };
151 };
152
152
153
153
154 OutputArea.prototype.scroll_area = function () {
154 OutputArea.prototype.scroll_area = function () {
155 this.element.addClass('output_scroll');
155 this.element.addClass('output_scroll');
156 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
156 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
157 this.scrolled = true;
157 this.scrolled = true;
158 };
158 };
159
159
160
160
161 OutputArea.prototype.unscroll_area = function () {
161 OutputArea.prototype.unscroll_area = function () {
162 this.element.removeClass('output_scroll');
162 this.element.removeClass('output_scroll');
163 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
163 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
164 this.scrolled = false;
164 this.scrolled = false;
165 };
165 };
166
166
167 /**
167 /**
168 *
168 *
169 * Scroll OutputArea if height supperior than a threshold (in lines).
169 * Scroll OutputArea if height supperior than a threshold (in lines).
170 *
170 *
171 * Threshold is a maximum number of lines. If unspecified, defaults to
171 * Threshold is a maximum number of lines. If unspecified, defaults to
172 * OutputArea.minimum_scroll_threshold.
172 * OutputArea.minimum_scroll_threshold.
173 *
173 *
174 * Negative threshold will prevent the OutputArea from ever scrolling.
174 * Negative threshold will prevent the OutputArea from ever scrolling.
175 *
175 *
176 * @method scroll_if_long
176 * @method scroll_if_long
177 *
177 *
178 * @param [lines=20]{Number} Default to 20 if not set,
178 * @param [lines=20]{Number} Default to 20 if not set,
179 * behavior undefined for value of `0`.
179 * behavior undefined for value of `0`.
180 *
180 *
181 **/
181 **/
182 OutputArea.prototype.scroll_if_long = function (lines) {
182 OutputArea.prototype.scroll_if_long = function (lines) {
183 var n = lines | OutputArea.minimum_scroll_threshold;
183 var n = lines | OutputArea.minimum_scroll_threshold;
184 if(n <= 0){
184 if(n <= 0){
185 return
185 return
186 }
186 }
187
187
188 if (this._should_scroll(n)) {
188 if (this._should_scroll(n)) {
189 // only allow scrolling long-enough output
189 // only allow scrolling long-enough output
190 this.scroll_area();
190 this.scroll_area();
191 }
191 }
192 };
192 };
193
193
194
194
195 OutputArea.prototype.toggle_scroll = function () {
195 OutputArea.prototype.toggle_scroll = function () {
196 if (this.scrolled) {
196 if (this.scrolled) {
197 this.unscroll_area();
197 this.unscroll_area();
198 } else {
198 } else {
199 // only allow scrolling long-enough output
199 // only allow scrolling long-enough output
200 this.scroll_if_long();
200 this.scroll_if_long();
201 }
201 }
202 };
202 };
203
203
204
204
205 // typeset with MathJax if MathJax is available
205 // typeset with MathJax if MathJax is available
206 OutputArea.prototype.typeset = function () {
206 OutputArea.prototype.typeset = function () {
207 if (window.MathJax){
207 if (window.MathJax){
208 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
208 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
209 }
209 }
210 };
210 };
211
211
212
212
213 OutputArea.prototype.handle_output = function (msg) {
213 OutputArea.prototype.handle_output = function (msg) {
214 var json = {};
214 var json = {};
215 var msg_type = json.output_type = msg.header.msg_type;
215 var msg_type = json.output_type = msg.header.msg_type;
216 var content = msg.content;
216 var content = msg.content;
217 if (msg_type === "stream") {
217 if (msg_type === "stream") {
218 json.text = content.data;
218 json.text = content.data;
219 json.stream = content.name;
219 json.stream = content.name;
220 } else if (msg_type === "display_data") {
220 } else if (msg_type === "display_data") {
221 json = content.data;
221 json = content.data;
222 json.output_type = msg_type;
222 json.output_type = msg_type;
223 json.metadata = content.metadata;
223 json.metadata = content.metadata;
224 } else if (msg_type === "pyout") {
224 } else if (msg_type === "pyout") {
225 json = content.data;
225 json = content.data;
226 json.output_type = msg_type;
226 json.output_type = msg_type;
227 json.metadata = content.metadata;
227 json.metadata = content.metadata;
228 json.prompt_number = content.execution_count;
228 json.prompt_number = content.execution_count;
229 } else if (msg_type === "pyerr") {
229 } else if (msg_type === "pyerr") {
230 json.ename = content.ename;
230 json.ename = content.ename;
231 json.evalue = content.evalue;
231 json.evalue = content.evalue;
232 json.traceback = content.traceback;
232 json.traceback = content.traceback;
233 }
233 }
234 this.append_output(json);
234 this.append_output(json);
235 };
235 };
236
236
237
237
238 OutputArea.prototype.rename_keys = function (data, key_map) {
238 OutputArea.prototype.rename_keys = function (data, key_map) {
239 var remapped = {};
239 var remapped = {};
240 for (var key in data) {
240 for (var key in data) {
241 var new_key = key_map[key] || key;
241 var new_key = key_map[key] || key;
242 remapped[new_key] = data[key];
242 remapped[new_key] = data[key];
243 }
243 }
244 return remapped;
244 return remapped;
245 };
245 };
246
246
247
247
248 OutputArea.output_types = [
248 OutputArea.output_types = [
249 'application/javascript',
249 'application/javascript',
250 'text/html',
250 'text/html',
251 'text/latex',
251 'text/latex',
252 'image/svg+xml',
252 'image/svg+xml',
253 'image/png',
253 'image/png',
254 'image/jpeg',
254 'image/jpeg',
255 'application/pdf',
255 'text/plain'
256 'text/plain'
256 ];
257 ];
257
258
258 OutputArea.prototype.validate_output = function (json) {
259 OutputArea.prototype.validate_output = function (json) {
259 // scrub invalid outputs
260 // scrub invalid outputs
260 // TODO: right now everything is a string, but JSON really shouldn't be.
261 // TODO: right now everything is a string, but JSON really shouldn't be.
261 // nbformat 4 will fix that.
262 // nbformat 4 will fix that.
262 $.map(OutputArea.output_types, function(key){
263 $.map(OutputArea.output_types, function(key){
263 if (json[key] !== undefined && typeof json[key] !== 'string') {
264 if (json[key] !== undefined && typeof json[key] !== 'string') {
264 console.log("Invalid type for " + key, json[key]);
265 console.log("Invalid type for " + key, json[key]);
265 delete json[key];
266 delete json[key];
266 }
267 }
267 });
268 });
268 return json;
269 return json;
269 };
270 };
270
271
271 OutputArea.prototype.append_output = function (json) {
272 OutputArea.prototype.append_output = function (json) {
272 this.expand();
273 this.expand();
273 // Clear the output if clear is queued.
274 // Clear the output if clear is queued.
274 var needs_height_reset = false;
275 var needs_height_reset = false;
275 if (this.clear_queued) {
276 if (this.clear_queued) {
276 this.clear_output(false);
277 this.clear_output(false);
277 needs_height_reset = true;
278 needs_height_reset = true;
278 }
279 }
279
280
280 // validate output data types
281 // validate output data types
281 json = this.validate_output(json);
282 json = this.validate_output(json);
282
283
283 if (json.output_type === 'pyout') {
284 if (json.output_type === 'pyout') {
284 this.append_pyout(json);
285 this.append_pyout(json);
285 } else if (json.output_type === 'pyerr') {
286 } else if (json.output_type === 'pyerr') {
286 this.append_pyerr(json);
287 this.append_pyerr(json);
287 } else if (json.output_type === 'display_data') {
288 } else if (json.output_type === 'display_data') {
288 this.append_display_data(json);
289 this.append_display_data(json);
289 } else if (json.output_type === 'stream') {
290 } else if (json.output_type === 'stream') {
290 this.append_stream(json);
291 this.append_stream(json);
291 }
292 }
292
293
293 this.outputs.push(json);
294 this.outputs.push(json);
294
295
295 // Only reset the height to automatic if the height is currently
296 // Only reset the height to automatic if the height is currently
296 // fixed (done by wait=True flag on clear_output).
297 // fixed (done by wait=True flag on clear_output).
297 if (needs_height_reset) {
298 if (needs_height_reset) {
298 this.element.height('');
299 this.element.height('');
299 }
300 }
300
301
301 var that = this;
302 var that = this;
302 setTimeout(function(){that.element.trigger('resize');}, 100);
303 setTimeout(function(){that.element.trigger('resize');}, 100);
303 };
304 };
304
305
305
306
306 OutputArea.prototype.create_output_area = function () {
307 OutputArea.prototype.create_output_area = function () {
307 var oa = $("<div/>").addClass("output_area");
308 var oa = $("<div/>").addClass("output_area");
308 if (this.prompt_area) {
309 if (this.prompt_area) {
309 oa.append($('<div/>').addClass('prompt'));
310 oa.append($('<div/>').addClass('prompt'));
310 }
311 }
311 return oa;
312 return oa;
312 };
313 };
313
314
314
315
315 function _get_metadata_key(metadata, key, mime) {
316 function _get_metadata_key(metadata, key, mime) {
316 var mime_md = metadata[mime];
317 var mime_md = metadata[mime];
317 // mime-specific higher priority
318 // mime-specific higher priority
318 if (mime_md && mime_md[key] !== undefined) {
319 if (mime_md && mime_md[key] !== undefined) {
319 return mime_md[key];
320 return mime_md[key];
320 }
321 }
321 // fallback on global
322 // fallback on global
322 return metadata[key];
323 return metadata[key];
323 }
324 }
324
325
325 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
326 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
326 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
327 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
327 if (_get_metadata_key(md, 'isolated', mime)) {
328 if (_get_metadata_key(md, 'isolated', mime)) {
328 // Create an iframe to isolate the subarea from the rest of the
329 // Create an iframe to isolate the subarea from the rest of the
329 // document
330 // document
330 var iframe = $('<iframe/>').addClass('box-flex1');
331 var iframe = $('<iframe/>').addClass('box-flex1');
331 iframe.css({'height':1, 'width':'100%', 'display':'block'});
332 iframe.css({'height':1, 'width':'100%', 'display':'block'});
332 iframe.attr('frameborder', 0);
333 iframe.attr('frameborder', 0);
333 iframe.attr('scrolling', 'auto');
334 iframe.attr('scrolling', 'auto');
334
335
335 // Once the iframe is loaded, the subarea is dynamically inserted
336 // Once the iframe is loaded, the subarea is dynamically inserted
336 iframe.on('load', function() {
337 iframe.on('load', function() {
337 // Workaround needed by Firefox, to properly render svg inside
338 // Workaround needed by Firefox, to properly render svg inside
338 // iframes, see http://stackoverflow.com/questions/10177190/
339 // iframes, see http://stackoverflow.com/questions/10177190/
339 // svg-dynamically-added-to-iframe-does-not-render-correctly
340 // svg-dynamically-added-to-iframe-does-not-render-correctly
340 this.contentDocument.open();
341 this.contentDocument.open();
341
342
342 // Insert the subarea into the iframe
343 // Insert the subarea into the iframe
343 // We must directly write the html. When using Jquery's append
344 // We must directly write the html. When using Jquery's append
344 // method, javascript is evaluated in the parent document and
345 // method, javascript is evaluated in the parent document and
345 // not in the iframe document.
346 // not in the iframe document.
346 this.contentDocument.write(subarea.html());
347 this.contentDocument.write(subarea.html());
347
348
348 this.contentDocument.close();
349 this.contentDocument.close();
349
350
350 var body = this.contentDocument.body;
351 var body = this.contentDocument.body;
351 // Adjust the iframe height automatically
352 // Adjust the iframe height automatically
352 iframe.height(body.scrollHeight + 'px');
353 iframe.height(body.scrollHeight + 'px');
353 });
354 });
354
355
355 // Elements should be appended to the inner subarea and not to the
356 // Elements should be appended to the inner subarea and not to the
356 // iframe
357 // iframe
357 iframe.append = function(that) {
358 iframe.append = function(that) {
358 subarea.append(that);
359 subarea.append(that);
359 };
360 };
360
361
361 return iframe;
362 return iframe;
362 } else {
363 } else {
363 return subarea;
364 return subarea;
364 }
365 }
365 }
366 }
366
367
367
368
368 OutputArea.prototype._append_javascript_error = function (err, element) {
369 OutputArea.prototype._append_javascript_error = function (err, element) {
369 // display a message when a javascript error occurs in display output
370 // display a message when a javascript error occurs in display output
370 var msg = "Javascript error adding output!"
371 var msg = "Javascript error adding output!"
371 if ( element === undefined ) return;
372 if ( element === undefined ) return;
372 element.append(
373 element.append(
373 $('<div/>').html(msg + "<br/>" +
374 $('<div/>').html(msg + "<br/>" +
374 err.toString() +
375 err.toString() +
375 '<br/>See your browser Javascript console for more details.'
376 '<br/>See your browser Javascript console for more details.'
376 ).addClass('js-error')
377 ).addClass('js-error')
377 );
378 );
378 };
379 };
379
380
380 OutputArea.prototype._safe_append = function (toinsert) {
381 OutputArea.prototype._safe_append = function (toinsert) {
381 // safely append an item to the document
382 // safely append an item to the document
382 // this is an object created by user code,
383 // this is an object created by user code,
383 // and may have errors, which should not be raised
384 // and may have errors, which should not be raised
384 // under any circumstances.
385 // under any circumstances.
385 try {
386 try {
386 this.element.append(toinsert);
387 this.element.append(toinsert);
387 } catch(err) {
388 } catch(err) {
388 console.log(err);
389 console.log(err);
389 // Create an actual output_area and output_subarea, which creates
390 // Create an actual output_area and output_subarea, which creates
390 // the prompt area and the proper indentation.
391 // the prompt area and the proper indentation.
391 var toinsert = this.create_output_area();
392 var toinsert = this.create_output_area();
392 var subarea = $('<div/>').addClass('output_subarea');
393 var subarea = $('<div/>').addClass('output_subarea');
393 toinsert.append(subarea);
394 toinsert.append(subarea);
394 this._append_javascript_error(err, subarea);
395 this._append_javascript_error(err, subarea);
395 this.element.append(toinsert);
396 this.element.append(toinsert);
396 }
397 }
397 };
398 };
398
399
399
400
400 OutputArea.prototype.append_pyout = function (json) {
401 OutputArea.prototype.append_pyout = function (json) {
401 var n = json.prompt_number || ' ';
402 var n = json.prompt_number || ' ';
402 var toinsert = this.create_output_area();
403 var toinsert = this.create_output_area();
403 if (this.prompt_area) {
404 if (this.prompt_area) {
404 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
405 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
405 }
406 }
406 this.append_mime_type(json, toinsert);
407 this.append_mime_type(json, toinsert);
407 this._safe_append(toinsert);
408 this._safe_append(toinsert);
408 // If we just output latex, typeset it.
409 // If we just output latex, typeset it.
409 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
410 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
410 this.typeset();
411 this.typeset();
411 }
412 }
412 };
413 };
413
414
414
415
415 OutputArea.prototype.append_pyerr = function (json) {
416 OutputArea.prototype.append_pyerr = function (json) {
416 var tb = json.traceback;
417 var tb = json.traceback;
417 if (tb !== undefined && tb.length > 0) {
418 if (tb !== undefined && tb.length > 0) {
418 var s = '';
419 var s = '';
419 var len = tb.length;
420 var len = tb.length;
420 for (var i=0; i<len; i++) {
421 for (var i=0; i<len; i++) {
421 s = s + tb[i] + '\n';
422 s = s + tb[i] + '\n';
422 }
423 }
423 s = s + '\n';
424 s = s + '\n';
424 var toinsert = this.create_output_area();
425 var toinsert = this.create_output_area();
425 this.append_text(s, {}, toinsert);
426 this.append_text(s, {}, toinsert);
426 this._safe_append(toinsert);
427 this._safe_append(toinsert);
427 }
428 }
428 };
429 };
429
430
430
431
431 OutputArea.prototype.append_stream = function (json) {
432 OutputArea.prototype.append_stream = function (json) {
432 // temporary fix: if stream undefined (json file written prior to this patch),
433 // temporary fix: if stream undefined (json file written prior to this patch),
433 // default to most likely stdout:
434 // default to most likely stdout:
434 if (json.stream == undefined){
435 if (json.stream == undefined){
435 json.stream = 'stdout';
436 json.stream = 'stdout';
436 }
437 }
437 var text = json.text;
438 var text = json.text;
438 var subclass = "output_"+json.stream;
439 var subclass = "output_"+json.stream;
439 if (this.outputs.length > 0){
440 if (this.outputs.length > 0){
440 // have at least one output to consider
441 // have at least one output to consider
441 var last = this.outputs[this.outputs.length-1];
442 var last = this.outputs[this.outputs.length-1];
442 if (last.output_type == 'stream' && json.stream == last.stream){
443 if (last.output_type == 'stream' && json.stream == last.stream){
443 // latest output was in the same stream,
444 // latest output was in the same stream,
444 // so append directly into its pre tag
445 // so append directly into its pre tag
445 // escape ANSI & HTML specials:
446 // escape ANSI & HTML specials:
446 var pre = this.element.find('div.'+subclass).last().find('pre');
447 var pre = this.element.find('div.'+subclass).last().find('pre');
447 var html = utils.fixCarriageReturn(
448 var html = utils.fixCarriageReturn(
448 pre.html() + utils.fixConsole(text));
449 pre.html() + utils.fixConsole(text));
449 pre.html(html);
450 pre.html(html);
450 return;
451 return;
451 }
452 }
452 }
453 }
453
454
454 if (!text.replace("\r", "")) {
455 if (!text.replace("\r", "")) {
455 // text is nothing (empty string, \r, etc.)
456 // text is nothing (empty string, \r, etc.)
456 // so don't append any elements, which might add undesirable space
457 // so don't append any elements, which might add undesirable space
457 return;
458 return;
458 }
459 }
459
460
460 // If we got here, attach a new div
461 // If we got here, attach a new div
461 var toinsert = this.create_output_area();
462 var toinsert = this.create_output_area();
462 this.append_text(text, {}, toinsert, "output_stream "+subclass);
463 this.append_text(text, {}, toinsert, "output_stream "+subclass);
463 this._safe_append(toinsert);
464 this._safe_append(toinsert);
464 };
465 };
465
466
466
467
467 OutputArea.prototype.append_display_data = function (json) {
468 OutputArea.prototype.append_display_data = function (json) {
468 var toinsert = this.create_output_area();
469 var toinsert = this.create_output_area();
469 if (this.append_mime_type(json, toinsert)) {
470 if (this.append_mime_type(json, toinsert)) {
470 this._safe_append(toinsert);
471 this._safe_append(toinsert);
471 // If we just output latex, typeset it.
472 // If we just output latex, typeset it.
472 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
473 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
473 this.typeset();
474 this.typeset();
474 }
475 }
475 }
476 }
476 };
477 };
477
478
478
479
479 OutputArea.safe_outputs = {
480 OutputArea.safe_outputs = {
480 'text/plain' : true,
481 'text/plain' : true,
481 'image/png' : true,
482 'image/png' : true,
482 'image/jpeg' : true
483 'image/jpeg' : true
483 };
484 };
484
485
485 OutputArea.prototype.append_mime_type = function (json, element) {
486 OutputArea.prototype.append_mime_type = function (json, element) {
486 for (var type_i in OutputArea.display_order) {
487 for (var type_i in OutputArea.display_order) {
487 var type = OutputArea.display_order[type_i];
488 var type = OutputArea.display_order[type_i];
488 var append = OutputArea.append_map[type];
489 var append = OutputArea.append_map[type];
489 if ((json[type] !== undefined) && append) {
490 if ((json[type] !== undefined) && append) {
490 if (!this.trusted && !OutputArea.safe_outputs[type]) {
491 if (!this.trusted && !OutputArea.safe_outputs[type]) {
491 // not trusted show warning and do not display
492 // not trusted show warning and do not display
492 var content = {
493 var content = {
493 text : "Untrusted " + type + " output ignored.",
494 text : "Untrusted " + type + " output ignored.",
494 stream : "stderr"
495 stream : "stderr"
495 }
496 }
496 this.append_stream(content);
497 this.append_stream(content);
497 continue;
498 continue;
498 }
499 }
499 var md = json.metadata || {};
500 var md = json.metadata || {};
500 var toinsert = append.apply(this, [json[type], md, element]);
501 var toinsert = append.apply(this, [json[type], md, element]);
501 $([IPython.events]).trigger('output_appended.OutputArea', [type, json[type], md, toinsert]);
502 $([IPython.events]).trigger('output_appended.OutputArea', [type, json[type], md, toinsert]);
502 return true;
503 return true;
503 }
504 }
504 }
505 }
505 return false;
506 return false;
506 };
507 };
507
508
508
509
509 OutputArea.prototype.append_html = function (html, md, element) {
510 OutputArea.prototype.append_html = function (html, md, element) {
510 var type = 'text/html';
511 var type = 'text/html';
511 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
512 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
512 IPython.keyboard_manager.register_events(toinsert);
513 IPython.keyboard_manager.register_events(toinsert);
513 toinsert.append(html);
514 toinsert.append(html);
514 element.append(toinsert);
515 element.append(toinsert);
515 return toinsert;
516 return toinsert;
516 };
517 };
517
518
518
519
519 OutputArea.prototype.append_javascript = function (js, md, element) {
520 OutputArea.prototype.append_javascript = function (js, md, element) {
520 // We just eval the JS code, element appears in the local scope.
521 // We just eval the JS code, element appears in the local scope.
521 var type = 'application/javascript';
522 var type = 'application/javascript';
522 var toinsert = this.create_output_subarea(md, "output_javascript", type);
523 var toinsert = this.create_output_subarea(md, "output_javascript", type);
523 IPython.keyboard_manager.register_events(toinsert);
524 IPython.keyboard_manager.register_events(toinsert);
524 element.append(toinsert);
525 element.append(toinsert);
525 // FIXME TODO : remove `container element for 3.0`
526 // FIXME TODO : remove `container element for 3.0`
526 //backward compat, js should be eval'ed in a context where `container` is defined.
527 //backward compat, js should be eval'ed in a context where `container` is defined.
527 var container = element;
528 var container = element;
528 container.show = function(){console.log('Warning "container.show()" is deprecated.')};
529 container.show = function(){console.log('Warning "container.show()" is deprecated.')};
529 // end backward compat
530 // end backward compat
530 try {
531 try {
531 eval(js);
532 eval(js);
532 } catch(err) {
533 } catch(err) {
533 console.log(err);
534 console.log(err);
534 this._append_javascript_error(err, toinsert);
535 this._append_javascript_error(err, toinsert);
535 }
536 }
536 return toinsert;
537 return toinsert;
537 };
538 };
538
539
539
540
540 OutputArea.prototype.append_text = function (data, md, element, extra_class) {
541 OutputArea.prototype.append_text = function (data, md, element, extra_class) {
541 var type = 'text/plain';
542 var type = 'text/plain';
542 var toinsert = this.create_output_subarea(md, "output_text", type);
543 var toinsert = this.create_output_subarea(md, "output_text", type);
543 // escape ANSI & HTML specials in plaintext:
544 // escape ANSI & HTML specials in plaintext:
544 data = utils.fixConsole(data);
545 data = utils.fixConsole(data);
545 data = utils.fixCarriageReturn(data);
546 data = utils.fixCarriageReturn(data);
546 data = utils.autoLinkUrls(data);
547 data = utils.autoLinkUrls(data);
547 if (extra_class){
548 if (extra_class){
548 toinsert.addClass(extra_class);
549 toinsert.addClass(extra_class);
549 }
550 }
550 toinsert.append($("<pre/>").html(data));
551 toinsert.append($("<pre/>").html(data));
551 element.append(toinsert);
552 element.append(toinsert);
552 return toinsert;
553 return toinsert;
553 };
554 };
554
555
555
556
556 OutputArea.prototype.append_svg = function (svg, md, element) {
557 OutputArea.prototype.append_svg = function (svg, md, element) {
557 var type = 'image/svg+xml';
558 var type = 'image/svg+xml';
558 var toinsert = this.create_output_subarea(md, "output_svg", type);
559 var toinsert = this.create_output_subarea(md, "output_svg", type);
559 toinsert.append(svg);
560 toinsert.append(svg);
560 element.append(toinsert);
561 element.append(toinsert);
561 return toinsert;
562 return toinsert;
562 };
563 };
563
564
564
565
565 OutputArea.prototype._dblclick_to_reset_size = function (img) {
566 OutputArea.prototype._dblclick_to_reset_size = function (img) {
566 // schedule wrapping image in resizable after a delay,
567 // schedule wrapping image in resizable after a delay,
567 // so we don't end up calling resize on a zero-size object
568 // so we don't end up calling resize on a zero-size object
568 var that = this;
569 var that = this;
569 setTimeout(function () {
570 setTimeout(function () {
570 var h0 = img.height();
571 var h0 = img.height();
571 var w0 = img.width();
572 var w0 = img.width();
572 if (!(h0 && w0)) {
573 if (!(h0 && w0)) {
573 // zero size, schedule another timeout
574 // zero size, schedule another timeout
574 that._dblclick_to_reset_size(img);
575 that._dblclick_to_reset_size(img);
575 return;
576 return;
576 }
577 }
577 img.resizable({
578 img.resizable({
578 aspectRatio: true,
579 aspectRatio: true,
579 autoHide: true
580 autoHide: true
580 });
581 });
581 img.dblclick(function () {
582 img.dblclick(function () {
582 // resize wrapper & image together for some reason:
583 // resize wrapper & image together for some reason:
583 img.parent().height(h0);
584 img.parent().height(h0);
584 img.height(h0);
585 img.height(h0);
585 img.parent().width(w0);
586 img.parent().width(w0);
586 img.width(w0);
587 img.width(w0);
587 });
588 });
588 }, 250);
589 }, 250);
589 };
590 };
590
591
591 var set_width_height = function (img, md, mime) {
592 var set_width_height = function (img, md, mime) {
592 // set width and height of an img element from metadata
593 // set width and height of an img element from metadata
593 var height = _get_metadata_key(md, 'height', mime);
594 var height = _get_metadata_key(md, 'height', mime);
594 if (height !== undefined) img.attr('height', height);
595 if (height !== undefined) img.attr('height', height);
595 var width = _get_metadata_key(md, 'width', mime);
596 var width = _get_metadata_key(md, 'width', mime);
596 if (width !== undefined) img.attr('width', width);
597 if (width !== undefined) img.attr('width', width);
597 };
598 };
598
599
599 OutputArea.prototype.append_png = function (png, md, element) {
600 OutputArea.prototype.append_png = function (png, md, element) {
600 var type = 'image/png';
601 var type = 'image/png';
601 var toinsert = this.create_output_subarea(md, "output_png", type);
602 var toinsert = this.create_output_subarea(md, "output_png", type);
602 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
603 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
603 set_width_height(img, md, 'image/png');
604 set_width_height(img, md, 'image/png');
604 this._dblclick_to_reset_size(img);
605 this._dblclick_to_reset_size(img);
605 toinsert.append(img);
606 toinsert.append(img);
606 element.append(toinsert);
607 element.append(toinsert);
607 return toinsert;
608 return toinsert;
608 };
609 };
609
610
610
611
611 OutputArea.prototype.append_jpeg = function (jpeg, md, element) {
612 OutputArea.prototype.append_jpeg = function (jpeg, md, element) {
612 var type = 'image/jpeg';
613 var type = 'image/jpeg';
613 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
614 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
614 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
615 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
615 set_width_height(img, md, 'image/jpeg');
616 set_width_height(img, md, 'image/jpeg');
616 this._dblclick_to_reset_size(img);
617 this._dblclick_to_reset_size(img);
617 toinsert.append(img);
618 toinsert.append(img);
618 element.append(toinsert);
619 element.append(toinsert);
619 return toinsert;
620 return toinsert;
620 };
621 };
621
622
622
623
624 OutputArea.prototype.append_pdf = function (pdf, md, element) {
625 var type = 'application/pdf';
626 var toinsert = this.create_output_subarea(md, "output_pdf", type);
627 var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf);
628 a.attr('target', '_blank');
629 a.text('View PDF')
630 toinsert.append(a);
631 element.append(toinsert);
632 return toinsert;
633 }
634
623 OutputArea.prototype.append_latex = function (latex, md, element) {
635 OutputArea.prototype.append_latex = function (latex, md, element) {
624 // This method cannot do the typesetting because the latex first has to
636 // This method cannot do the typesetting because the latex first has to
625 // be on the page.
637 // be on the page.
626 var type = 'text/latex';
638 var type = 'text/latex';
627 var toinsert = this.create_output_subarea(md, "output_latex", type);
639 var toinsert = this.create_output_subarea(md, "output_latex", type);
628 toinsert.append(latex);
640 toinsert.append(latex);
629 element.append(toinsert);
641 element.append(toinsert);
630 return toinsert;
642 return toinsert;
631 };
643 };
632
644
633
645
634 OutputArea.prototype.append_raw_input = function (msg) {
646 OutputArea.prototype.append_raw_input = function (msg) {
635 var that = this;
647 var that = this;
636 this.expand();
648 this.expand();
637 var content = msg.content;
649 var content = msg.content;
638 var area = this.create_output_area();
650 var area = this.create_output_area();
639
651
640 // disable any other raw_inputs, if they are left around
652 // disable any other raw_inputs, if they are left around
641 $("div.output_subarea.raw_input").remove();
653 $("div.output_subarea.raw_input").remove();
642
654
643 area.append(
655 area.append(
644 $("<div/>")
656 $("<div/>")
645 .addClass("box-flex1 output_subarea raw_input")
657 .addClass("box-flex1 output_subarea raw_input")
646 .append(
658 .append(
647 $("<span/>")
659 $("<span/>")
648 .addClass("input_prompt")
660 .addClass("input_prompt")
649 .text(content.prompt)
661 .text(content.prompt)
650 )
662 )
651 .append(
663 .append(
652 $("<input/>")
664 $("<input/>")
653 .addClass("raw_input")
665 .addClass("raw_input")
654 .attr('type', 'text')
666 .attr('type', 'text')
655 .attr("size", 47)
667 .attr("size", 47)
656 .keydown(function (event, ui) {
668 .keydown(function (event, ui) {
657 // make sure we submit on enter,
669 // make sure we submit on enter,
658 // and don't re-execute the *cell* on shift-enter
670 // and don't re-execute the *cell* on shift-enter
659 if (event.which === utils.keycodes.ENTER) {
671 if (event.which === utils.keycodes.ENTER) {
660 that._submit_raw_input();
672 that._submit_raw_input();
661 return false;
673 return false;
662 }
674 }
663 })
675 })
664 )
676 )
665 );
677 );
666
678
667 this.element.append(area);
679 this.element.append(area);
668 var raw_input = area.find('input.raw_input');
680 var raw_input = area.find('input.raw_input');
669 // Register events that enable/disable the keyboard manager while raw
681 // Register events that enable/disable the keyboard manager while raw
670 // input is focused.
682 // input is focused.
671 IPython.keyboard_manager.register_events(raw_input);
683 IPython.keyboard_manager.register_events(raw_input);
672 // Note, the following line used to read raw_input.focus().focus().
684 // Note, the following line used to read raw_input.focus().focus().
673 // This seemed to be needed otherwise only the cell would be focused.
685 // This seemed to be needed otherwise only the cell would be focused.
674 // But with the modal UI, this seems to work fine with one call to focus().
686 // But with the modal UI, this seems to work fine with one call to focus().
675 raw_input.focus();
687 raw_input.focus();
676 }
688 }
677
689
678 OutputArea.prototype._submit_raw_input = function (evt) {
690 OutputArea.prototype._submit_raw_input = function (evt) {
679 var container = this.element.find("div.raw_input");
691 var container = this.element.find("div.raw_input");
680 var theprompt = container.find("span.input_prompt");
692 var theprompt = container.find("span.input_prompt");
681 var theinput = container.find("input.raw_input");
693 var theinput = container.find("input.raw_input");
682 var value = theinput.val();
694 var value = theinput.val();
683 var content = {
695 var content = {
684 output_type : 'stream',
696 output_type : 'stream',
685 name : 'stdout',
697 name : 'stdout',
686 text : theprompt.text() + value + '\n'
698 text : theprompt.text() + value + '\n'
687 }
699 }
688 // remove form container
700 // remove form container
689 container.parent().remove();
701 container.parent().remove();
690 // replace with plaintext version in stdout
702 // replace with plaintext version in stdout
691 this.append_output(content, false);
703 this.append_output(content, false);
692 $([IPython.events]).trigger('send_input_reply.Kernel', value);
704 $([IPython.events]).trigger('send_input_reply.Kernel', value);
693 }
705 }
694
706
695
707
696 OutputArea.prototype.handle_clear_output = function (msg) {
708 OutputArea.prototype.handle_clear_output = function (msg) {
697 // msg spec v4 had stdout, stderr, display keys
709 // msg spec v4 had stdout, stderr, display keys
698 // v4.1 replaced these with just wait
710 // v4.1 replaced these with just wait
699 // The default behavior is the same (stdout=stderr=display=True, wait=False),
711 // The default behavior is the same (stdout=stderr=display=True, wait=False),
700 // so v4 messages will still be properly handled,
712 // so v4 messages will still be properly handled,
701 // except for the rarely used clearing less than all output.
713 // except for the rarely used clearing less than all output.
702 this.clear_output(msg.content.wait || false);
714 this.clear_output(msg.content.wait || false);
703 };
715 };
704
716
705
717
706 OutputArea.prototype.clear_output = function(wait) {
718 OutputArea.prototype.clear_output = function(wait) {
707 if (wait) {
719 if (wait) {
708
720
709 // If a clear is queued, clear before adding another to the queue.
721 // If a clear is queued, clear before adding another to the queue.
710 if (this.clear_queued) {
722 if (this.clear_queued) {
711 this.clear_output(false);
723 this.clear_output(false);
712 };
724 };
713
725
714 this.clear_queued = true;
726 this.clear_queued = true;
715 } else {
727 } else {
716
728
717 // Fix the output div's height if the clear_output is waiting for
729 // Fix the output div's height if the clear_output is waiting for
718 // new output (it is being used in an animation).
730 // new output (it is being used in an animation).
719 if (this.clear_queued) {
731 if (this.clear_queued) {
720 var height = this.element.height();
732 var height = this.element.height();
721 this.element.height(height);
733 this.element.height(height);
722 this.clear_queued = false;
734 this.clear_queued = false;
723 }
735 }
724
736
725 // clear all, no need for logic
737 // clear all, no need for logic
726 this.element.html("");
738 this.element.html("");
727 this.outputs = [];
739 this.outputs = [];
728 this.trusted = true;
740 this.trusted = true;
729 this.unscroll_area();
741 this.unscroll_area();
730 return;
742 return;
731 };
743 };
732 };
744 };
733
745
734
746
735 // JSON serialization
747 // JSON serialization
736
748
737 OutputArea.prototype.fromJSON = function (outputs) {
749 OutputArea.prototype.fromJSON = function (outputs) {
738 var len = outputs.length;
750 var len = outputs.length;
739 var data;
751 var data;
740
752
741 for (var i=0; i<len; i++) {
753 for (var i=0; i<len; i++) {
742 data = outputs[i];
754 data = outputs[i];
743 var msg_type = data.output_type;
755 var msg_type = data.output_type;
744 if (msg_type === "display_data" || msg_type === "pyout") {
756 if (msg_type === "display_data" || msg_type === "pyout") {
745 // convert short keys to mime keys
757 // convert short keys to mime keys
746 // TODO: remove mapping of short keys when we update to nbformat 4
758 // TODO: remove mapping of short keys when we update to nbformat 4
747 data = this.rename_keys(data, OutputArea.mime_map_r);
759 data = this.rename_keys(data, OutputArea.mime_map_r);
748 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
760 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
749 }
761 }
750
762
751 this.append_output(data);
763 this.append_output(data);
752 }
764 }
753 };
765 };
754
766
755
767
756 OutputArea.prototype.toJSON = function () {
768 OutputArea.prototype.toJSON = function () {
757 var outputs = [];
769 var outputs = [];
758 var len = this.outputs.length;
770 var len = this.outputs.length;
759 var data;
771 var data;
760 for (var i=0; i<len; i++) {
772 for (var i=0; i<len; i++) {
761 data = this.outputs[i];
773 data = this.outputs[i];
762 var msg_type = data.output_type;
774 var msg_type = data.output_type;
763 if (msg_type === "display_data" || msg_type === "pyout") {
775 if (msg_type === "display_data" || msg_type === "pyout") {
764 // convert mime keys to short keys
776 // convert mime keys to short keys
765 data = this.rename_keys(data, OutputArea.mime_map);
777 data = this.rename_keys(data, OutputArea.mime_map);
766 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
778 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
767 }
779 }
768 outputs[i] = data;
780 outputs[i] = data;
769 }
781 }
770 return outputs;
782 return outputs;
771 };
783 };
772
784
773 /**
785 /**
774 * Class properties
786 * Class properties
775 **/
787 **/
776
788
777 /**
789 /**
778 * Threshold to trigger autoscroll when the OutputArea is resized,
790 * Threshold to trigger autoscroll when the OutputArea is resized,
779 * typically when new outputs are added.
791 * typically when new outputs are added.
780 *
792 *
781 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
793 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
782 * unless it is < 0, in which case autoscroll will never be triggered
794 * unless it is < 0, in which case autoscroll will never be triggered
783 *
795 *
784 * @property auto_scroll_threshold
796 * @property auto_scroll_threshold
785 * @type Number
797 * @type Number
786 * @default 100
798 * @default 100
787 *
799 *
788 **/
800 **/
789 OutputArea.auto_scroll_threshold = 100;
801 OutputArea.auto_scroll_threshold = 100;
790
802
791 /**
803 /**
792 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
804 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
793 * shorter than this are never scrolled.
805 * shorter than this are never scrolled.
794 *
806 *
795 * @property minimum_scroll_threshold
807 * @property minimum_scroll_threshold
796 * @type Number
808 * @type Number
797 * @default 20
809 * @default 20
798 *
810 *
799 **/
811 **/
800 OutputArea.minimum_scroll_threshold = 20;
812 OutputArea.minimum_scroll_threshold = 20;
801
813
802
814
803
815
804 OutputArea.mime_map = {
816 OutputArea.mime_map = {
805 "text/plain" : "text",
817 "text/plain" : "text",
806 "text/html" : "html",
818 "text/html" : "html",
807 "image/svg+xml" : "svg",
819 "image/svg+xml" : "svg",
808 "image/png" : "png",
820 "image/png" : "png",
809 "image/jpeg" : "jpeg",
821 "image/jpeg" : "jpeg",
822 "application/pdf" : "pdf",
810 "text/latex" : "latex",
823 "text/latex" : "latex",
811 "application/json" : "json",
824 "application/json" : "json",
812 "application/javascript" : "javascript",
825 "application/javascript" : "javascript",
813 };
826 };
814
827
815 OutputArea.mime_map_r = {
828 OutputArea.mime_map_r = {
816 "text" : "text/plain",
829 "text" : "text/plain",
817 "html" : "text/html",
830 "html" : "text/html",
818 "svg" : "image/svg+xml",
831 "svg" : "image/svg+xml",
819 "png" : "image/png",
832 "png" : "image/png",
820 "jpeg" : "image/jpeg",
833 "jpeg" : "image/jpeg",
834 "pdf" : "application/pdf",
821 "latex" : "text/latex",
835 "latex" : "text/latex",
822 "json" : "application/json",
836 "json" : "application/json",
823 "javascript" : "application/javascript",
837 "javascript" : "application/javascript",
824 };
838 };
825
839
826 OutputArea.display_order = [
840 OutputArea.display_order = [
827 'application/javascript',
841 'application/javascript',
828 'text/html',
842 'text/html',
829 'text/latex',
843 'text/latex',
830 'image/svg+xml',
844 'image/svg+xml',
831 'image/png',
845 'image/png',
832 'image/jpeg',
846 'image/jpeg',
847 'application/pdf',
833 'text/plain'
848 'text/plain'
834 ];
849 ];
835
850
836 OutputArea.append_map = {
851 OutputArea.append_map = {
837 "text/plain" : OutputArea.prototype.append_text,
852 "text/plain" : OutputArea.prototype.append_text,
838 "text/html" : OutputArea.prototype.append_html,
853 "text/html" : OutputArea.prototype.append_html,
839 "image/svg+xml" : OutputArea.prototype.append_svg,
854 "image/svg+xml" : OutputArea.prototype.append_svg,
840 "image/png" : OutputArea.prototype.append_png,
855 "image/png" : OutputArea.prototype.append_png,
841 "image/jpeg" : OutputArea.prototype.append_jpeg,
856 "image/jpeg" : OutputArea.prototype.append_jpeg,
842 "text/latex" : OutputArea.prototype.append_latex,
857 "text/latex" : OutputArea.prototype.append_latex,
843 "application/json" : OutputArea.prototype.append_json,
858 "application/json" : OutputArea.prototype.append_json,
844 "application/javascript" : OutputArea.prototype.append_javascript,
859 "application/javascript" : OutputArea.prototype.append_javascript,
860 "application/pdf" : OutputArea.prototype.append_pdf
845 };
861 };
846
862
847 IPython.OutputArea = OutputArea;
863 IPython.OutputArea = OutputArea;
848
864
849 return IPython;
865 return IPython;
850
866
851 }(IPython));
867 }(IPython));
@@ -1,173 +1,173 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 // SaveWidget
9 // SaveWidget
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 SaveWidget = function (selector) {
17 var SaveWidget = function (selector) {
18 this.selector = selector;
18 this.selector = selector;
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
21 this.style();
21 this.style();
22 this.bind_events();
22 this.bind_events();
23 }
23 }
24 };
24 };
25
25
26
26
27 SaveWidget.prototype.style = function () {
27 SaveWidget.prototype.style = function () {
28 };
28 };
29
29
30
30
31 SaveWidget.prototype.bind_events = function () {
31 SaveWidget.prototype.bind_events = function () {
32 var that = this;
32 var that = this;
33 this.element.find('span#notebook_name').click(function () {
33 this.element.find('span#notebook_name').click(function () {
34 that.rename_notebook();
34 that.rename_notebook();
35 });
35 });
36 this.element.find('span#notebook_name').hover(function () {
36 this.element.find('span#notebook_name').hover(function () {
37 $(this).addClass("ui-state-hover");
37 $(this).addClass("ui-state-hover");
38 }, function () {
38 }, function () {
39 $(this).removeClass("ui-state-hover");
39 $(this).removeClass("ui-state-hover");
40 });
40 });
41 $([IPython.events]).on('notebook_loaded.Notebook', function () {
41 $([IPython.events]).on('notebook_loaded.Notebook', function () {
42 that.update_notebook_name();
42 that.update_notebook_name();
43 that.update_document_title();
43 that.update_document_title();
44 });
44 });
45 $([IPython.events]).on('notebook_saved.Notebook', function () {
45 $([IPython.events]).on('notebook_saved.Notebook', function () {
46 that.update_notebook_name();
46 that.update_notebook_name();
47 that.update_document_title();
47 that.update_document_title();
48 });
48 });
49 $([IPython.events]).on('notebook_renamed.Notebook', function () {
49 $([IPython.events]).on('notebook_renamed.Notebook', function () {
50 that.update_notebook_name();
50 that.update_notebook_name();
51 that.update_document_title();
51 that.update_document_title();
52 that.update_address_bar();
52 that.update_address_bar();
53 });
53 });
54 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
54 $([IPython.events]).on('notebook_save_failed.Notebook', function () {
55 that.set_save_status('Autosave Failed!');
55 that.set_save_status('Autosave Failed!');
56 });
56 });
57 $([IPython.events]).on('checkpoints_listed.Notebook', function (event, data) {
57 $([IPython.events]).on('checkpoints_listed.Notebook', function (event, data) {
58 that.set_last_checkpoint(data[0]);
58 that.set_last_checkpoint(data[0]);
59 });
59 });
60
60
61 $([IPython.events]).on('checkpoint_created.Notebook', function (event, data) {
61 $([IPython.events]).on('checkpoint_created.Notebook', function (event, data) {
62 that.set_last_checkpoint(data);
62 that.set_last_checkpoint(data);
63 });
63 });
64 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
64 $([IPython.events]).on('set_dirty.Notebook', function (event, data) {
65 that.set_autosaved(data.value);
65 that.set_autosaved(data.value);
66 });
66 });
67 };
67 };
68
68
69
69
70 SaveWidget.prototype.rename_notebook = function () {
70 SaveWidget.prototype.rename_notebook = function () {
71 var that = this;
71 var that = this;
72 var dialog = $('<div/>').append(
72 var dialog = $('<div/>').append(
73 $("<p/>").addClass("rename-message")
73 $("<p/>").addClass("rename-message")
74 .text('Enter a new notebook name:')
74 .text('Enter a new notebook name:')
75 ).append(
75 ).append(
76 $("<br/>")
76 $("<br/>")
77 ).append(
77 ).append(
78 $('<input/>').attr('type','text').attr('size','25')
78 $('<input/>').attr('type','text').attr('size','25')
79 .val(IPython.notebook.get_notebook_name())
79 .val(IPython.notebook.get_notebook_name())
80 );
80 );
81 IPython.dialog.modal({
81 IPython.dialog.modal({
82 title: "Rename Notebook",
82 title: "Rename Notebook",
83 body: dialog,
83 body: dialog,
84 buttons : {
84 buttons : {
85 "Cancel": {},
85 "Cancel": {},
86 "OK": {
86 "OK": {
87 class: "btn-primary",
87 class: "btn-primary",
88 click: function () {
88 click: function () {
89 var new_name = $(this).find('input').val();
89 var new_name = $(this).find('input').val();
90 if (!IPython.notebook.test_notebook_name(new_name)) {
90 if (!IPython.notebook.test_notebook_name(new_name)) {
91 $(this).find('.rename-message').text(
91 $(this).find('.rename-message').text(
92 "Invalid notebook name. Notebook names must "+
92 "Invalid notebook name. Notebook names must "+
93 "have 1 or more characters and can contain any characters " +
93 "have 1 or more characters and can contain any characters " +
94 "except :/\\. Please enter a new notebook name:"
94 "except :/\\. Please enter a new notebook name:"
95 );
95 );
96 return false;
96 return false;
97 } else {
97 } else {
98 IPython.notebook.rename(new_name);
98 IPython.notebook.rename(new_name);
99 }
99 }
100 }}
100 }}
101 },
101 },
102 open : function (event, ui) {
102 open : function (event, ui) {
103 var that = $(this);
103 var that = $(this);
104 // Upon ENTER, click the OK button.
104 // Upon ENTER, click the OK button.
105 that.find('input[type="text"]').keydown(function (event, ui) {
105 that.find('input[type="text"]').keydown(function (event, ui) {
106 if (event.which === utils.keycodes.ENTER) {
106 if (event.which === utils.keycodes.ENTER) {
107 that.find('.btn-primary').first().click();
107 that.find('.btn-primary').first().click();
108 return false;
108 return false;
109 }
109 }
110 });
110 });
111 that.find('input[type="text"]').focus().select();
111 that.find('input[type="text"]').focus().select();
112 }
112 }
113 });
113 });
114 }
114 }
115
115
116
116
117 SaveWidget.prototype.update_notebook_name = function () {
117 SaveWidget.prototype.update_notebook_name = function () {
118 var nbname = IPython.notebook.get_notebook_name();
118 var nbname = IPython.notebook.get_notebook_name();
119 this.element.find('span#notebook_name').text(nbname);
119 this.element.find('span#notebook_name').text(nbname);
120 };
120 };
121
121
122
122
123 SaveWidget.prototype.update_document_title = function () {
123 SaveWidget.prototype.update_document_title = function () {
124 var nbname = IPython.notebook.get_notebook_name();
124 var nbname = IPython.notebook.get_notebook_name();
125 document.title = nbname;
125 document.title = nbname;
126 };
126 };
127
127
128 SaveWidget.prototype.update_address_bar = function(){
128 SaveWidget.prototype.update_address_bar = function(){
129 var nbname = IPython.notebook.notebook_name;
129 var nbname = IPython.notebook.notebook_name;
130 var path = IPython.notebook.notebookPath();
130 var path = IPython.notebook.notebook_path;
131 var state = {path : utils.url_join_encode(path, nbname)};
131 var state = {path : utils.url_join_encode(path, nbname)};
132 window.history.replaceState(state, "", utils.url_join_encode(
132 window.history.replaceState(state, "", utils.url_join_encode(
133 "/notebooks",
133 "/notebooks",
134 path,
134 path,
135 nbname)
135 nbname)
136 );
136 );
137 }
137 }
138
138
139
139
140 SaveWidget.prototype.set_save_status = function (msg) {
140 SaveWidget.prototype.set_save_status = function (msg) {
141 this.element.find('span#autosave_status').text(msg);
141 this.element.find('span#autosave_status').text(msg);
142 }
142 }
143
143
144 SaveWidget.prototype.set_checkpoint_status = function (msg) {
144 SaveWidget.prototype.set_checkpoint_status = function (msg) {
145 this.element.find('span#checkpoint_status').text(msg);
145 this.element.find('span#checkpoint_status').text(msg);
146 }
146 }
147
147
148 SaveWidget.prototype.set_last_checkpoint = function (checkpoint) {
148 SaveWidget.prototype.set_last_checkpoint = function (checkpoint) {
149 if (!checkpoint) {
149 if (!checkpoint) {
150 this.set_checkpoint_status("");
150 this.set_checkpoint_status("");
151 return;
151 return;
152 }
152 }
153 var d = new Date(checkpoint.last_modified);
153 var d = new Date(checkpoint.last_modified);
154 this.set_checkpoint_status(
154 this.set_checkpoint_status(
155 "Last Checkpoint: " + d.format('mmm dd HH:MM')
155 "Last Checkpoint: " + d.format('mmm dd HH:MM')
156 );
156 );
157 }
157 }
158
158
159 SaveWidget.prototype.set_autosaved = function (dirty) {
159 SaveWidget.prototype.set_autosaved = function (dirty) {
160 if (dirty) {
160 if (dirty) {
161 this.set_save_status("(unsaved changes)");
161 this.set_save_status("(unsaved changes)");
162 } else {
162 } else {
163 this.set_save_status("(autosaved)");
163 this.set_save_status("(autosaved)");
164 }
164 }
165 };
165 };
166
166
167
167
168 IPython.SaveWidget = SaveWidget;
168 IPython.SaveWidget = SaveWidget;
169
169
170 return IPython;
170 return IPython;
171
171
172 }(IPython));
172 }(IPython));
173
173
@@ -1,3 +1,18 b''
1 #notification_area {
1 #notification_area {
2 z-index: 10;
2 z-index: 10;
3 }
3 }
4
5 .indicator_area {
6 color: @navbarLinkColor;
7 padding: 4px 3px;
8 margin: 0px;
9 width: 11px;
10 z-index: 10;
11 text-align: center;
12 }
13
14 #kernel_indicator {
15 // Pull it to the right, outside the container boundary
16 margin-right: -16px;
17 }
18
@@ -1,22 +1,13 b''
1 .notification_widget{
1 .notification_widget {
2 color: @navbarLinkColor;
2 color: @navbarLinkColor;
3 padding: 1px 12px;
3 padding: 1px 12px;
4 margin: 2px 4px;
4 margin: 2px 4px;
5 z-index: 10;
5 z-index: 10;
6 border: 1px solid #ccc;
6 border: 1px solid #ccc;
7 border-radius: @baseBorderRadius;
7 border-radius: @baseBorderRadius;
8 background: rgba(240, 240, 240, 0.5);
8 background: rgba(240, 240, 240, 0.5);
9
9
10 &.span {
10 &.span {
11 padding-right:2px;
11 padding-right:2px;
12 }
12 }
13
14 }
15
16 #indicator_area{
17 color: @navbarLinkColor;
18 padding: 2px 2px;
19 margin: 2px -9px 2px 4px;
20 z-index: 10;
21
22 }
13 }
@@ -1,603 +1,609 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 "use strict";
19 "use strict";
20
20
21 var utils = IPython.utils;
21 var utils = IPython.utils;
22
22
23 // Initialization and connection.
23 // Initialization and connection.
24 /**
24 /**
25 * A Kernel Class to communicate with the Python kernel
25 * A Kernel Class to communicate with the Python kernel
26 * @Class Kernel
26 * @Class Kernel
27 */
27 */
28 var Kernel = function (base_url) {
28 var Kernel = function (kernel_service_url) {
29 this.kernel_id = null;
29 this.kernel_id = null;
30 this.shell_channel = null;
30 this.shell_channel = null;
31 this.iopub_channel = null;
31 this.iopub_channel = null;
32 this.stdin_channel = null;
32 this.stdin_channel = null;
33 this.base_url = base_url;
33 this.kernel_service_url = kernel_service_url;
34 this.running = false;
34 this.running = false;
35 this.username = "username";
35 this.username = "username";
36 this.session_id = utils.uuid();
36 this.session_id = utils.uuid();
37 this._msg_callbacks = {};
37 this._msg_callbacks = {};
38
38
39 if (typeof(WebSocket) !== 'undefined') {
39 if (typeof(WebSocket) !== 'undefined') {
40 this.WebSocket = WebSocket;
40 this.WebSocket = WebSocket;
41 } else if (typeof(MozWebSocket) !== 'undefined') {
41 } else if (typeof(MozWebSocket) !== 'undefined') {
42 this.WebSocket = MozWebSocket;
42 this.WebSocket = MozWebSocket;
43 } else {
43 } else {
44 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.');
44 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.');
45 }
45 }
46
46
47 this.bind_events();
47 this.bind_events();
48 this.init_iopub_handlers();
48 this.init_iopub_handlers();
49 this.comm_manager = new IPython.CommManager(this);
49 this.comm_manager = new IPython.CommManager(this);
50 this.widget_manager = new IPython.WidgetManager(this.comm_manager);
50 this.widget_manager = new IPython.WidgetManager(this.comm_manager);
51 };
51 };
52
52
53
53
54 Kernel.prototype._get_msg = function (msg_type, content, metadata) {
54 Kernel.prototype._get_msg = function (msg_type, content, metadata) {
55 var msg = {
55 var msg = {
56 header : {
56 header : {
57 msg_id : utils.uuid(),
57 msg_id : utils.uuid(),
58 username : this.username,
58 username : this.username,
59 session : this.session_id,
59 session : this.session_id,
60 msg_type : msg_type
60 msg_type : msg_type
61 },
61 },
62 metadata : metadata || {},
62 metadata : metadata || {},
63 content : content,
63 content : content,
64 parent_header : {}
64 parent_header : {}
65 };
65 };
66 return msg;
66 return msg;
67 };
67 };
68
68
69 Kernel.prototype.bind_events = function () {
69 Kernel.prototype.bind_events = function () {
70 var that = this;
70 var that = this;
71 $([IPython.events]).on('send_input_reply.Kernel', function(evt, data) {
71 $([IPython.events]).on('send_input_reply.Kernel', function(evt, data) {
72 that.send_input_reply(data);
72 that.send_input_reply(data);
73 });
73 });
74 };
74 };
75
75
76 // Initialize the iopub handlers
76 // Initialize the iopub handlers
77
77
78 Kernel.prototype.init_iopub_handlers = function () {
78 Kernel.prototype.init_iopub_handlers = function () {
79 var output_types = ['stream', 'display_data', 'pyout', 'pyerr'];
79 var output_types = ['stream', 'display_data', 'pyout', 'pyerr'];
80 this._iopub_handlers = {};
80 this._iopub_handlers = {};
81 this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
81 this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
82 this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
82 this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
83
83
84 for (var i=0; i < output_types.length; i++) {
84 for (var i=0; i < output_types.length; i++) {
85 this.register_iopub_handler(output_types[i], $.proxy(this._handle_output_message, this));
85 this.register_iopub_handler(output_types[i], $.proxy(this._handle_output_message, this));
86 }
86 }
87 };
87 };
88
88
89 /**
89 /**
90 * Start the Python kernel
90 * Start the Python kernel
91 * @method start
91 * @method start
92 */
92 */
93 Kernel.prototype.start = function (params) {
93 Kernel.prototype.start = function (params) {
94 params = params || {};
94 params = params || {};
95 if (!this.running) {
95 if (!this.running) {
96 var qs = $.param(params);
96 var qs = $.param(params);
97 var url = this.base_url + '?' + qs;
97 $.post(utils.url_join_encode(this.kernel_service_url) + '?' + qs,
98 $.post(url,
99 $.proxy(this._kernel_started, this),
98 $.proxy(this._kernel_started, this),
100 'json'
99 'json'
101 );
100 );
102 }
101 }
103 };
102 };
104
103
105 /**
104 /**
106 * Restart the python kernel.
105 * Restart the python kernel.
107 *
106 *
108 * Emit a 'status_restarting.Kernel' event with
107 * Emit a 'status_restarting.Kernel' event with
109 * the current object as parameter
108 * the current object as parameter
110 *
109 *
111 * @method restart
110 * @method restart
112 */
111 */
113 Kernel.prototype.restart = function () {
112 Kernel.prototype.restart = function () {
114 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
113 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
115 if (this.running) {
114 if (this.running) {
116 this.stop_channels();
115 this.stop_channels();
117 var url = utils.url_join_encode(this.kernel_url, "restart");
116 $.post(utils.url_join_encode(this.kernel_url, "restart"),
118 $.post(url,
119 $.proxy(this._kernel_started, this),
117 $.proxy(this._kernel_started, this),
120 'json'
118 'json'
121 );
119 );
122 }
120 }
123 };
121 };
124
122
125
123
126 Kernel.prototype._kernel_started = function (json) {
124 Kernel.prototype._kernel_started = function (json) {
127 console.log("Kernel started: ", json.id);
125 console.log("Kernel started: ", json.id);
128 this.running = true;
126 this.running = true;
129 this.kernel_id = json.id;
127 this.kernel_id = json.id;
130 var ws_url = json.ws_url;
128 var ws_url = json.ws_url;
131 if (ws_url.match(/wss?:\/\//) === null) {
129 if (ws_url.match(/wss?:\/\//) === null) {
132 // trailing 's' in https will become wss for secure web sockets
130 // trailing 's' in https will become wss for secure web sockets
133 var prot = location.protocol.replace('http', 'ws') + "//";
131 var prot = location.protocol.replace('http', 'ws') + "//";
134 ws_url = prot + location.host + ws_url;
132 ws_url = prot + location.host + ws_url;
135 }
133 }
136 this.ws_url = ws_url;
134 var parsed = utils.parse_url(ws_url);
137 this.kernel_url = utils.url_join_encode(this.base_url, this.kernel_id);
135 this.ws_host = parsed.protocol + "//" + parsed.host;
136 this.kernel_url = utils.url_path_join(this.kernel_service_url, this.kernel_id);
137 this.ws_url = utils.url_path_join(parsed.pathname, this.kernel_url);
138 this.start_channels();
138 this.start_channels();
139 };
139 };
140
140
141
141
142 Kernel.prototype._websocket_closed = function(ws_url, early) {
142 Kernel.prototype._websocket_closed = function(ws_url, early) {
143 this.stop_channels();
143 this.stop_channels();
144 $([IPython.events]).trigger('websocket_closed.Kernel',
144 $([IPython.events]).trigger('websocket_closed.Kernel',
145 {ws_url: ws_url, kernel: this, early: early}
145 {ws_url: ws_url, kernel: this, early: early}
146 );
146 );
147 };
147 };
148
148
149 /**
149 /**
150 * Start the `shell`and `iopub` channels.
150 * Start the `shell`and `iopub` channels.
151 * Will stop and restart them if they already exist.
151 * Will stop and restart them if they already exist.
152 *
152 *
153 * @method start_channels
153 * @method start_channels
154 */
154 */
155 Kernel.prototype.start_channels = function () {
155 Kernel.prototype.start_channels = function () {
156 var that = this;
156 var that = this;
157 this.stop_channels();
157 this.stop_channels();
158 var ws_url = this.ws_url + this.kernel_url;
158 console.log("Starting WebSockets:", this.ws_host + this.ws_url);
159 console.log("Starting WebSockets:", ws_url);
159 this.shell_channel = new this.WebSocket(
160 this.shell_channel = new this.WebSocket(ws_url + "/shell");
160 this.ws_host + utils.url_join_encode(this.ws_url, "shell")
161 this.stdin_channel = new this.WebSocket(ws_url + "/stdin");
161 );
162 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
162 this.stdin_channel = new this.WebSocket(
163 this.ws_host + utils.url_join_encode(this.ws_url, "stdin")
164 );
165 this.iopub_channel = new this.WebSocket(
166 this.ws_host + utils.url_join_encode(this.ws_url, "iopub")
167 );
163
168
169 var ws_host_url = this.ws_host + this.ws_url;
164 var already_called_onclose = false; // only alert once
170 var already_called_onclose = false; // only alert once
165 var ws_closed_early = function(evt){
171 var ws_closed_early = function(evt){
166 if (already_called_onclose){
172 if (already_called_onclose){
167 return;
173 return;
168 }
174 }
169 already_called_onclose = true;
175 already_called_onclose = true;
170 if ( ! evt.wasClean ){
176 if ( ! evt.wasClean ){
171 that._websocket_closed(ws_url, true);
177 that._websocket_closed(ws_host_url, true);
172 }
178 }
173 };
179 };
174 var ws_closed_late = function(evt){
180 var ws_closed_late = function(evt){
175 if (already_called_onclose){
181 if (already_called_onclose){
176 return;
182 return;
177 }
183 }
178 already_called_onclose = true;
184 already_called_onclose = true;
179 if ( ! evt.wasClean ){
185 if ( ! evt.wasClean ){
180 that._websocket_closed(ws_url, false);
186 that._websocket_closed(ws_host_url, false);
181 }
187 }
182 };
188 };
183 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
189 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
184 for (var i=0; i < channels.length; i++) {
190 for (var i=0; i < channels.length; i++) {
185 channels[i].onopen = $.proxy(this._ws_opened, this);
191 channels[i].onopen = $.proxy(this._ws_opened, this);
186 channels[i].onclose = ws_closed_early;
192 channels[i].onclose = ws_closed_early;
187 }
193 }
188 // switch from early-close to late-close message after 1s
194 // switch from early-close to late-close message after 1s
189 setTimeout(function() {
195 setTimeout(function() {
190 for (var i=0; i < channels.length; i++) {
196 for (var i=0; i < channels.length; i++) {
191 if (channels[i] !== null) {
197 if (channels[i] !== null) {
192 channels[i].onclose = ws_closed_late;
198 channels[i].onclose = ws_closed_late;
193 }
199 }
194 }
200 }
195 }, 1000);
201 }, 1000);
196 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
202 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
197 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_message, this);
203 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_message, this);
198 this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
204 this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
199 };
205 };
200
206
201 /**
207 /**
202 * Handle a websocket entering the open state
208 * Handle a websocket entering the open state
203 * sends session and cookie authentication info as first message.
209 * sends session and cookie authentication info as first message.
204 * Once all sockets are open, signal the Kernel.status_started event.
210 * Once all sockets are open, signal the Kernel.status_started event.
205 * @method _ws_opened
211 * @method _ws_opened
206 */
212 */
207 Kernel.prototype._ws_opened = function (evt) {
213 Kernel.prototype._ws_opened = function (evt) {
208 // send the session id so the Session object Python-side
214 // send the session id so the Session object Python-side
209 // has the same identity
215 // has the same identity
210 evt.target.send(this.session_id + ':' + document.cookie);
216 evt.target.send(this.session_id + ':' + document.cookie);
211
217
212 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
218 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
213 for (var i=0; i < channels.length; i++) {
219 for (var i=0; i < channels.length; i++) {
214 // if any channel is not ready, don't trigger event.
220 // if any channel is not ready, don't trigger event.
215 if ( !channels[i].readyState ) return;
221 if ( !channels[i].readyState ) return;
216 }
222 }
217 // all events ready, trigger started event.
223 // all events ready, trigger started event.
218 $([IPython.events]).trigger('status_started.Kernel', {kernel: this});
224 $([IPython.events]).trigger('status_started.Kernel', {kernel: this});
219 };
225 };
220
226
221 /**
227 /**
222 * Stop the websocket channels.
228 * Stop the websocket channels.
223 * @method stop_channels
229 * @method stop_channels
224 */
230 */
225 Kernel.prototype.stop_channels = function () {
231 Kernel.prototype.stop_channels = function () {
226 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
232 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
227 for (var i=0; i < channels.length; i++) {
233 for (var i=0; i < channels.length; i++) {
228 if ( channels[i] !== null ) {
234 if ( channels[i] !== null ) {
229 channels[i].onclose = null;
235 channels[i].onclose = null;
230 channels[i].close();
236 channels[i].close();
231 }
237 }
232 }
238 }
233 this.shell_channel = this.iopub_channel = this.stdin_channel = null;
239 this.shell_channel = this.iopub_channel = this.stdin_channel = null;
234 };
240 };
235
241
236 // Main public methods.
242 // Main public methods.
237
243
238 // send a message on the Kernel's shell channel
244 // send a message on the Kernel's shell channel
239 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
245 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
240 var msg = this._get_msg(msg_type, content, metadata);
246 var msg = this._get_msg(msg_type, content, metadata);
241 this.shell_channel.send(JSON.stringify(msg));
247 this.shell_channel.send(JSON.stringify(msg));
242 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
248 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
243 return msg.header.msg_id;
249 return msg.header.msg_id;
244 };
250 };
245
251
246 /**
252 /**
247 * Get kernel info
253 * Get kernel info
248 *
254 *
249 * @param callback {function}
255 * @param callback {function}
250 * @method object_info
256 * @method object_info
251 *
257 *
252 * When calling this method, pass a callback function that expects one argument.
258 * When calling this method, pass a callback function that expects one argument.
253 * The callback will be passed the complete `kernel_info_reply` message documented
259 * The callback will be passed the complete `kernel_info_reply` message documented
254 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info)
260 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info)
255 */
261 */
256 Kernel.prototype.kernel_info = function (callback) {
262 Kernel.prototype.kernel_info = function (callback) {
257 var callbacks;
263 var callbacks;
258 if (callback) {
264 if (callback) {
259 callbacks = { shell : { reply : callback } };
265 callbacks = { shell : { reply : callback } };
260 }
266 }
261 return this.send_shell_message("kernel_info_request", {}, callbacks);
267 return this.send_shell_message("kernel_info_request", {}, callbacks);
262 };
268 };
263
269
264 /**
270 /**
265 * Get info on an object
271 * Get info on an object
266 *
272 *
267 * @param objname {string}
273 * @param objname {string}
268 * @param callback {function}
274 * @param callback {function}
269 * @method object_info
275 * @method object_info
270 *
276 *
271 * When calling this method, pass a callback function that expects one argument.
277 * When calling this method, pass a callback function that expects one argument.
272 * The callback will be passed the complete `object_info_reply` message documented
278 * The callback will be passed the complete `object_info_reply` message documented
273 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
279 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
274 */
280 */
275 Kernel.prototype.object_info = function (objname, callback) {
281 Kernel.prototype.object_info = function (objname, callback) {
276 var callbacks;
282 var callbacks;
277 if (callback) {
283 if (callback) {
278 callbacks = { shell : { reply : callback } };
284 callbacks = { shell : { reply : callback } };
279 }
285 }
280
286
281 if (typeof(objname) !== null && objname !== null) {
287 if (typeof(objname) !== null && objname !== null) {
282 var content = {
288 var content = {
283 oname : objname.toString(),
289 oname : objname.toString(),
284 detail_level : 0,
290 detail_level : 0,
285 };
291 };
286 return this.send_shell_message("object_info_request", content, callbacks);
292 return this.send_shell_message("object_info_request", content, callbacks);
287 }
293 }
288 return;
294 return;
289 };
295 };
290
296
291 /**
297 /**
292 * Execute given code into kernel, and pass result to callback.
298 * Execute given code into kernel, and pass result to callback.
293 *
299 *
294 * @async
300 * @async
295 * @method execute
301 * @method execute
296 * @param {string} code
302 * @param {string} code
297 * @param [callbacks] {Object} With the following keys (all optional)
303 * @param [callbacks] {Object} With the following keys (all optional)
298 * @param callbacks.shell.reply {function}
304 * @param callbacks.shell.reply {function}
299 * @param callbacks.shell.payload.[payload_name] {function}
305 * @param callbacks.shell.payload.[payload_name] {function}
300 * @param callbacks.iopub.output {function}
306 * @param callbacks.iopub.output {function}
301 * @param callbacks.iopub.clear_output {function}
307 * @param callbacks.iopub.clear_output {function}
302 * @param callbacks.input {function}
308 * @param callbacks.input {function}
303 * @param {object} [options]
309 * @param {object} [options]
304 * @param [options.silent=false] {Boolean}
310 * @param [options.silent=false] {Boolean}
305 * @param [options.user_expressions=empty_dict] {Dict}
311 * @param [options.user_expressions=empty_dict] {Dict}
306 * @param [options.user_variables=empty_list] {List od Strings}
312 * @param [options.user_variables=empty_list] {List od Strings}
307 * @param [options.allow_stdin=false] {Boolean} true|false
313 * @param [options.allow_stdin=false] {Boolean} true|false
308 *
314 *
309 * @example
315 * @example
310 *
316 *
311 * The options object should contain the options for the execute call. Its default
317 * The options object should contain the options for the execute call. Its default
312 * values are:
318 * values are:
313 *
319 *
314 * options = {
320 * options = {
315 * silent : true,
321 * silent : true,
316 * user_variables : [],
322 * user_variables : [],
317 * user_expressions : {},
323 * user_expressions : {},
318 * allow_stdin : false
324 * allow_stdin : false
319 * }
325 * }
320 *
326 *
321 * When calling this method pass a callbacks structure of the form:
327 * When calling this method pass a callbacks structure of the form:
322 *
328 *
323 * callbacks = {
329 * callbacks = {
324 * shell : {
330 * shell : {
325 * reply : execute_reply_callback,
331 * reply : execute_reply_callback,
326 * payload : {
332 * payload : {
327 * set_next_input : set_next_input_callback,
333 * set_next_input : set_next_input_callback,
328 * }
334 * }
329 * },
335 * },
330 * iopub : {
336 * iopub : {
331 * output : output_callback,
337 * output : output_callback,
332 * clear_output : clear_output_callback,
338 * clear_output : clear_output_callback,
333 * },
339 * },
334 * input : raw_input_callback
340 * input : raw_input_callback
335 * }
341 * }
336 *
342 *
337 * Each callback will be passed the entire message as a single arugment.
343 * Each callback will be passed the entire message as a single arugment.
338 * Payload handlers will be passed the corresponding payload and the execute_reply message.
344 * Payload handlers will be passed the corresponding payload and the execute_reply message.
339 */
345 */
340 Kernel.prototype.execute = function (code, callbacks, options) {
346 Kernel.prototype.execute = function (code, callbacks, options) {
341
347
342 var content = {
348 var content = {
343 code : code,
349 code : code,
344 silent : true,
350 silent : true,
345 store_history : false,
351 store_history : false,
346 user_variables : [],
352 user_variables : [],
347 user_expressions : {},
353 user_expressions : {},
348 allow_stdin : false
354 allow_stdin : false
349 };
355 };
350 callbacks = callbacks || {};
356 callbacks = callbacks || {};
351 if (callbacks.input !== undefined) {
357 if (callbacks.input !== undefined) {
352 content.allow_stdin = true;
358 content.allow_stdin = true;
353 }
359 }
354 $.extend(true, content, options);
360 $.extend(true, content, options);
355 $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
361 $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
356 return this.send_shell_message("execute_request", content, callbacks);
362 return this.send_shell_message("execute_request", content, callbacks);
357 };
363 };
358
364
359 /**
365 /**
360 * When calling this method, pass a function to be called with the `complete_reply` message
366 * When calling this method, pass a function to be called with the `complete_reply` message
361 * as its only argument when it arrives.
367 * as its only argument when it arrives.
362 *
368 *
363 * `complete_reply` is documented
369 * `complete_reply` is documented
364 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
370 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
365 *
371 *
366 * @method complete
372 * @method complete
367 * @param line {integer}
373 * @param line {integer}
368 * @param cursor_pos {integer}
374 * @param cursor_pos {integer}
369 * @param callback {function}
375 * @param callback {function}
370 *
376 *
371 */
377 */
372 Kernel.prototype.complete = function (line, cursor_pos, callback) {
378 Kernel.prototype.complete = function (line, cursor_pos, callback) {
373 var callbacks;
379 var callbacks;
374 if (callback) {
380 if (callback) {
375 callbacks = { shell : { reply : callback } };
381 callbacks = { shell : { reply : callback } };
376 }
382 }
377 var content = {
383 var content = {
378 text : '',
384 text : '',
379 line : line,
385 line : line,
380 block : null,
386 block : null,
381 cursor_pos : cursor_pos
387 cursor_pos : cursor_pos
382 };
388 };
383 return this.send_shell_message("complete_request", content, callbacks);
389 return this.send_shell_message("complete_request", content, callbacks);
384 };
390 };
385
391
386
392
387 Kernel.prototype.interrupt = function () {
393 Kernel.prototype.interrupt = function () {
388 if (this.running) {
394 if (this.running) {
389 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
395 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
390 $.post(this.kernel_url + "/interrupt");
396 $.post(utils.url_join_encode(this.kernel_url, "interrupt"));
391 }
397 }
392 };
398 };
393
399
394
400
395 Kernel.prototype.kill = function () {
401 Kernel.prototype.kill = function () {
396 if (this.running) {
402 if (this.running) {
397 this.running = false;
403 this.running = false;
398 var settings = {
404 var settings = {
399 cache : false,
405 cache : false,
400 type : "DELETE"
406 type : "DELETE"
401 };
407 };
402 $.ajax(this.kernel_url, settings);
408 $.ajax(utils.url_join_encode(this.kernel_url), settings);
403 }
409 }
404 };
410 };
405
411
406 Kernel.prototype.send_input_reply = function (input) {
412 Kernel.prototype.send_input_reply = function (input) {
407 var content = {
413 var content = {
408 value : input,
414 value : input,
409 };
415 };
410 $([IPython.events]).trigger('input_reply.Kernel', {kernel: this, content:content});
416 $([IPython.events]).trigger('input_reply.Kernel', {kernel: this, content:content});
411 var msg = this._get_msg("input_reply", content);
417 var msg = this._get_msg("input_reply", content);
412 this.stdin_channel.send(JSON.stringify(msg));
418 this.stdin_channel.send(JSON.stringify(msg));
413 return msg.header.msg_id;
419 return msg.header.msg_id;
414 };
420 };
415
421
416
422
417 // Reply handlers
423 // Reply handlers
418
424
419 Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
425 Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
420 this._iopub_handlers[msg_type] = callback;
426 this._iopub_handlers[msg_type] = callback;
421 };
427 };
422
428
423 Kernel.prototype.get_iopub_handler = function (msg_type) {
429 Kernel.prototype.get_iopub_handler = function (msg_type) {
424 // get iopub handler for a specific message type
430 // get iopub handler for a specific message type
425 return this._iopub_handlers[msg_type];
431 return this._iopub_handlers[msg_type];
426 };
432 };
427
433
428
434
429 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
435 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
430 // get callbacks for a specific message
436 // get callbacks for a specific message
431 return this._msg_callbacks[msg_id];
437 return this._msg_callbacks[msg_id];
432 };
438 };
433
439
434
440
435 Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
441 Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
436 if (this._msg_callbacks[msg_id] !== undefined ) {
442 if (this._msg_callbacks[msg_id] !== undefined ) {
437 delete this._msg_callbacks[msg_id];
443 delete this._msg_callbacks[msg_id];
438 }
444 }
439 };
445 };
440
446
441 /* Set callbacks for a particular message.
447 /* Set callbacks for a particular message.
442 * Callbacks should be a struct of the following form:
448 * Callbacks should be a struct of the following form:
443 * shell : {
449 * shell : {
444 *
450 *
445 * }
451 * }
446
452
447 */
453 */
448 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
454 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
449 if (callbacks) {
455 if (callbacks) {
450 // shallow-copy mapping, because we will modify it at the top level
456 // shallow-copy mapping, because we will modify it at the top level
451 var cbcopy = this._msg_callbacks[msg_id] = {};
457 var cbcopy = this._msg_callbacks[msg_id] = {};
452 cbcopy.shell = callbacks.shell;
458 cbcopy.shell = callbacks.shell;
453 cbcopy.iopub = callbacks.iopub;
459 cbcopy.iopub = callbacks.iopub;
454 cbcopy.input = callbacks.input;
460 cbcopy.input = callbacks.input;
455 this._msg_callbacks[msg_id] = cbcopy;
461 this._msg_callbacks[msg_id] = cbcopy;
456 }
462 }
457 };
463 };
458
464
459
465
460 Kernel.prototype._handle_shell_reply = function (e) {
466 Kernel.prototype._handle_shell_reply = function (e) {
461 var reply = $.parseJSON(e.data);
467 var reply = $.parseJSON(e.data);
462 $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
468 $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
463 var content = reply.content;
469 var content = reply.content;
464 var metadata = reply.metadata;
470 var metadata = reply.metadata;
465 var parent_id = reply.parent_header.msg_id;
471 var parent_id = reply.parent_header.msg_id;
466 var callbacks = this.get_callbacks_for_msg(parent_id);
472 var callbacks = this.get_callbacks_for_msg(parent_id);
467 if (!callbacks || !callbacks.shell) {
473 if (!callbacks || !callbacks.shell) {
468 return;
474 return;
469 }
475 }
470 var shell_callbacks = callbacks.shell;
476 var shell_callbacks = callbacks.shell;
471
477
472 // clear callbacks on shell
478 // clear callbacks on shell
473 delete callbacks.shell;
479 delete callbacks.shell;
474 delete callbacks.input;
480 delete callbacks.input;
475 if (!callbacks.iopub) {
481 if (!callbacks.iopub) {
476 this.clear_callbacks_for_msg(parent_id);
482 this.clear_callbacks_for_msg(parent_id);
477 }
483 }
478
484
479 if (shell_callbacks.reply !== undefined) {
485 if (shell_callbacks.reply !== undefined) {
480 shell_callbacks.reply(reply);
486 shell_callbacks.reply(reply);
481 }
487 }
482 if (content.payload && shell_callbacks.payload) {
488 if (content.payload && shell_callbacks.payload) {
483 this._handle_payloads(content.payload, shell_callbacks.payload, reply);
489 this._handle_payloads(content.payload, shell_callbacks.payload, reply);
484 }
490 }
485 };
491 };
486
492
487
493
488 Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
494 Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
489 var l = payloads.length;
495 var l = payloads.length;
490 // Payloads are handled by triggering events because we don't want the Kernel
496 // Payloads are handled by triggering events because we don't want the Kernel
491 // to depend on the Notebook or Pager classes.
497 // to depend on the Notebook or Pager classes.
492 for (var i=0; i<l; i++) {
498 for (var i=0; i<l; i++) {
493 var payload = payloads[i];
499 var payload = payloads[i];
494 var callback = payload_callbacks[payload.source];
500 var callback = payload_callbacks[payload.source];
495 if (callback) {
501 if (callback) {
496 callback(payload, msg);
502 callback(payload, msg);
497 }
503 }
498 }
504 }
499 };
505 };
500
506
501 Kernel.prototype._handle_status_message = function (msg) {
507 Kernel.prototype._handle_status_message = function (msg) {
502 var execution_state = msg.content.execution_state;
508 var execution_state = msg.content.execution_state;
503 var parent_id = msg.parent_header.msg_id;
509 var parent_id = msg.parent_header.msg_id;
504
510
505 // dispatch status msg callbacks, if any
511 // dispatch status msg callbacks, if any
506 var callbacks = this.get_callbacks_for_msg(parent_id);
512 var callbacks = this.get_callbacks_for_msg(parent_id);
507 if (callbacks && callbacks.iopub && callbacks.iopub.status) {
513 if (callbacks && callbacks.iopub && callbacks.iopub.status) {
508 try {
514 try {
509 callbacks.iopub.status(msg);
515 callbacks.iopub.status(msg);
510 } catch (e) {
516 } catch (e) {
511 console.log("Exception in status msg handler", e, e.stack);
517 console.log("Exception in status msg handler", e, e.stack);
512 }
518 }
513 }
519 }
514
520
515 if (execution_state === 'busy') {
521 if (execution_state === 'busy') {
516 $([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
522 $([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
517 } else if (execution_state === 'idle') {
523 } else if (execution_state === 'idle') {
518 // clear callbacks on idle, there can be no more
524 // clear callbacks on idle, there can be no more
519 if (callbacks !== undefined) {
525 if (callbacks !== undefined) {
520 delete callbacks.iopub;
526 delete callbacks.iopub;
521 delete callbacks.input;
527 delete callbacks.input;
522 if (!callbacks.shell) {
528 if (!callbacks.shell) {
523 this.clear_callbacks_for_msg(parent_id);
529 this.clear_callbacks_for_msg(parent_id);
524 }
530 }
525 }
531 }
526 // trigger status_idle event
532 // trigger status_idle event
527 $([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
533 $([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
528 } else if (execution_state === 'restarting') {
534 } else if (execution_state === 'restarting') {
529 // autorestarting is distinct from restarting,
535 // autorestarting is distinct from restarting,
530 // in that it means the kernel died and the server is restarting it.
536 // in that it means the kernel died and the server is restarting it.
531 // status_restarting sets the notification widget,
537 // status_restarting sets the notification widget,
532 // autorestart shows the more prominent dialog.
538 // autorestart shows the more prominent dialog.
533 $([IPython.events]).trigger('status_autorestarting.Kernel', {kernel: this});
539 $([IPython.events]).trigger('status_autorestarting.Kernel', {kernel: this});
534 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
540 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
535 } else if (execution_state === 'dead') {
541 } else if (execution_state === 'dead') {
536 this.stop_channels();
542 this.stop_channels();
537 $([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
543 $([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
538 }
544 }
539 };
545 };
540
546
541
547
542 // handle clear_output message
548 // handle clear_output message
543 Kernel.prototype._handle_clear_output = function (msg) {
549 Kernel.prototype._handle_clear_output = function (msg) {
544 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
550 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
545 if (!callbacks || !callbacks.iopub) {
551 if (!callbacks || !callbacks.iopub) {
546 return;
552 return;
547 }
553 }
548 var callback = callbacks.iopub.clear_output;
554 var callback = callbacks.iopub.clear_output;
549 if (callback) {
555 if (callback) {
550 callback(msg);
556 callback(msg);
551 }
557 }
552 };
558 };
553
559
554
560
555 // handle an output message (pyout, display_data, etc.)
561 // handle an output message (pyout, display_data, etc.)
556 Kernel.prototype._handle_output_message = function (msg) {
562 Kernel.prototype._handle_output_message = function (msg) {
557 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
563 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
558 if (!callbacks || !callbacks.iopub) {
564 if (!callbacks || !callbacks.iopub) {
559 return;
565 return;
560 }
566 }
561 var callback = callbacks.iopub.output;
567 var callback = callbacks.iopub.output;
562 if (callback) {
568 if (callback) {
563 callback(msg);
569 callback(msg);
564 }
570 }
565 };
571 };
566
572
567 // dispatch IOPub messages to respective handlers.
573 // dispatch IOPub messages to respective handlers.
568 // each message type should have a handler.
574 // each message type should have a handler.
569 Kernel.prototype._handle_iopub_message = function (e) {
575 Kernel.prototype._handle_iopub_message = function (e) {
570 var msg = $.parseJSON(e.data);
576 var msg = $.parseJSON(e.data);
571
577
572 var handler = this.get_iopub_handler(msg.header.msg_type);
578 var handler = this.get_iopub_handler(msg.header.msg_type);
573 if (handler !== undefined) {
579 if (handler !== undefined) {
574 handler(msg);
580 handler(msg);
575 }
581 }
576 };
582 };
577
583
578
584
579 Kernel.prototype._handle_input_request = function (e) {
585 Kernel.prototype._handle_input_request = function (e) {
580 var request = $.parseJSON(e.data);
586 var request = $.parseJSON(e.data);
581 var header = request.header;
587 var header = request.header;
582 var content = request.content;
588 var content = request.content;
583 var metadata = request.metadata;
589 var metadata = request.metadata;
584 var msg_type = header.msg_type;
590 var msg_type = header.msg_type;
585 if (msg_type !== 'input_request') {
591 if (msg_type !== 'input_request') {
586 console.log("Invalid input request!", request);
592 console.log("Invalid input request!", request);
587 return;
593 return;
588 }
594 }
589 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
595 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
590 if (callbacks) {
596 if (callbacks) {
591 if (callbacks.input) {
597 if (callbacks.input) {
592 callbacks.input(request);
598 callbacks.input(request);
593 }
599 }
594 }
600 }
595 };
601 };
596
602
597
603
598 IPython.Kernel = Kernel;
604 IPython.Kernel = Kernel;
599
605
600 return IPython;
606 return IPython;
601
607
602 }(IPython));
608 }(IPython));
603
609
@@ -1,118 +1,119 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Notebook
9 // Notebook
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 var Session = function(notebook_name, notebook_path, notebook){
17 var Session = function(notebook, options){
18 this.kernel = null;
18 this.kernel = null;
19 this.id = null;
19 this.id = null;
20 this.name = notebook_name;
21 this.path = notebook_path;
22 this.notebook = notebook;
20 this.notebook = notebook;
23 this._baseProjectUrl = notebook.baseProjectUrl();
21 this.name = notebook.notebook_name;
22 this.path = notebook.notebook_path;
23 this.base_url = notebook.base_url;
24 this.base_kernel_url = options.base_kernel_url || utils.get_body_data("baseKernelUrl");
24 };
25 };
25
26
26 Session.prototype.start = function(callback) {
27 Session.prototype.start = function(callback) {
27 var that = this;
28 var that = this;
28 var model = {
29 var model = {
29 notebook : {
30 notebook : {
30 name : this.name,
31 name : this.name,
31 path : this.path
32 path : this.path
32 }
33 }
33 };
34 };
34 var settings = {
35 var settings = {
35 processData : false,
36 processData : false,
36 cache : false,
37 cache : false,
37 type : "POST",
38 type : "POST",
38 data: JSON.stringify(model),
39 data: JSON.stringify(model),
39 dataType : "json",
40 dataType : "json",
40 success : function (data, status, xhr) {
41 success : function (data, status, xhr) {
41 that._handle_start_success(data);
42 that._handle_start_success(data);
42 if (callback) {
43 if (callback) {
43 callback(data, status, xhr);
44 callback(data, status, xhr);
44 }
45 }
45 },
46 },
46 };
47 };
47 var url = utils.url_join_encode(this._baseProjectUrl, 'api/sessions');
48 var url = utils.url_join_encode(this.base_url, 'api/sessions');
48 $.ajax(url, settings);
49 $.ajax(url, settings);
49 };
50 };
50
51
51 Session.prototype.rename_notebook = function (name, path) {
52 Session.prototype.rename_notebook = function (name, path) {
52 this.name = name;
53 this.name = name;
53 this.path = path;
54 this.path = path;
54 var model = {
55 var model = {
55 notebook : {
56 notebook : {
56 name : this.name,
57 name : this.name,
57 path : this.path
58 path : this.path
58 }
59 }
59 };
60 };
60 var settings = {
61 var settings = {
61 processData : false,
62 processData : false,
62 cache : false,
63 cache : false,
63 type : "PATCH",
64 type : "PATCH",
64 data: JSON.stringify(model),
65 data: JSON.stringify(model),
65 dataType : "json",
66 dataType : "json",
66 };
67 };
67 var url = utils.url_join_encode(this._baseProjectUrl, 'api/sessions', this.id);
68 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
68 $.ajax(url, settings);
69 $.ajax(url, settings);
69 };
70 };
70
71
71 Session.prototype.delete = function() {
72 Session.prototype.delete = function() {
72 var settings = {
73 var settings = {
73 processData : false,
74 processData : false,
74 cache : false,
75 cache : false,
75 type : "DELETE",
76 type : "DELETE",
76 dataType : "json",
77 dataType : "json",
77 };
78 };
78 this.kernel.running = false;
79 this.kernel.running = false;
79 var url = utils.url_join_encode(this._baseProjectUrl, 'api/sessions', this.id);
80 var url = utils.url_join_encode(this.base_url, 'api/sessions', this.id);
80 $.ajax(url, settings);
81 $.ajax(url, settings);
81 };
82 };
82
83
83 // Kernel related things
84 // Kernel related things
84 /**
85 /**
85 * Create the Kernel object associated with this Session.
86 * Create the Kernel object associated with this Session.
86 *
87 *
87 * @method _handle_start_success
88 * @method _handle_start_success
88 */
89 */
89 Session.prototype._handle_start_success = function (data, status, xhr) {
90 Session.prototype._handle_start_success = function (data, status, xhr) {
90 this.id = data.id;
91 this.id = data.id;
91 var base_url = utils.url_path_join($('body').data('baseKernelUrl'), "api/kernels");
92 var kernel_service_url = utils.url_path_join(this.base_kernel_url, "api/kernels");
92 this.kernel = new IPython.Kernel(base_url);
93 this.kernel = new IPython.Kernel(kernel_service_url);
93 this.kernel._kernel_started(data.kernel);
94 this.kernel._kernel_started(data.kernel);
94 };
95 };
95
96
96 /**
97 /**
97 * Prompt the user to restart the IPython kernel.
98 * Prompt the user to restart the IPython kernel.
98 *
99 *
99 * @method restart_kernel
100 * @method restart_kernel
100 */
101 */
101 Session.prototype.restart_kernel = function () {
102 Session.prototype.restart_kernel = function () {
102 this.kernel.restart();
103 this.kernel.restart();
103 };
104 };
104
105
105 Session.prototype.interrupt_kernel = function() {
106 Session.prototype.interrupt_kernel = function() {
106 this.kernel.interrupt();
107 this.kernel.interrupt();
107 };
108 };
108
109
109
110
110 Session.prototype.kill_kernel = function() {
111 Session.prototype.kill_kernel = function() {
111 this.kernel.kill();
112 this.kernel.kill();
112 };
113 };
113
114
114 IPython.Session = Session;
115 IPython.Session = Session;
115
116
116 return IPython;
117 return IPython;
117
118
118 }(IPython));
119 }(IPython));
@@ -1,1526 +1,1527 b''
1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
1 article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}
2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
2 audio,canvas,video{display:inline-block;*display:inline;*zoom:1}
3 audio:not([controls]){display:none}
3 audio:not([controls]){display:none}
4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
4 html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}
5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
5 a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
6 a:hover,a:active{outline:0}
6 a:hover,a:active{outline:0}
7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}
7 sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}
8 sup{top:-0.5em}
8 sup{top:-0.5em}
9 sub{bottom:-0.25em}
9 sub{bottom:-0.25em}
10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}
10 img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}
11 #map_canvas img,.google-maps img{max-width:none}
11 #map_canvas img,.google-maps img{max-width:none}
12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}
12 button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}
13 button,input{*overflow:visible;line-height:normal}
13 button,input{*overflow:visible;line-height:normal}
14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
14 button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}
15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
15 button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}
16 label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}
17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}
17 input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}
18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
18 input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}
19 textarea{overflow:auto;vertical-align:top}
19 textarea{overflow:auto;vertical-align:top}
20 @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""} pre,blockquote{border:1px solid #999;page-break-inside:avoid} thead{display:table-header-group} tr,img{page-break-inside:avoid} img{max-width:100% !important} @page {margin:.5cm}p,h2,h3{orphans:3;widows:3} h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000;background-color:#fff}
20 @media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""} pre,blockquote{border:1px solid #999;page-break-inside:avoid} thead{display:table-header-group} tr,img{page-break-inside:avoid} img{max-width:100% !important} @page {margin:.5cm}p,h2,h3{orphans:3;widows:3} h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:20px;color:#000;background-color:#fff}
21 a{color:#08c;text-decoration:none}
21 a{color:#08c;text-decoration:none}
22 a:hover,a:focus{color:#005580;text-decoration:underline}
22 a:hover,a:focus{color:#005580;text-decoration:underline}
23 .img-rounded{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
23 .img-rounded{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
24 .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}
24 .img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}
25 .img-circle{border-radius:500px;-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}
25 .img-circle{border-radius:500px;-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}
26 .row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0}
26 .row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0}
27 .row:after{clear:both}
27 .row:after{clear:both}
28 [class*="span"]{float:left;min-height:1px;margin-left:20px}
28 [class*="span"]{float:left;min-height:1px;margin-left:20px}
29 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
29 .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
30 .span12{width:940px}
30 .span12{width:940px}
31 .span11{width:860px}
31 .span11{width:860px}
32 .span10{width:780px}
32 .span10{width:780px}
33 .span9{width:700px}
33 .span9{width:700px}
34 .span8{width:620px}
34 .span8{width:620px}
35 .span7{width:540px}
35 .span7{width:540px}
36 .span6{width:460px}
36 .span6{width:460px}
37 .span5{width:380px}
37 .span5{width:380px}
38 .span4{width:300px}
38 .span4{width:300px}
39 .span3{width:220px}
39 .span3{width:220px}
40 .span2{width:140px}
40 .span2{width:140px}
41 .span1{width:60px}
41 .span1{width:60px}
42 .offset12{margin-left:980px}
42 .offset12{margin-left:980px}
43 .offset11{margin-left:900px}
43 .offset11{margin-left:900px}
44 .offset10{margin-left:820px}
44 .offset10{margin-left:820px}
45 .offset9{margin-left:740px}
45 .offset9{margin-left:740px}
46 .offset8{margin-left:660px}
46 .offset8{margin-left:660px}
47 .offset7{margin-left:580px}
47 .offset7{margin-left:580px}
48 .offset6{margin-left:500px}
48 .offset6{margin-left:500px}
49 .offset5{margin-left:420px}
49 .offset5{margin-left:420px}
50 .offset4{margin-left:340px}
50 .offset4{margin-left:340px}
51 .offset3{margin-left:260px}
51 .offset3{margin-left:260px}
52 .offset2{margin-left:180px}
52 .offset2{margin-left:180px}
53 .offset1{margin-left:100px}
53 .offset1{margin-left:100px}
54 .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0}
54 .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0}
55 .row-fluid:after{clear:both}
55 .row-fluid:after{clear:both}
56 .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%}
56 .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%}
57 .row-fluid [class*="span"]:first-child{margin-left:0}
57 .row-fluid [class*="span"]:first-child{margin-left:0}
58 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}
58 .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}
59 .row-fluid .span12{width:100%;*width:99.94680851063829%}
59 .row-fluid .span12{width:100%;*width:99.94680851063829%}
60 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}
60 .row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}
61 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}
61 .row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}
62 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}
62 .row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}
63 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}
63 .row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}
64 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}
64 .row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}
65 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}
65 .row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}
66 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}
66 .row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}
67 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}
67 .row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}
68 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}
68 .row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}
69 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}
69 .row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}
70 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}
70 .row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}
71 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}
71 .row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}
72 .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}
72 .row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}
73 .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}
73 .row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}
74 .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}
74 .row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}
75 .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}
75 .row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}
76 .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}
76 .row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}
77 .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}
77 .row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}
78 .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}
78 .row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}
79 .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}
79 .row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}
80 .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}
80 .row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}
81 .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}
81 .row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}
82 .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}
82 .row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}
83 .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}
83 .row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}
84 .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}
84 .row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}
85 .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}
85 .row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}
86 .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}
86 .row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}
87 .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}
87 .row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}
88 .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}
88 .row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}
89 .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}
89 .row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}
90 .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}
90 .row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}
91 .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}
91 .row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}
92 .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}
92 .row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}
93 .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}
93 .row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}
94 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}
94 .row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}
95 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none}
95 [class*="span"].hide,.row-fluid [class*="span"].hide{display:none}
96 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}
96 [class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}
97 .container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:"";line-height:0}
97 .container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:"";line-height:0}
98 .container:after{clear:both}
98 .container:after{clear:both}
99 .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0}
99 .container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0}
100 .container-fluid:after{clear:both}
100 .container-fluid:after{clear:both}
101 p{margin:0 0 10px}
101 p{margin:0 0 10px}
102 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px}
102 .lead{margin-bottom:20px;font-size:19.5px;font-weight:200;line-height:30px}
103 small{font-size:85%}
103 small{font-size:85%}
104 strong{font-weight:bold}
104 strong{font-weight:bold}
105 em{font-style:italic}
105 em{font-style:italic}
106 cite{font-style:normal}
106 cite{font-style:normal}
107 .muted{color:#999}
107 .muted{color:#999}
108 a.muted:hover,a.muted:focus{color:#808080}
108 a.muted:hover,a.muted:focus{color:#808080}
109 .text-warning{color:#c09853}
109 .text-warning{color:#c09853}
110 a.text-warning:hover,a.text-warning:focus{color:#a47e3c}
110 a.text-warning:hover,a.text-warning:focus{color:#a47e3c}
111 .text-error{color:#b94a48}
111 .text-error{color:#b94a48}
112 a.text-error:hover,a.text-error:focus{color:#953b39}
112 a.text-error:hover,a.text-error:focus{color:#953b39}
113 .text-info{color:#3a87ad}
113 .text-info{color:#3a87ad}
114 a.text-info:hover,a.text-info:focus{color:#2d6987}
114 a.text-info:hover,a.text-info:focus{color:#2d6987}
115 .text-success{color:#468847}
115 .text-success{color:#468847}
116 a.text-success:hover,a.text-success:focus{color:#356635}
116 a.text-success:hover,a.text-success:focus{color:#356635}
117 .text-left{text-align:left}
117 .text-left{text-align:left}
118 .text-right{text-align:right}
118 .text-right{text-align:right}
119 .text-center{text-align:center}
119 .text-center{text-align:center}
120 h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}
120 h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}
121 h1,h2,h3{line-height:40px}
121 h1,h2,h3{line-height:40px}
122 h1{font-size:35.75px}
122 h1{font-size:35.75px}
123 h2{font-size:29.25px}
123 h2{font-size:29.25px}
124 h3{font-size:22.75px}
124 h3{font-size:22.75px}
125 h4{font-size:16.25px}
125 h4{font-size:16.25px}
126 h5{font-size:13px}
126 h5{font-size:13px}
127 h6{font-size:11.049999999999999px}
127 h6{font-size:11.049999999999999px}
128 h1 small{font-size:22.75px}
128 h1 small{font-size:22.75px}
129 h2 small{font-size:16.25px}
129 h2 small{font-size:16.25px}
130 h3 small{font-size:13px}
130 h3 small{font-size:13px}
131 h4 small{font-size:13px}
131 h4 small{font-size:13px}
132 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}
132 .page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}
133 ul,ol{padding:0;margin:0 0 10px 25px}
133 ul,ol{padding:0;margin:0 0 10px 25px}
134 ul ul,ul ol,ol ol,ol ul{margin-bottom:0}
134 ul ul,ul ol,ol ol,ol ul{margin-bottom:0}
135 li{line-height:20px}
135 li{line-height:20px}
136 ul.unstyled,ol.unstyled{margin-left:0;list-style:none}
136 ul.unstyled,ol.unstyled{margin-left:0;list-style:none}
137 ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px}
137 ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px}
138 dl{margin-bottom:20px}
138 dl{margin-bottom:20px}
139 dt,dd{line-height:20px}
139 dt,dd{line-height:20px}
140 dt{font-weight:bold}
140 dt{font-weight:bold}
141 dd{margin-left:10px}
141 dd{margin-left:10px}
142 .dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0}
142 .dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0}
143 .dl-horizontal:after{clear:both}
143 .dl-horizontal:after{clear:both}
144 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
144 .dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
145 .dl-horizontal dd{margin-left:180px}
145 .dl-horizontal dd{margin-left:180px}
146 hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}
146 hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}
147 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}
147 abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}
148 abbr.initialism{font-size:90%;text-transform:uppercase}
148 abbr.initialism{font-size:90%;text-transform:uppercase}
149 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16.25px;font-weight:300;line-height:1.25}
149 blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16.25px;font-weight:300;line-height:1.25}
150 blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}
150 blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}
151 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}
151 blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}
152 blockquote.pull-right small:before{content:''}
152 blockquote.pull-right small:before{content:''}
153 blockquote.pull-right small:after{content:'\00A0 \2014'}
153 blockquote.pull-right small:after{content:'\00A0 \2014'}
154 q:before,q:after,blockquote:before,blockquote:after{content:""}
154 q:before,q:after,blockquote:before,blockquote:after{content:""}
155 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}
155 address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}
156 code,pre{padding:0 3px 2px;font-family:monospace;font-size:11px;color:#333;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
156 code,pre{padding:0 3px 2px;font-family:monospace;font-size:11px;color:#333;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
157 code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}
157 code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap}
158 pre{display:block;padding:9.5px;margin:0 0 10px;font-size:12px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}
158 pre{display:block;padding:9.5px;margin:0 0 10px;font-size:12px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}
159 pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}
159 pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}
160 .pre-scrollable{max-height:340px;overflow-y:scroll}
160 .pre-scrollable{max-height:340px;overflow-y:scroll}
161 form{margin:0 0 20px}
161 form{margin:0 0 20px}
162 fieldset{padding:0;margin:0;border:0}
162 fieldset{padding:0;margin:0;border:0}
163 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}
163 legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:19.5px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}
164 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px}
164 label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:20px}
165 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}
165 input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}
166 label{display:block;margin-bottom:5px}
166 label{display:block;margin-bottom:5px}
167 select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:13px;line-height:20px;color:#555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle}
167 select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:13px;line-height:20px;color:#555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle}
168 input,textarea,.uneditable-input{width:206px}
168 input,textarea,.uneditable-input{width:206px}
169 textarea{height:auto}
169 textarea{height:auto}
170 textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)}
170 textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6)}
171 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal}
171 input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal}
172 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}
172 input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}
173 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}
173 select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}
174 select{width:220px;border:1px solid #ccc;background-color:#fff}
174 select{width:220px;border:1px solid #ccc;background-color:#fff}
175 select[multiple],select[size]{height:auto}
175 select[multiple],select[size]{height:auto}
176 select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
176 select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
177 .uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);cursor:not-allowed}
177 .uneditable-input,.uneditable-textarea{color:#999;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);cursor:not-allowed}
178 .uneditable-input{overflow:hidden;white-space:nowrap}
178 .uneditable-input{overflow:hidden;white-space:nowrap}
179 .uneditable-textarea{width:auto;height:auto}
179 .uneditable-textarea{width:auto;height:auto}
180 input:-moz-placeholder,textarea:-moz-placeholder{color:#999}
180 input:-moz-placeholder,textarea:-moz-placeholder{color:#999}
181 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}
181 input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}
182 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}
182 input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}
183 .radio,.checkbox{min-height:20px;padding-left:20px}
183 .radio,.checkbox{min-height:20px;padding-left:20px}
184 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}
184 .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}
185 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}
185 .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}
186 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}
186 .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}
187 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}
187 .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}
188 .input-mini{width:60px}
188 .input-mini{width:60px}
189 .input-small{width:90px}
189 .input-small{width:90px}
190 .input-medium{width:150px}
190 .input-medium{width:150px}
191 .input-large{width:210px}
191 .input-large{width:210px}
192 .input-xlarge{width:270px}
192 .input-xlarge{width:270px}
193 .input-xxlarge{width:530px}
193 .input-xxlarge{width:530px}
194 input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}
194 input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}
195 .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}
195 .input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}
196 input,textarea,.uneditable-input{margin-left:0}
196 input,textarea,.uneditable-input{margin-left:0}
197 .controls-row [class*="span"]+[class*="span"]{margin-left:20px}
197 .controls-row [class*="span"]+[class*="span"]{margin-left:20px}
198 input.span12,textarea.span12,.uneditable-input.span12{width:926px}
198 input.span12,textarea.span12,.uneditable-input.span12{width:926px}
199 input.span11,textarea.span11,.uneditable-input.span11{width:846px}
199 input.span11,textarea.span11,.uneditable-input.span11{width:846px}
200 input.span10,textarea.span10,.uneditable-input.span10{width:766px}
200 input.span10,textarea.span10,.uneditable-input.span10{width:766px}
201 input.span9,textarea.span9,.uneditable-input.span9{width:686px}
201 input.span9,textarea.span9,.uneditable-input.span9{width:686px}
202 input.span8,textarea.span8,.uneditable-input.span8{width:606px}
202 input.span8,textarea.span8,.uneditable-input.span8{width:606px}
203 input.span7,textarea.span7,.uneditable-input.span7{width:526px}
203 input.span7,textarea.span7,.uneditable-input.span7{width:526px}
204 input.span6,textarea.span6,.uneditable-input.span6{width:446px}
204 input.span6,textarea.span6,.uneditable-input.span6{width:446px}
205 input.span5,textarea.span5,.uneditable-input.span5{width:366px}
205 input.span5,textarea.span5,.uneditable-input.span5{width:366px}
206 input.span4,textarea.span4,.uneditable-input.span4{width:286px}
206 input.span4,textarea.span4,.uneditable-input.span4{width:286px}
207 input.span3,textarea.span3,.uneditable-input.span3{width:206px}
207 input.span3,textarea.span3,.uneditable-input.span3{width:206px}
208 input.span2,textarea.span2,.uneditable-input.span2{width:126px}
208 input.span2,textarea.span2,.uneditable-input.span2{width:126px}
209 input.span1,textarea.span1,.uneditable-input.span1{width:46px}
209 input.span1,textarea.span1,.uneditable-input.span1{width:46px}
210 .controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0}
210 .controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0}
211 .controls-row:after{clear:both}
211 .controls-row:after{clear:both}
212 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}
212 .controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}
213 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}
213 .controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}
214 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}
214 input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}
215 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}
215 input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}
216 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}
216 .control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}
217 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}
217 .control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}
218 .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}
218 .control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}
219 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}
219 .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}
220 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}
220 .control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}
221 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}
221 .control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}
222 .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}
222 .control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}
223 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}
223 .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}
224 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}
224 .control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}
225 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}
225 .control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}
226 .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}
226 .control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}
227 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}
227 .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}
228 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}
228 .control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}
229 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}
229 .control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}
230 .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}
230 .control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}
231 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}
231 .control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}
232 input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}
232 input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}
233 .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0}
233 .form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0}
234 .form-actions:after{clear:both}
234 .form-actions:after{clear:both}
235 .help-block,.help-inline{color:#262626}
235 .help-block,.help-inline{color:#262626}
236 .help-block{display:block;margin-bottom:10px}
236 .help-block{display:block;margin-bottom:10px}
237 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px}
237 .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px}
238 .input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:13px}
238 .input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:13px}
239 .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}
239 .input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}
240 .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:13px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}
240 .input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:13px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}
241 .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
241 .input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
242 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}
242 .input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}
243 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px}
243 .input-prepend .add-on,.input-prepend .btn{margin-right:-1px}
244 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
244 .input-prepend .add-on:first-child,.input-prepend .btn:first-child{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
245 .input-append input,.input-append select,.input-append .uneditable-input{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
245 .input-append input,.input-append select,.input-append .uneditable-input{border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
246 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}
246 .input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}
247 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
247 .input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
248 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
248 .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
249 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
249 .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
250 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
250 .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
251 .input-prepend.input-append .btn-group:first-child{margin-left:0}
251 .input-prepend.input-append .btn-group:first-child{margin-left:0}
252 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
252 input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
253 .form-search .input-append .search-query,.form-search .input-prepend .search-query{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
253 .form-search .input-append .search-query,.form-search .input-prepend .search-query{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
254 .form-search .input-append .search-query{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
254 .form-search .input-append .search-query{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
255 .form-search .input-append .btn{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
255 .form-search .input-append .btn{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
256 .form-search .input-prepend .search-query{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
256 .form-search .input-prepend .search-query{border-radius:0 14px 14px 0;-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}
257 .form-search .input-prepend .btn{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
257 .form-search .input-prepend .btn{border-radius:14px 0 0 14px;-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}
258 .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle}
258 .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle}
259 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}
259 .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}
260 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}
260 .form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}
261 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}
261 .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}
262 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}
262 .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}
263 .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}
263 .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}
264 .control-group{margin-bottom:10px}
264 .control-group{margin-bottom:10px}
265 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}
265 legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}
266 .form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0}
266 .form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0}
267 .form-horizontal .control-group:after{clear:both}
267 .form-horizontal .control-group:after{clear:both}
268 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}
268 .form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}
269 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}
269 .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}
270 .form-horizontal .help-block{margin-bottom:0}
270 .form-horizontal .help-block{margin-bottom:0}
271 .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}
271 .form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}
272 .form-horizontal .form-actions{padding-left:180px}
272 .form-horizontal .form-actions{padding-left:180px}
273 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}
273 table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}
274 .table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}
274 .table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}
275 .table th{font-weight:bold}
275 .table th{font-weight:bold}
276 .table thead th{vertical-align:bottom}
276 .table thead th{vertical-align:bottom}
277 .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}
277 .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}
278 .table tbody+tbody{border-top:2px solid #ddd}
278 .table tbody+tbody{border-top:2px solid #ddd}
279 .table .table{background-color:#fff}
279 .table .table{background-color:#fff}
280 .table-condensed th,.table-condensed td{padding:4px 5px}
280 .table-condensed th,.table-condensed td{padding:4px 5px}
281 .table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}
281 .table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}
282 .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}
282 .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}
283 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
283 .table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
284 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
284 .table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
285 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
285 .table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
286 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
286 .table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
287 .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0}
287 .table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0}
288 .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0}
288 .table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0}
289 .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
289 .table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
290 .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
290 .table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px}
291 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
291 .table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}
292 .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}
292 .table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}
293 table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}
293 table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}
294 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0}
294 .table td.span1,.table th.span1{float:none;width:44px;margin-left:0}
295 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0}
295 .table td.span2,.table th.span2{float:none;width:124px;margin-left:0}
296 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0}
296 .table td.span3,.table th.span3{float:none;width:204px;margin-left:0}
297 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0}
297 .table td.span4,.table th.span4{float:none;width:284px;margin-left:0}
298 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0}
298 .table td.span5,.table th.span5{float:none;width:364px;margin-left:0}
299 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0}
299 .table td.span6,.table th.span6{float:none;width:444px;margin-left:0}
300 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0}
300 .table td.span7,.table th.span7{float:none;width:524px;margin-left:0}
301 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0}
301 .table td.span8,.table th.span8{float:none;width:604px;margin-left:0}
302 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0}
302 .table td.span9,.table th.span9{float:none;width:684px;margin-left:0}
303 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0}
303 .table td.span10,.table th.span10{float:none;width:764px;margin-left:0}
304 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0}
304 .table td.span11,.table th.span11{float:none;width:844px;margin-left:0}
305 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0}
305 .table td.span12,.table th.span12{float:none;width:924px;margin-left:0}
306 .table tbody tr.success>td{background-color:#dff0d8}
306 .table tbody tr.success>td{background-color:#dff0d8}
307 .table tbody tr.error>td{background-color:#f2dede}
307 .table tbody tr.error>td{background-color:#f2dede}
308 .table tbody tr.warning>td{background-color:#fcf8e3}
308 .table tbody tr.warning>td{background-color:#fcf8e3}
309 .table tbody tr.info>td{background-color:#d9edf7}
309 .table tbody tr.info>td{background-color:#d9edf7}
310 .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}
310 .table-hover tbody tr.success:hover>td{background-color:#d0e9c6}
311 .table-hover tbody tr.error:hover>td{background-color:#ebcccc}
311 .table-hover tbody tr.error:hover>td{background-color:#ebcccc}
312 .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}
312 .table-hover tbody tr.warning:hover>td{background-color:#faf2cc}
313 .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}
313 .table-hover tbody tr.info:hover>td{background-color:#c4e3f3}
314 [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px}
314 [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px}
315 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}
315 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}
316 .icon-glass{background-position:0 0}
316 .icon-glass{background-position:0 0}
317 .icon-music{background-position:-24px 0}
317 .icon-music{background-position:-24px 0}
318 .icon-search{background-position:-48px 0}
318 .icon-search{background-position:-48px 0}
319 .icon-envelope{background-position:-72px 0}
319 .icon-envelope{background-position:-72px 0}
320 .icon-heart{background-position:-96px 0}
320 .icon-heart{background-position:-96px 0}
321 .icon-star{background-position:-120px 0}
321 .icon-star{background-position:-120px 0}
322 .icon-star-empty{background-position:-144px 0}
322 .icon-star-empty{background-position:-144px 0}
323 .icon-user{background-position:-168px 0}
323 .icon-user{background-position:-168px 0}
324 .icon-film{background-position:-192px 0}
324 .icon-film{background-position:-192px 0}
325 .icon-th-large{background-position:-216px 0}
325 .icon-th-large{background-position:-216px 0}
326 .icon-th{background-position:-240px 0}
326 .icon-th{background-position:-240px 0}
327 .icon-th-list{background-position:-264px 0}
327 .icon-th-list{background-position:-264px 0}
328 .icon-ok{background-position:-288px 0}
328 .icon-ok{background-position:-288px 0}
329 .icon-remove{background-position:-312px 0}
329 .icon-remove{background-position:-312px 0}
330 .icon-zoom-in{background-position:-336px 0}
330 .icon-zoom-in{background-position:-336px 0}
331 .icon-zoom-out{background-position:-360px 0}
331 .icon-zoom-out{background-position:-360px 0}
332 .icon-off{background-position:-384px 0}
332 .icon-off{background-position:-384px 0}
333 .icon-signal{background-position:-408px 0}
333 .icon-signal{background-position:-408px 0}
334 .icon-cog{background-position:-432px 0}
334 .icon-cog{background-position:-432px 0}
335 .icon-trash{background-position:-456px 0}
335 .icon-trash{background-position:-456px 0}
336 .icon-home{background-position:0 -24px}
336 .icon-home{background-position:0 -24px}
337 .icon-file{background-position:-24px -24px}
337 .icon-file{background-position:-24px -24px}
338 .icon-time{background-position:-48px -24px}
338 .icon-time{background-position:-48px -24px}
339 .icon-road{background-position:-72px -24px}
339 .icon-road{background-position:-72px -24px}
340 .icon-download-alt{background-position:-96px -24px}
340 .icon-download-alt{background-position:-96px -24px}
341 .icon-download{background-position:-120px -24px}
341 .icon-download{background-position:-120px -24px}
342 .icon-upload{background-position:-144px -24px}
342 .icon-upload{background-position:-144px -24px}
343 .icon-inbox{background-position:-168px -24px}
343 .icon-inbox{background-position:-168px -24px}
344 .icon-play-circle{background-position:-192px -24px}
344 .icon-play-circle{background-position:-192px -24px}
345 .icon-repeat{background-position:-216px -24px}
345 .icon-repeat{background-position:-216px -24px}
346 .icon-refresh{background-position:-240px -24px}
346 .icon-refresh{background-position:-240px -24px}
347 .icon-list-alt{background-position:-264px -24px}
347 .icon-list-alt{background-position:-264px -24px}
348 .icon-lock{background-position:-287px -24px}
348 .icon-lock{background-position:-287px -24px}
349 .icon-flag{background-position:-312px -24px}
349 .icon-flag{background-position:-312px -24px}
350 .icon-headphones{background-position:-336px -24px}
350 .icon-headphones{background-position:-336px -24px}
351 .icon-volume-off{background-position:-360px -24px}
351 .icon-volume-off{background-position:-360px -24px}
352 .icon-volume-down{background-position:-384px -24px}
352 .icon-volume-down{background-position:-384px -24px}
353 .icon-volume-up{background-position:-408px -24px}
353 .icon-volume-up{background-position:-408px -24px}
354 .icon-qrcode{background-position:-432px -24px}
354 .icon-qrcode{background-position:-432px -24px}
355 .icon-barcode{background-position:-456px -24px}
355 .icon-barcode{background-position:-456px -24px}
356 .icon-tag{background-position:0 -48px}
356 .icon-tag{background-position:0 -48px}
357 .icon-tags{background-position:-25px -48px}
357 .icon-tags{background-position:-25px -48px}
358 .icon-book{background-position:-48px -48px}
358 .icon-book{background-position:-48px -48px}
359 .icon-bookmark{background-position:-72px -48px}
359 .icon-bookmark{background-position:-72px -48px}
360 .icon-print{background-position:-96px -48px}
360 .icon-print{background-position:-96px -48px}
361 .icon-camera{background-position:-120px -48px}
361 .icon-camera{background-position:-120px -48px}
362 .icon-font{background-position:-144px -48px}
362 .icon-font{background-position:-144px -48px}
363 .icon-bold{background-position:-167px -48px}
363 .icon-bold{background-position:-167px -48px}
364 .icon-italic{background-position:-192px -48px}
364 .icon-italic{background-position:-192px -48px}
365 .icon-text-height{background-position:-216px -48px}
365 .icon-text-height{background-position:-216px -48px}
366 .icon-text-width{background-position:-240px -48px}
366 .icon-text-width{background-position:-240px -48px}
367 .icon-align-left{background-position:-264px -48px}
367 .icon-align-left{background-position:-264px -48px}
368 .icon-align-center{background-position:-288px -48px}
368 .icon-align-center{background-position:-288px -48px}
369 .icon-align-right{background-position:-312px -48px}
369 .icon-align-right{background-position:-312px -48px}
370 .icon-align-justify{background-position:-336px -48px}
370 .icon-align-justify{background-position:-336px -48px}
371 .icon-list{background-position:-360px -48px}
371 .icon-list{background-position:-360px -48px}
372 .icon-indent-left{background-position:-384px -48px}
372 .icon-indent-left{background-position:-384px -48px}
373 .icon-indent-right{background-position:-408px -48px}
373 .icon-indent-right{background-position:-408px -48px}
374 .icon-facetime-video{background-position:-432px -48px}
374 .icon-facetime-video{background-position:-432px -48px}
375 .icon-picture{background-position:-456px -48px}
375 .icon-picture{background-position:-456px -48px}
376 .icon-pencil{background-position:0 -72px}
376 .icon-pencil{background-position:0 -72px}
377 .icon-map-marker{background-position:-24px -72px}
377 .icon-map-marker{background-position:-24px -72px}
378 .icon-adjust{background-position:-48px -72px}
378 .icon-adjust{background-position:-48px -72px}
379 .icon-tint{background-position:-72px -72px}
379 .icon-tint{background-position:-72px -72px}
380 .icon-edit{background-position:-96px -72px}
380 .icon-edit{background-position:-96px -72px}
381 .icon-share{background-position:-120px -72px}
381 .icon-share{background-position:-120px -72px}
382 .icon-check{background-position:-144px -72px}
382 .icon-check{background-position:-144px -72px}
383 .icon-move{background-position:-168px -72px}
383 .icon-move{background-position:-168px -72px}
384 .icon-step-backward{background-position:-192px -72px}
384 .icon-step-backward{background-position:-192px -72px}
385 .icon-fast-backward{background-position:-216px -72px}
385 .icon-fast-backward{background-position:-216px -72px}
386 .icon-backward{background-position:-240px -72px}
386 .icon-backward{background-position:-240px -72px}
387 .icon-play{background-position:-264px -72px}
387 .icon-play{background-position:-264px -72px}
388 .icon-pause{background-position:-288px -72px}
388 .icon-pause{background-position:-288px -72px}
389 .icon-stop{background-position:-312px -72px}
389 .icon-stop{background-position:-312px -72px}
390 .icon-forward{background-position:-336px -72px}
390 .icon-forward{background-position:-336px -72px}
391 .icon-fast-forward{background-position:-360px -72px}
391 .icon-fast-forward{background-position:-360px -72px}
392 .icon-step-forward{background-position:-384px -72px}
392 .icon-step-forward{background-position:-384px -72px}
393 .icon-eject{background-position:-408px -72px}
393 .icon-eject{background-position:-408px -72px}
394 .icon-chevron-left{background-position:-432px -72px}
394 .icon-chevron-left{background-position:-432px -72px}
395 .icon-chevron-right{background-position:-456px -72px}
395 .icon-chevron-right{background-position:-456px -72px}
396 .icon-plus-sign{background-position:0 -96px}
396 .icon-plus-sign{background-position:0 -96px}
397 .icon-minus-sign{background-position:-24px -96px}
397 .icon-minus-sign{background-position:-24px -96px}
398 .icon-remove-sign{background-position:-48px -96px}
398 .icon-remove-sign{background-position:-48px -96px}
399 .icon-ok-sign{background-position:-72px -96px}
399 .icon-ok-sign{background-position:-72px -96px}
400 .icon-question-sign{background-position:-96px -96px}
400 .icon-question-sign{background-position:-96px -96px}
401 .icon-info-sign{background-position:-120px -96px}
401 .icon-info-sign{background-position:-120px -96px}
402 .icon-screenshot{background-position:-144px -96px}
402 .icon-screenshot{background-position:-144px -96px}
403 .icon-remove-circle{background-position:-168px -96px}
403 .icon-remove-circle{background-position:-168px -96px}
404 .icon-ok-circle{background-position:-192px -96px}
404 .icon-ok-circle{background-position:-192px -96px}
405 .icon-ban-circle{background-position:-216px -96px}
405 .icon-ban-circle{background-position:-216px -96px}
406 .icon-arrow-left{background-position:-240px -96px}
406 .icon-arrow-left{background-position:-240px -96px}
407 .icon-arrow-right{background-position:-264px -96px}
407 .icon-arrow-right{background-position:-264px -96px}
408 .icon-arrow-up{background-position:-289px -96px}
408 .icon-arrow-up{background-position:-289px -96px}
409 .icon-arrow-down{background-position:-312px -96px}
409 .icon-arrow-down{background-position:-312px -96px}
410 .icon-share-alt{background-position:-336px -96px}
410 .icon-share-alt{background-position:-336px -96px}
411 .icon-resize-full{background-position:-360px -96px}
411 .icon-resize-full{background-position:-360px -96px}
412 .icon-resize-small{background-position:-384px -96px}
412 .icon-resize-small{background-position:-384px -96px}
413 .icon-plus{background-position:-408px -96px}
413 .icon-plus{background-position:-408px -96px}
414 .icon-minus{background-position:-433px -96px}
414 .icon-minus{background-position:-433px -96px}
415 .icon-asterisk{background-position:-456px -96px}
415 .icon-asterisk{background-position:-456px -96px}
416 .icon-exclamation-sign{background-position:0 -120px}
416 .icon-exclamation-sign{background-position:0 -120px}
417 .icon-gift{background-position:-24px -120px}
417 .icon-gift{background-position:-24px -120px}
418 .icon-leaf{background-position:-48px -120px}
418 .icon-leaf{background-position:-48px -120px}
419 .icon-fire{background-position:-72px -120px}
419 .icon-fire{background-position:-72px -120px}
420 .icon-eye-open{background-position:-96px -120px}
420 .icon-eye-open{background-position:-96px -120px}
421 .icon-eye-close{background-position:-120px -120px}
421 .icon-eye-close{background-position:-120px -120px}
422 .icon-warning-sign{background-position:-144px -120px}
422 .icon-warning-sign{background-position:-144px -120px}
423 .icon-plane{background-position:-168px -120px}
423 .icon-plane{background-position:-168px -120px}
424 .icon-calendar{background-position:-192px -120px}
424 .icon-calendar{background-position:-192px -120px}
425 .icon-random{background-position:-216px -120px;width:16px}
425 .icon-random{background-position:-216px -120px;width:16px}
426 .icon-comment{background-position:-240px -120px}
426 .icon-comment{background-position:-240px -120px}
427 .icon-magnet{background-position:-264px -120px}
427 .icon-magnet{background-position:-264px -120px}
428 .icon-chevron-up{background-position:-288px -120px}
428 .icon-chevron-up{background-position:-288px -120px}
429 .icon-chevron-down{background-position:-313px -119px}
429 .icon-chevron-down{background-position:-313px -119px}
430 .icon-retweet{background-position:-336px -120px}
430 .icon-retweet{background-position:-336px -120px}
431 .icon-shopping-cart{background-position:-360px -120px}
431 .icon-shopping-cart{background-position:-360px -120px}
432 .icon-folder-close{background-position:-384px -120px;width:16px}
432 .icon-folder-close{background-position:-384px -120px;width:16px}
433 .icon-folder-open{background-position:-408px -120px;width:16px}
433 .icon-folder-open{background-position:-408px -120px;width:16px}
434 .icon-resize-vertical{background-position:-432px -119px}
434 .icon-resize-vertical{background-position:-432px -119px}
435 .icon-resize-horizontal{background-position:-456px -118px}
435 .icon-resize-horizontal{background-position:-456px -118px}
436 .icon-hdd{background-position:0 -144px}
436 .icon-hdd{background-position:0 -144px}
437 .icon-bullhorn{background-position:-24px -144px}
437 .icon-bullhorn{background-position:-24px -144px}
438 .icon-bell{background-position:-48px -144px}
438 .icon-bell{background-position:-48px -144px}
439 .icon-certificate{background-position:-72px -144px}
439 .icon-certificate{background-position:-72px -144px}
440 .icon-thumbs-up{background-position:-96px -144px}
440 .icon-thumbs-up{background-position:-96px -144px}
441 .icon-thumbs-down{background-position:-120px -144px}
441 .icon-thumbs-down{background-position:-120px -144px}
442 .icon-hand-right{background-position:-144px -144px}
442 .icon-hand-right{background-position:-144px -144px}
443 .icon-hand-left{background-position:-168px -144px}
443 .icon-hand-left{background-position:-168px -144px}
444 .icon-hand-up{background-position:-192px -144px}
444 .icon-hand-up{background-position:-192px -144px}
445 .icon-hand-down{background-position:-216px -144px}
445 .icon-hand-down{background-position:-216px -144px}
446 .icon-circle-arrow-right{background-position:-240px -144px}
446 .icon-circle-arrow-right{background-position:-240px -144px}
447 .icon-circle-arrow-left{background-position:-264px -144px}
447 .icon-circle-arrow-left{background-position:-264px -144px}
448 .icon-circle-arrow-up{background-position:-288px -144px}
448 .icon-circle-arrow-up{background-position:-288px -144px}
449 .icon-circle-arrow-down{background-position:-312px -144px}
449 .icon-circle-arrow-down{background-position:-312px -144px}
450 .icon-globe{background-position:-336px -144px}
450 .icon-globe{background-position:-336px -144px}
451 .icon-wrench{background-position:-360px -144px}
451 .icon-wrench{background-position:-360px -144px}
452 .icon-tasks{background-position:-384px -144px}
452 .icon-tasks{background-position:-384px -144px}
453 .icon-filter{background-position:-408px -144px}
453 .icon-filter{background-position:-408px -144px}
454 .icon-briefcase{background-position:-432px -144px}
454 .icon-briefcase{background-position:-432px -144px}
455 .icon-fullscreen{background-position:-456px -144px}
455 .icon-fullscreen{background-position:-456px -144px}
456 .dropup,.dropdown{position:relative}
456 .dropup,.dropdown{position:relative}
457 .dropdown-toggle{*margin-bottom:-3px}
457 .dropdown-toggle{*margin-bottom:-3px}
458 .dropdown-toggle:active,.open .dropdown-toggle{outline:0}
458 .dropdown-toggle:active,.open .dropdown-toggle{outline:0}
459 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}
459 .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}
460 .dropdown .caret{margin-top:8px;margin-left:2px}
460 .dropdown .caret{margin-top:8px;margin-left:2px}
461 .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
461 .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}
462 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
462 .dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
463 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}
463 .dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}
464 .dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
464 .dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
465 .dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
465 .dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)}
466 .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
466 .dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}
467 .dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default}
467 .dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default}
468 .open{*z-index:1000}.open>.dropdown-menu{display:block}
468 .open{*z-index:1000}.open>.dropdown-menu{display:block}
469 .dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}
469 .dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}
470 .pull-right>.dropdown-menu{right:0;left:auto}
470 .pull-right>.dropdown-menu{right:0;left:auto}
471 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}
471 .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}
472 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}
472 .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}
473 .dropdown-submenu{position:relative}
473 .dropdown-submenu{position:relative}
474 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px 6px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}
474 .dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;border-radius:0 6px 6px 6px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}
475 .dropdown-submenu:hover>.dropdown-menu{display:block}
475 .dropdown-submenu:hover>.dropdown-menu{display:block}
476 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:5px 5px 5px 0;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}
476 .dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:5px 5px 5px 0;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}
477 .dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}
477 .dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#ccc;margin-top:5px;margin-right:-10px}
478 .dropdown-submenu:hover>a:after{border-left-color:#fff}
478 .dropdown-submenu:hover>a:after{border-left-color:#fff}
479 .dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
479 .dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
480 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}
480 .dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px}
481 .typeahead{z-index:1051;margin-top:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
481 .typeahead{z-index:1051;margin-top:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
482 .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}
482 .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}
483 .well-large{padding:24px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
483 .well-large{padding:24px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
484 .well-small{padding:9px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
484 .well-small{padding:9px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
485 .fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}
485 .fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}
486 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}
486 .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}
487 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}
487 .close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}
488 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}
488 button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}
489 .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:13px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #fff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #fff, #e6e6e6);background-image:-o-linear-gradient(top, #fff, #e6e6e6);background-image:linear-gradient(to bottom, #fff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}
489 .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:13px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #fff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #fff, #e6e6e6);background-image:-o-linear-gradient(top, #fff, #e6e6e6);background-image:linear-gradient(to bottom, #fff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}
490 .btn:active,.btn.active{background-color:#ccc \9}
490 .btn:active,.btn.active{background-color:#ccc \9}
491 .btn:first-child{*margin-left:0}
491 .btn:first-child{*margin-left:0}
492 .btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}
492 .btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}
493 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
493 .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}
494 .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
494 .btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
495 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
495 .btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
496 .btn-large{padding:11px 19px;font-size:16.25px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
496 .btn-large{padding:11px 19px;font-size:16.25px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
497 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}
497 .btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}
498 .btn-small{padding:2px 10px;font-size:11.049999999999999px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
498 .btn-small{padding:2px 10px;font-size:11.049999999999999px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
499 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}
499 .btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}
500 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}
500 .btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}
501 .btn-mini{padding:0 6px;font-size:9.75px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
501 .btn-mini{padding:0 6px;font-size:9.75px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
502 .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
502 .btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
503 .btn-block+.btn-block{margin-top:5px}
503 .btn-block+.btn-block{margin-top:5px}
504 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}
504 input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}
505 .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}
505 .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}
506 .btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}
506 .btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}
507 .btn-primary:active,.btn-primary.active{background-color:#039 \9}
507 .btn-primary:active,.btn-primary.active{background-color:#039 \9}
508 .btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}
508 .btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}
509 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9}
509 .btn-warning:active,.btn-warning.active{background-color:#c67605 \9}
510 .btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}
510 .btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}
511 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9}
511 .btn-danger:active,.btn-danger.active{background-color:#942a25 \9}
512 .btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}
512 .btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}
513 .btn-success:active,.btn-success.active{background-color:#408140 \9}
513 .btn-success:active,.btn-success.active{background-color:#408140 \9}
514 .btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}
514 .btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}
515 .btn-info:active,.btn-info.active{background-color:#24748c \9}
515 .btn-info:active,.btn-info.active{background-color:#24748c \9}
516 .btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444, #222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#222));background-image:-webkit-linear-gradient(top, #444, #222);background-image:-o-linear-gradient(top, #444, #222);background-image:linear-gradient(to bottom, #444, #222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}
516 .btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444, #222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#222));background-image:-webkit-linear-gradient(top, #444, #222);background-image:-o-linear-gradient(top, #444, #222);background-image:linear-gradient(to bottom, #444, #222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}
517 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}
517 .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}
518 button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}
518 button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}
519 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}
519 button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}
520 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}
520 button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}
521 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}
521 button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}
522 .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
522 .btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}
523 .btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
523 .btn-link{border-color:transparent;cursor:pointer;color:#08c;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
524 .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}
524 .btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}
525 .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}
525 .btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}
526 .btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em}.btn-group:first-child{*margin-left:0}
526 .btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em}.btn-group:first-child{*margin-left:0}
527 .btn-group+.btn-group{margin-left:5px}
527 .btn-group+.btn-group{margin-left:5px}
528 .btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}
528 .btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}
529 .btn-group>.btn{position:relative;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
529 .btn-group>.btn{position:relative;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
530 .btn-group>.btn+.btn{margin-left:-1px}
530 .btn-group>.btn+.btn{margin-left:-1px}
531 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px}
531 .btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:13px}
532 .btn-group>.btn-mini{font-size:9.75px}
532 .btn-group>.btn-mini{font-size:9.75px}
533 .btn-group>.btn-small{font-size:11.049999999999999px}
533 .btn-group>.btn-small{font-size:11.049999999999999px}
534 .btn-group>.btn-large{font-size:16.25px}
534 .btn-group>.btn-large{font-size:16.25px}
535 .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
535 .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
536 .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
536 .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
537 .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
537 .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
538 .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
538 .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
539 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}
539 .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}
540 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}
540 .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}
541 .btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px}
541 .btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px}
542 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px}
542 .btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px}
543 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}
543 .btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}
544 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px}
544 .btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px}
545 .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
545 .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)}
546 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}
546 .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}
547 .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}
547 .btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}
548 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}
548 .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}
549 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}
549 .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}
550 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}
550 .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}
551 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}
551 .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}
552 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}
552 .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}
553 .btn .caret{margin-top:8px;margin-left:0}
553 .btn .caret{margin-top:8px;margin-left:0}
554 .btn-large .caret{margin-top:6px}
554 .btn-large .caret{margin-top:6px}
555 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}
555 .btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px}
556 .btn-mini .caret,.btn-small .caret{margin-top:8px}
556 .btn-mini .caret,.btn-small .caret{margin-top:8px}
557 .dropup .btn-large .caret{border-bottom-width:5px}
557 .dropup .btn-large .caret{border-bottom-width:5px}
558 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}
558 .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}
559 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}
559 .btn-group-vertical{display:inline-block;*display:inline;*zoom:1}
560 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
560 .btn-group-vertical>.btn{display:block;float:none;max-width:100%;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
561 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}
561 .btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px}
562 .btn-group-vertical>.btn:first-child{border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}
562 .btn-group-vertical>.btn:first-child{border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}
563 .btn-group-vertical>.btn:last-child{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}
563 .btn-group-vertical>.btn:last-child{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}
564 .btn-group-vertical>.btn-large:first-child{border-radius:6px 6px 0 0;-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}
564 .btn-group-vertical>.btn-large:first-child{border-radius:6px 6px 0 0;-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}
565 .btn-group-vertical>.btn-large:last-child{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
565 .btn-group-vertical>.btn-large:last-child{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
566 .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
566 .alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
567 .alert,.alert h4{color:#c09853}
567 .alert,.alert h4{color:#c09853}
568 .alert h4{margin:0}
568 .alert h4{margin:0}
569 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}
569 .alert .close{position:relative;top:-2px;right:-21px;line-height:20px}
570 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}
570 .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}
571 .alert-success h4{color:#468847}
571 .alert-success h4{color:#468847}
572 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}
572 .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}
573 .alert-danger h4,.alert-error h4{color:#b94a48}
573 .alert-danger h4,.alert-error h4{color:#b94a48}
574 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}
574 .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}
575 .alert-info h4{color:#3a87ad}
575 .alert-info h4{color:#3a87ad}
576 .alert-block{padding-top:14px;padding-bottom:14px}
576 .alert-block{padding-top:14px;padding-bottom:14px}
577 .alert-block>p,.alert-block>ul{margin-bottom:0}
577 .alert-block>p,.alert-block>ul{margin-bottom:0}
578 .alert-block p+p{margin-top:5px}
578 .alert-block p+p{margin-top:5px}
579 .nav{margin-left:0;margin-bottom:20px;list-style:none}
579 .nav{margin-left:0;margin-bottom:20px;list-style:none}
580 .nav>li>a{display:block}
580 .nav>li>a{display:block}
581 .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
581 .nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}
582 .nav>li>a>img{max-width:none}
582 .nav>li>a>img{max-width:none}
583 .nav>.pull-right{float:right}
583 .nav>.pull-right{float:right}
584 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}
584 .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}
585 .nav li+.nav-header{margin-top:9px}
585 .nav li+.nav-header{margin-top:9px}
586 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}
586 .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0}
587 .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}
587 .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}
588 .nav-list>li>a{padding:3px 15px}
588 .nav-list>li>a{padding:3px 15px}
589 .nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}
589 .nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}
590 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}
590 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}
591 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
591 .nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}
592 .nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0}
592 .nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0}
593 .nav-tabs:after,.nav-pills:after{clear:both}
593 .nav-tabs:after,.nav-pills:after{clear:both}
594 .nav-tabs>li,.nav-pills>li{float:left}
594 .nav-tabs>li,.nav-pills>li{float:left}
595 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}
595 .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}
596 .nav-tabs{border-bottom:1px solid #ddd}
596 .nav-tabs{border-bottom:1px solid #ddd}
597 .nav-tabs>li{margin-bottom:-1px}
597 .nav-tabs>li{margin-bottom:-1px}
598 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}
598 .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}
599 .nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
599 .nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}
600 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
600 .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
601 .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}
601 .nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}
602 .nav-stacked>li{float:none}
602 .nav-stacked>li{float:none}
603 .nav-stacked>li>a{margin-right:0}
603 .nav-stacked>li>a{margin-right:0}
604 .nav-tabs.nav-stacked{border-bottom:0}
604 .nav-tabs.nav-stacked{border-bottom:0}
605 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
605 .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
606 .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
606 .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px}
607 .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
607 .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
608 .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2}
608 .nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2}
609 .nav-pills.nav-stacked>li>a{margin-bottom:3px}
609 .nav-pills.nav-stacked>li>a{margin-bottom:3px}
610 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}
610 .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}
611 .nav-tabs .dropdown-menu{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
611 .nav-tabs .dropdown-menu{border-radius:0 0 6px 6px;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}
612 .nav-pills .dropdown-menu{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
612 .nav-pills .dropdown-menu{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
613 .nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}
613 .nav .dropdown-toggle .caret{border-top-color:#08c;border-bottom-color:#08c;margin-top:6px}
614 .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}
614 .nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}
615 .nav-tabs .dropdown-toggle .caret{margin-top:8px}
615 .nav-tabs .dropdown-toggle .caret{margin-top:8px}
616 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
616 .nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
617 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
617 .nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
618 .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}
618 .nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}
619 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}
619 .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}
620 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}
620 .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}
621 .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}
621 .tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}
622 .tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0}
622 .tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0}
623 .tabbable:after{clear:both}
623 .tabbable:after{clear:both}
624 .tab-content{overflow:auto}
624 .tab-content{overflow:auto}
625 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}
625 .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}
626 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
626 .tab-content>.tab-pane,.pill-content>.pill-pane{display:none}
627 .tab-content>.active,.pill-content>.active{display:block}
627 .tab-content>.active,.pill-content>.active{display:block}
628 .tabs-below>.nav-tabs{border-top:1px solid #ddd}
628 .tabs-below>.nav-tabs{border-top:1px solid #ddd}
629 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}
629 .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}
630 .tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd}
630 .tabs-below>.nav-tabs>li>a{border-radius:0 0 4px 4px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd}
631 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}
631 .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}
632 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}
632 .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}
633 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}
633 .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}
634 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}
634 .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}
635 .tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
635 .tabs-left>.nav-tabs>li>a{margin-right:-1px;border-radius:4px 0 0 4px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}
636 .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}
636 .tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}
637 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}
637 .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}
638 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}
638 .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}
639 .tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
639 .tabs-right>.nav-tabs>li>a{margin-left:-1px;border-radius:0 4px 4px 0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}
640 .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}
640 .tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}
641 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}
641 .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}
642 .nav>.disabled>a{color:#999}
642 .nav>.disabled>a{color:#999}
643 .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default}
643 .nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default}
644 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2}
644 .navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2}
645 .navbar-inner{min-height:36px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #fff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #fff, #f2f2f2);background-image:-o-linear-gradient(top, #fff, #f2f2f2);background-image:linear-gradient(to bottom, #fff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);*zoom:1}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0}
645 .navbar-inner{min-height:36px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #fff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #fff, #f2f2f2);background-image:-o-linear-gradient(top, #fff, #f2f2f2);background-image:linear-gradient(to bottom, #fff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065);*zoom:1}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0}
646 .navbar-inner:after{clear:both}
646 .navbar-inner:after{clear:both}
647 .navbar .container{width:auto}
647 .navbar .container{width:auto}
648 .nav-collapse.collapse{height:auto;overflow:visible}
648 .nav-collapse.collapse{height:auto;overflow:visible}
649 .navbar .brand{float:left;display:block;padding:8px 20px 8px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}
649 .navbar .brand{float:left;display:block;padding:8px 20px 8px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}
650 .navbar-text{margin-bottom:0;line-height:36px;color:#777}
650 .navbar-text{margin-bottom:0;line-height:36px;color:#777}
651 .navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}
651 .navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}
652 .navbar .divider-vertical{height:36px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}
652 .navbar .divider-vertical{height:36px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #fff}
653 .navbar .btn,.navbar .btn-group{margin-top:3px}
653 .navbar .btn,.navbar .btn-group{margin-top:3px}
654 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}
654 .navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}
655 .navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0}
655 .navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0}
656 .navbar-form:after{clear:both}
656 .navbar-form:after{clear:both}
657 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:3px}
657 .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:3px}
658 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}
658 .navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}
659 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}
659 .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}
660 .navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}
660 .navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}
661 .navbar-search{position:relative;float:left;margin-top:3px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
661 .navbar-search{position:relative;float:left;margin-top:3px;margin-bottom:0}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
662 .navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
662 .navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
663 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}
663 .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}
664 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}
664 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}
665 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}
665 .navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}
666 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
666 .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
667 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
667 .navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}
668 .navbar-fixed-top{top:0}
668 .navbar-fixed-top{top:0}
669 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1)}
669 .navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1)}
670 .navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1)}
670 .navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1)}
671 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}
671 .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}
672 .navbar .nav.pull-right{float:right;margin-right:0}
672 .navbar .nav.pull-right{float:right;margin-right:0}
673 .navbar .nav>li{float:left}
673 .navbar .nav>li{float:left}
674 .navbar .nav>li>a{float:none;padding:8px 15px 8px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}
674 .navbar .nav>li>a{float:none;padding:8px 15px 8px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}
675 .navbar .nav .dropdown-toggle .caret{margin-top:8px}
675 .navbar .nav .dropdown-toggle .caret{margin-top:8px}
676 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}
676 .navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333;text-decoration:none}
677 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}
677 .navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}
678 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}
678 .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}
679 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}
679 .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}
680 .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}
680 .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}
681 .btn-navbar .icon-bar+.icon-bar{margin-top:3px}
681 .btn-navbar .icon-bar+.icon-bar{margin-top:3px}
682 .navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:9px}
682 .navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,0.2);position:absolute;top:-7px;left:9px}
683 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}
683 .navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:10px}
684 .navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);border-bottom:0;bottom:-7px;top:auto}
684 .navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0,0,0,0.2);border-bottom:0;bottom:-7px;top:auto}
685 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}
685 .navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #fff;border-bottom:0;bottom:-6px;top:auto}
686 .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}
686 .navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}
687 .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555}
687 .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555}
688 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}
688 .navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}
689 .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
689 .navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}
690 .navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px}
690 .navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px}
691 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px}
691 .navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px}
692 .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
692 .navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;border-radius:6px 0 6px 6px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}
693 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222, #111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222), to(#111));background-image:-webkit-linear-gradient(top, #222, #111);background-image:-o-linear-gradient(top, #222, #111);background-image:linear-gradient(to bottom, #222, #111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525}
693 .navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222, #111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222), to(#111));background-image:-webkit-linear-gradient(top, #222, #111);background-image:-o-linear-gradient(top, #222, #111);background-image:linear-gradient(to bottom, #222, #111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525}
694 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}
694 .navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}
695 .navbar-inverse .brand{color:#999}
695 .navbar-inverse .brand{color:#999}
696 .navbar-inverse .navbar-text{color:#999}
696 .navbar-inverse .navbar-text{color:#999}
697 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}
697 .navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#fff}
698 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}
698 .navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}
699 .navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}
699 .navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}
700 .navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}
700 .navbar-inverse .divider-vertical{border-left-color:#111;border-right-color:#222}
701 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111;color:#fff}
701 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111;color:#fff}
702 .navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}
702 .navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}
703 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}
703 .navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}
704 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
704 .navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}
705 .navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}
705 .navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}
706 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}
706 .navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}
707 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}
707 .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}
708 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15);outline:0}
708 .navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15);outline:0}
709 .navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}
709 .navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}
710 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}
710 .navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}
711 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #fff}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}
711 .breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #fff}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}
712 .breadcrumb>.active{color:#999}
712 .breadcrumb>.active{color:#999}
713 .pagination{margin:20px 0}
713 .pagination{margin:20px 0}
714 .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}
714 .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}
715 .pagination ul>li{display:inline}
715 .pagination ul>li{display:inline}
716 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}
716 .pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}
717 .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}
717 .pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}
718 .pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}
718 .pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}
719 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;background-color:transparent;cursor:default}
719 .pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;background-color:transparent;cursor:default}
720 .pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
720 .pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px}
721 .pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
721 .pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px}
722 .pagination-centered{text-align:center}
722 .pagination-centered{text-align:center}
723 .pagination-right{text-align:right}
723 .pagination-right{text-align:right}
724 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px}
724 .pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:16.25px}
725 .pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
725 .pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px}
726 .pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
726 .pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px}
727 .pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px}
727 .pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px}
728 .pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px}
728 .pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px}
729 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px}
729 .pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.049999999999999px}
730 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px}
730 .pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:9.75px}
731 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1}.pager:before,.pager:after{display:table;content:"";line-height:0}
731 .pager{margin:20px 0;list-style:none;text-align:center;*zoom:1}.pager:before,.pager:after{display:table;content:"";line-height:0}
732 .pager:after{clear:both}
732 .pager:after{clear:both}
733 .pager li{display:inline}
733 .pager li{display:inline}
734 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
734 .pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}
735 .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}
735 .pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}
736 .pager .next>a,.pager .next>span{float:right}
736 .pager .next>a,.pager .next>span{float:right}
737 .pager .previous>a,.pager .previous>span{float:left}
737 .pager .previous>a,.pager .previous>span{float:left}
738 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}
738 .pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:default}
739 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}
739 .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}
740 .modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}
740 .modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}
741 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%}
741 .modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%}
742 .modal.fade.in{top:10%}
742 .modal.fade.in{top:10%}
743 .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}
743 .modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}
744 .modal-header h3{margin:0;line-height:30px}
744 .modal-header h3{margin:0;line-height:30px}
745 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px}
745 .modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px}
746 .modal-form{margin-bottom:0}
746 .modal-form{margin-bottom:0}
747 .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff;*zoom:1}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0}
747 .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff;*zoom:1}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0}
748 .modal-footer:after{clear:both}
748 .modal-footer:after{clear:both}
749 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}
749 .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}
750 .modal-footer .btn-group .btn+.btn{margin-left:-1px}
750 .modal-footer .btn-group .btn+.btn{margin-left:-1px}
751 .modal-footer .btn-block+.btn-block{margin-left:0}
751 .modal-footer .btn-block+.btn-block{margin-left:0}
752 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}
752 .tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}
753 .tooltip.top{margin-top:-3px;padding:5px 0}
753 .tooltip.top{margin-top:-3px;padding:5px 0}
754 .tooltip.right{margin-left:3px;padding:0 5px}
754 .tooltip.right{margin-left:3px;padding:0 5px}
755 .tooltip.bottom{margin-top:3px;padding:5px 0}
755 .tooltip.bottom{margin-top:3px;padding:5px 0}
756 .tooltip.left{margin-left:-3px;padding:0 5px}
756 .tooltip.left{margin-left:-3px;padding:0 5px}
757 .tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
757 .tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
758 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}
758 .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}
759 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}
759 .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}
760 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}
760 .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}
761 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}
761 .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}
762 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}
762 .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}
763 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}
763 .popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}
764 .popover.right{margin-left:10px}
764 .popover.right{margin-left:10px}
765 .popover.bottom{margin-top:10px}
765 .popover.bottom{margin-top:10px}
766 .popover.left{margin-left:-10px}
766 .popover.left{margin-left:-10px}
767 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}
767 .popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}
768 .popover-content{padding:9px 14px}
768 .popover-content{padding:9px 14px}
769 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}
769 .popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}
770 .popover .arrow{border-width:11px}
770 .popover .arrow{border-width:11px}
771 .popover .arrow:after{border-width:10px;content:""}
771 .popover .arrow:after{border-width:10px;content:""}
772 .popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}
772 .popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}
773 .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}
773 .popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}
774 .popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}
774 .popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}
775 .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}
775 .popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}
776 .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0}
776 .thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0}
777 .thumbnails:after{clear:both}
777 .thumbnails:after{clear:both}
778 .row-fluid .thumbnails{margin-left:0}
778 .row-fluid .thumbnails{margin-left:0}
779 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}
779 .thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}
780 .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
780 .thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
781 a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}
781 a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}
782 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}
782 .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto}
783 .thumbnail .caption{padding:9px;color:#555}
783 .thumbnail .caption{padding:9px;color:#555}
784 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1}
784 .media,.media-body{overflow:hidden;*overflow:visible;zoom:1}
785 .media,.media .media{margin-top:15px}
785 .media,.media .media{margin-top:15px}
786 .media:first-child{margin-top:0}
786 .media:first-child{margin-top:0}
787 .media-object{display:block}
787 .media-object{display:block}
788 .media-heading{margin:0 0 5px}
788 .media-heading{margin:0 0 5px}
789 .media>.pull-left{margin-right:10px}
789 .media>.pull-left{margin-right:10px}
790 .media>.pull-right{margin-left:10px}
790 .media>.pull-right{margin-left:10px}
791 .media-list{margin-left:0;list-style:none}
791 .media-list{margin-left:0;list-style:none}
792 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#999}
792 .label,.badge{display:inline-block;padding:2px 4px;font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#999}
793 .label{border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
793 .label{border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
794 .badge{padding-left:9px;padding-right:9px;border-radius:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}
794 .badge{padding-left:9px;padding-right:9px;border-radius:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}
795 .label:empty,.badge:empty{display:none}
795 .label:empty,.badge:empty{display:none}
796 a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
796 a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}
797 .label-important,.badge-important{background-color:#b94a48}
797 .label-important,.badge-important{background-color:#b94a48}
798 .label-important[href],.badge-important[href]{background-color:#953b39}
798 .label-important[href],.badge-important[href]{background-color:#953b39}
799 .label-warning,.badge-warning{background-color:#f89406}
799 .label-warning,.badge-warning{background-color:#f89406}
800 .label-warning[href],.badge-warning[href]{background-color:#c67605}
800 .label-warning[href],.badge-warning[href]{background-color:#c67605}
801 .label-success,.badge-success{background-color:#468847}
801 .label-success,.badge-success{background-color:#468847}
802 .label-success[href],.badge-success[href]{background-color:#356635}
802 .label-success[href],.badge-success[href]{background-color:#356635}
803 .label-info,.badge-info{background-color:#3a87ad}
803 .label-info,.badge-info{background-color:#3a87ad}
804 .label-info[href],.badge-info[href]{background-color:#2d6987}
804 .label-info[href],.badge-info[href]{background-color:#2d6987}
805 .label-inverse,.badge-inverse{background-color:#333}
805 .label-inverse,.badge-inverse{background-color:#333}
806 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}
806 .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}
807 .btn .label,.btn .badge{position:relative;top:-1px}
807 .btn .label,.btn .badge{position:relative;top:-1px}
808 .btn-mini .label,.btn-mini .badge{top:0}
808 .btn-mini .label,.btn-mini .badge{top:0}
809 @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0} to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
809 @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0} to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0} to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
810 .progress .bar{width:0;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}
810 .progress .bar{width:0;height:100%;color:#fff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}
811 .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)}
811 .progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)}
812 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}
812 .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}
813 .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}
813 .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}
814 .progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0)}
814 .progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0)}
815 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
815 .progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
816 .progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0)}
816 .progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0)}
817 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
817 .progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
818 .progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0)}
818 .progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0)}
819 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
819 .progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
820 .progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0)}
820 .progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0)}
821 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
821 .progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,0.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,0.15)), color-stop(.75, rgba(255,255,255,0.15)), color-stop(.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}
822 .accordion{margin-bottom:20px}
822 .accordion{margin-bottom:20px}
823 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
823 .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
824 .accordion-heading{border-bottom:0}
824 .accordion-heading{border-bottom:0}
825 .accordion-heading .accordion-toggle{display:block;padding:8px 15px}
825 .accordion-heading .accordion-toggle{display:block;padding:8px 15px}
826 .accordion-toggle{cursor:pointer}
826 .accordion-toggle{cursor:pointer}
827 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}
827 .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}
828 .carousel{position:relative;margin-bottom:20px;line-height:1}
828 .carousel{position:relative;margin-bottom:20px;line-height:1}
829 .carousel-inner{overflow:hidden;width:100%;position:relative}
829 .carousel-inner{overflow:hidden;width:100%;position:relative}
830 .carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}
830 .carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}
831 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}
831 .carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}
832 .carousel-inner>.active{left:0}
832 .carousel-inner>.active{left:0}
833 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}
833 .carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}
834 .carousel-inner>.next{left:100%}
834 .carousel-inner>.next{left:100%}
835 .carousel-inner>.prev{left:-100%}
835 .carousel-inner>.prev{left:-100%}
836 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}
836 .carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}
837 .carousel-inner>.active.left{left:-100%}
837 .carousel-inner>.active.left{left:-100%}
838 .carousel-inner>.active.right{left:100%}
838 .carousel-inner>.active.right{left:100%}
839 .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{left:auto;right:15px}
839 .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{left:auto;right:15px}
840 .carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}
840 .carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}
841 .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}
841 .carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}
842 .carousel-indicators .active{background-color:#fff}
842 .carousel-indicators .active{background-color:#fff}
843 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}
843 .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}
844 .carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}
844 .carousel-caption h4,.carousel-caption p{color:#fff;line-height:20px}
845 .carousel-caption h4{margin:0 0 5px}
845 .carousel-caption h4{margin:0 0 5px}
846 .carousel-caption p{margin-bottom:0}
846 .carousel-caption p{margin-bottom:0}
847 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px}
847 .hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px}
848 .hero-unit li{line-height:30px}
848 .hero-unit li{line-height:30px}
849 .pull-right{float:right}
849 .pull-right{float:right}
850 .pull-left{float:left}
850 .pull-left{float:left}
851 .hide{display:none}
851 .hide{display:none}
852 .show{display:block}
852 .show{display:block}
853 .invisible{visibility:hidden}
853 .invisible{visibility:hidden}
854 .affix{position:fixed}
854 .affix{position:fixed}
855 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
855 .clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}
856 .clearfix:after{clear:both}
856 .clearfix:after{clear:both}
857 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
857 .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}
858 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
858 .input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}
859 @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}
859 @-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}
860 .visible-phone{display:none !important}
860 .visible-phone{display:none !important}
861 .visible-tablet{display:none !important}
861 .visible-tablet{display:none !important}
862 .hidden-desktop{display:none !important}
862 .hidden-desktop{display:none !important}
863 .visible-desktop{display:inherit !important}
863 .visible-desktop{display:inherit !important}
864 @media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-tablet{display:inherit !important} .hidden-tablet{display:none !important}}@media (max-width:767px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-phone{display:inherit !important} .hidden-phone{display:none !important}}.visible-print{display:none !important}
864 @media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-tablet{display:inherit !important} .hidden-tablet{display:none !important}}@media (max-width:767px){.hidden-desktop{display:inherit !important} .visible-desktop{display:none !important} .visible-phone{display:inherit !important} .hidden-phone{display:none !important}}.visible-print{display:none !important}
865 @media print{.visible-print{display:inherit !important} .hidden-print{display:none !important}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:30px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px} .span12{width:1170px} .span11{width:1070px} .span10{width:970px} .span9{width:870px} .span8{width:770px} .span7{width:670px} .span6{width:570px} .span5{width:470px} .span4{width:370px} .span3{width:270px} .span2{width:170px} .span1{width:70px} .offset12{margin-left:1230px} .offset11{margin-left:1130px} .offset10{margin-left:1030px} .offset9{margin-left:930px} .offset8{margin-left:830px} .offset7{margin-left:730px} .offset6{margin-left:630px} .offset5{margin-left:530px} .offset4{margin-left:430px} .offset3{margin-left:330px} .offset2{margin-left:230px} .offset1{margin-left:130px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:30px} input.span12,textarea.span12,.uneditable-input.span12{width:1156px} input.span11,textarea.span11,.uneditable-input.span11{width:1056px} input.span10,textarea.span10,.uneditable-input.span10{width:956px} input.span9,textarea.span9,.uneditable-input.span9{width:856px} input.span8,textarea.span8,.uneditable-input.span8{width:756px} input.span7,textarea.span7,.uneditable-input.span7{width:656px} input.span6,textarea.span6,.uneditable-input.span6{width:556px} input.span5,textarea.span5,.uneditable-input.span5{width:456px} input.span4,textarea.span4,.uneditable-input.span4{width:356px} input.span3,textarea.span3,.uneditable-input.span3{width:256px} input.span2,textarea.span2,.uneditable-input.span2{width:156px} input.span1,textarea.span1,.uneditable-input.span1{width:56px} .thumbnails{margin-left:-30px} .thumbnails>li{margin-left:30px} .row-fluid .thumbnails{margin-left:0}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:20px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px} .span12{width:724px} .span11{width:662px} .span10{width:600px} .span9{width:538px} .span8{width:476px} .span7{width:414px} .span6{width:352px} .span5{width:290px} .span4{width:228px} .span3{width:166px} .span2{width:104px} .span1{width:42px} .offset12{margin-left:764px} .offset11{margin-left:702px} .offset10{margin-left:640px} .offset9{margin-left:578px} .offset8{margin-left:516px} .offset7{margin-left:454px} .offset6{margin-left:392px} .offset5{margin-left:330px} .offset4{margin-left:268px} .offset3{margin-left:206px} .offset2{margin-left:144px} .offset1{margin-left:82px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:20px} input.span12,textarea.span12,.uneditable-input.span12{width:710px} input.span11,textarea.span11,.uneditable-input.span11{width:648px} input.span10,textarea.span10,.uneditable-input.span10{width:586px} input.span9,textarea.span9,.uneditable-input.span9{width:524px} input.span8,textarea.span8,.uneditable-input.span8{width:462px} input.span7,textarea.span7,.uneditable-input.span7{width:400px} input.span6,textarea.span6,.uneditable-input.span6{width:338px} input.span5,textarea.span5,.uneditable-input.span5{width:276px} input.span4,textarea.span4,.uneditable-input.span4{width:214px} input.span3,textarea.span3,.uneditable-input.span3{width:152px} input.span2,textarea.span2,.uneditable-input.span2{width:90px} input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media (max-width:767px){body{padding-left:20px;padding-right:20px} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px} .container-fluid{padding:0} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left} .dl-horizontal dd{margin-left:0} .container{width:auto} .row-fluid{width:100%} .row,.thumbnails{margin-left:0} .thumbnails>li{float:none;margin-left:0} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .row-fluid [class*="offset"]:first-child{margin-left:0} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto} .controls-row [class*="span"]+[class*="span"]{margin-left:0} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0}.modal.fade{top:-100px} .modal.fade.in{top:20px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0)} .page-header h1 small{display:block;line-height:20px} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left} .form-horizontal .controls{margin-left:0} .form-horizontal .control-list{padding-top:0} .form-horizontal .form-actions{padding-left:10px;padding-right:10px} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px} .media-object{margin-right:0;margin-left:0} .modal{top:10px;left:10px;right:10px} .modal-header .close{padding:10px;margin:-10px} .carousel-caption{position:static}}@media (max-width:979px){body{padding-top:0} .navbar-fixed-top,.navbar-fixed-bottom{position:static} .navbar-fixed-top{margin-bottom:20px} .navbar-fixed-bottom{margin-top:20px} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px} .navbar .container{width:auto;padding:0} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px} .nav-collapse{clear:both} .nav-collapse .nav{float:none;margin:0 0 10px} .nav-collapse .nav>li{float:none} .nav-collapse .nav>li>a{margin-bottom:2px} .nav-collapse .nav>.divider-vertical{display:none} .nav-collapse .nav .nav-header{color:#777;text-shadow:none} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111} .nav-collapse.in .btn-group{margin-top:5px;padding:0} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} .nav-collapse .open>.dropdown-menu{display:block} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none} .nav-collapse .dropdown-menu .divider{display:none} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0} .navbar .btn-navbar{display:block} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px}}@media (min-width:979px + 1){.nav-collapse.collapse{height:auto !important;overflow:visible !important}}@font-face{font-family:'FontAwesome';src:url('../components/font-awesome/font/fontawesome-webfont.eot?v=3.2.1');src:url('../components/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../components/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../components/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../components/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}
865 @media print{.visible-print{display:inherit !important} .hidden-print{display:none !important}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:30px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px} .span12{width:1170px} .span11{width:1070px} .span10{width:970px} .span9{width:870px} .span8{width:770px} .span7{width:670px} .span6{width:570px} .span5{width:470px} .span4{width:370px} .span3{width:270px} .span2{width:170px} .span1{width:70px} .offset12{margin-left:1230px} .offset11{margin-left:1130px} .offset10{margin-left:1030px} .offset9{margin-left:930px} .offset8{margin-left:830px} .offset7{margin-left:730px} .offset6{margin-left:630px} .offset5{margin-left:530px} .offset4{margin-left:430px} .offset3{margin-left:330px} .offset2{margin-left:230px} .offset1{margin-left:130px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:30px} input.span12,textarea.span12,.uneditable-input.span12{width:1156px} input.span11,textarea.span11,.uneditable-input.span11{width:1056px} input.span10,textarea.span10,.uneditable-input.span10{width:956px} input.span9,textarea.span9,.uneditable-input.span9{width:856px} input.span8,textarea.span8,.uneditable-input.span8{width:756px} input.span7,textarea.span7,.uneditable-input.span7{width:656px} input.span6,textarea.span6,.uneditable-input.span6{width:556px} input.span5,textarea.span5,.uneditable-input.span5{width:456px} input.span4,textarea.span4,.uneditable-input.span4{width:356px} input.span3,textarea.span3,.uneditable-input.span3{width:256px} input.span2,textarea.span2,.uneditable-input.span2{width:156px} input.span1,textarea.span1,.uneditable-input.span1{width:56px} .thumbnails{margin-left:-30px} .thumbnails>li{margin-left:30px} .row-fluid .thumbnails{margin-left:0}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:"";line-height:0} .row:after{clear:both} [class*="span"]{float:left;min-height:1px;margin-left:20px} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px} .span12{width:724px} .span11{width:662px} .span10{width:600px} .span9{width:538px} .span8{width:476px} .span7{width:414px} .span6{width:352px} .span5{width:290px} .span4{width:228px} .span3{width:166px} .span2{width:104px} .span1{width:42px} .offset12{margin-left:764px} .offset11{margin-left:702px} .offset10{margin-left:640px} .offset9{margin-left:578px} .offset8{margin-left:516px} .offset7{margin-left:454px} .offset6{margin-left:392px} .offset5{margin-left:330px} .offset4{margin-left:268px} .offset3{margin-left:206px} .offset2{margin-left:144px} .offset1{margin-left:82px} .row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0} .row-fluid:after{clear:both} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%} .row-fluid [class*="span"]:first-child{margin-left:0} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%} .row-fluid .span12{width:100%;*width:99.94680851063829%} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%} input,textarea,.uneditable-input{margin-left:0} .controls-row [class*="span"]+[class*="span"]{margin-left:20px} input.span12,textarea.span12,.uneditable-input.span12{width:710px} input.span11,textarea.span11,.uneditable-input.span11{width:648px} input.span10,textarea.span10,.uneditable-input.span10{width:586px} input.span9,textarea.span9,.uneditable-input.span9{width:524px} input.span8,textarea.span8,.uneditable-input.span8{width:462px} input.span7,textarea.span7,.uneditable-input.span7{width:400px} input.span6,textarea.span6,.uneditable-input.span6{width:338px} input.span5,textarea.span5,.uneditable-input.span5{width:276px} input.span4,textarea.span4,.uneditable-input.span4{width:214px} input.span3,textarea.span3,.uneditable-input.span3{width:152px} input.span2,textarea.span2,.uneditable-input.span2{width:90px} input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media (max-width:767px){body{padding-left:20px;padding-right:20px} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px} .container-fluid{padding:0} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left} .dl-horizontal dd{margin-left:0} .container{width:auto} .row-fluid{width:100%} .row,.thumbnails{margin-left:0} .thumbnails>li{float:none;margin-left:0} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .row-fluid [class*="offset"]:first-child{margin-left:0} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto} .controls-row [class*="span"]+[class*="span"]{margin-left:0} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0}.modal.fade{top:-100px} .modal.fade.in{top:20px}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0)} .page-header h1 small{display:block;line-height:20px} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left} .form-horizontal .controls{margin-left:0} .form-horizontal .control-list{padding-top:0} .form-horizontal .form-actions{padding-left:10px;padding-right:10px} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px} .media-object{margin-right:0;margin-left:0} .modal{top:10px;left:10px;right:10px} .modal-header .close{padding:10px;margin:-10px} .carousel-caption{position:static}}@media (max-width:979px){body{padding-top:0} .navbar-fixed-top,.navbar-fixed-bottom{position:static} .navbar-fixed-top{margin-bottom:20px} .navbar-fixed-bottom{margin-top:20px} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px} .navbar .container{width:auto;padding:0} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px} .nav-collapse{clear:both} .nav-collapse .nav{float:none;margin:0 0 10px} .nav-collapse .nav>li{float:none} .nav-collapse .nav>li>a{margin-bottom:2px} .nav-collapse .nav>.divider-vertical{display:none} .nav-collapse .nav .nav-header{color:#777;text-shadow:none} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111} .nav-collapse.in .btn-group{margin-top:5px;padding:0} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} .nav-collapse .open>.dropdown-menu{display:block} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none} .nav-collapse .dropdown-menu .divider{display:none} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0} .navbar .btn-navbar{display:block} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px}}@media (min-width:979px + 1){.nav-collapse.collapse{height:auto !important;overflow:visible !important}}@font-face{font-family:'FontAwesome';src:url('../components/font-awesome/font/fontawesome-webfont.eot?v=3.2.1');src:url('../components/font-awesome/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('../components/font-awesome/font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('../components/font-awesome/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('../components/font-awesome/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}
866 [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}
866 [class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}
867 .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}
867 .icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}
868 a [class^="icon-"],a [class*=" icon-"]{display:inline}
868 a [class^="icon-"],a [class*=" icon-"]{display:inline}
869 [class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}
869 [class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:.2857142857142857em}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em}
870 .icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}
870 .icons-ul{margin-left:2.142857142857143em;list-style-type:none}.icons-ul>li{position:relative}
871 .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}
871 .icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit}
872 [class^="icon-"].hide,[class*=" icon-"].hide{display:none}
872 [class^="icon-"].hide,[class*=" icon-"].hide{display:none}
873 .icon-muted{color:#eee}
873 .icon-muted{color:#eee}
874 .icon-light{color:#fff}
874 .icon-light{color:#fff}
875 .icon-dark{color:#333}
875 .icon-dark{color:#333}
876 .icon-border{border:solid 1px #eee;padding:.2em .25em .15em;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
876 .icon-border{border:solid 1px #eee;padding:.2em .25em .15em;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}
877 .icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
877 .icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}
878 .icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
878 .icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}
879 .icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
879 .icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}
880 .icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;border-radius:7px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}
880 .icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;border-radius:7px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}
881 .pull-right{float:right}
881 .pull-right{float:right}
882 .pull-left{float:left}
882 .pull-left{float:left}
883 [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}
883 [class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}
884 [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}
884 [class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}
885 [class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}
885 [class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}
886 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}
886 .icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}
887 .btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}
887 .btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}
888 .btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}
888 .btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}
889 .nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}
889 .nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}
890 .btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}
890 .btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}
891 .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}
891 .btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}
892 .btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}
892 .btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}
893 .btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}
893 .btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}
894 .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}
894 .btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}
895 .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}
895 .btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}
896 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}
896 .nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit}
897 .icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}
897 .icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}
898 .icon-stack .icon-stack-base{font-size:2em;*line-height:1em}
898 .icon-stack .icon-stack-base{font-size:2em;*line-height:1em}
899 .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}
899 .icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}
900 a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}
900 a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none}
901 @-moz-keyframes spin{0%{-moz-transform:rotate(0deg)} 100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)} 100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)} 100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)} 100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)} 100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}
901 @-moz-keyframes spin{0%{-moz-transform:rotate(0deg)} 100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)} 100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)} 100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)} 100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)} 100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}
902 .icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}
902 .icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}
903 .icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}
903 .icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}
904 .icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}
904 .icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}
905 .icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}
905 .icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}
906 a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}
906 a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block}
907 .icon-glass:before{content:"\f000"}
907 .icon-glass:before{content:"\f000"}
908 .icon-music:before{content:"\f001"}
908 .icon-music:before{content:"\f001"}
909 .icon-search:before{content:"\f002"}
909 .icon-search:before{content:"\f002"}
910 .icon-envelope-alt:before{content:"\f003"}
910 .icon-envelope-alt:before{content:"\f003"}
911 .icon-heart:before{content:"\f004"}
911 .icon-heart:before{content:"\f004"}
912 .icon-star:before{content:"\f005"}
912 .icon-star:before{content:"\f005"}
913 .icon-star-empty:before{content:"\f006"}
913 .icon-star-empty:before{content:"\f006"}
914 .icon-user:before{content:"\f007"}
914 .icon-user:before{content:"\f007"}
915 .icon-film:before{content:"\f008"}
915 .icon-film:before{content:"\f008"}
916 .icon-th-large:before{content:"\f009"}
916 .icon-th-large:before{content:"\f009"}
917 .icon-th:before{content:"\f00a"}
917 .icon-th:before{content:"\f00a"}
918 .icon-th-list:before{content:"\f00b"}
918 .icon-th-list:before{content:"\f00b"}
919 .icon-ok:before{content:"\f00c"}
919 .icon-ok:before{content:"\f00c"}
920 .icon-remove:before{content:"\f00d"}
920 .icon-remove:before{content:"\f00d"}
921 .icon-zoom-in:before{content:"\f00e"}
921 .icon-zoom-in:before{content:"\f00e"}
922 .icon-zoom-out:before{content:"\f010"}
922 .icon-zoom-out:before{content:"\f010"}
923 .icon-power-off:before,.icon-off:before{content:"\f011"}
923 .icon-power-off:before,.icon-off:before{content:"\f011"}
924 .icon-signal:before{content:"\f012"}
924 .icon-signal:before{content:"\f012"}
925 .icon-gear:before,.icon-cog:before{content:"\f013"}
925 .icon-gear:before,.icon-cog:before{content:"\f013"}
926 .icon-trash:before{content:"\f014"}
926 .icon-trash:before{content:"\f014"}
927 .icon-home:before{content:"\f015"}
927 .icon-home:before{content:"\f015"}
928 .icon-file-alt:before{content:"\f016"}
928 .icon-file-alt:before{content:"\f016"}
929 .icon-time:before{content:"\f017"}
929 .icon-time:before{content:"\f017"}
930 .icon-road:before{content:"\f018"}
930 .icon-road:before{content:"\f018"}
931 .icon-download-alt:before{content:"\f019"}
931 .icon-download-alt:before{content:"\f019"}
932 .icon-download:before{content:"\f01a"}
932 .icon-download:before{content:"\f01a"}
933 .icon-upload:before{content:"\f01b"}
933 .icon-upload:before{content:"\f01b"}
934 .icon-inbox:before{content:"\f01c"}
934 .icon-inbox:before{content:"\f01c"}
935 .icon-play-circle:before{content:"\f01d"}
935 .icon-play-circle:before{content:"\f01d"}
936 .icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}
936 .icon-rotate-right:before,.icon-repeat:before{content:"\f01e"}
937 .icon-refresh:before{content:"\f021"}
937 .icon-refresh:before{content:"\f021"}
938 .icon-list-alt:before{content:"\f022"}
938 .icon-list-alt:before{content:"\f022"}
939 .icon-lock:before{content:"\f023"}
939 .icon-lock:before{content:"\f023"}
940 .icon-flag:before{content:"\f024"}
940 .icon-flag:before{content:"\f024"}
941 .icon-headphones:before{content:"\f025"}
941 .icon-headphones:before{content:"\f025"}
942 .icon-volume-off:before{content:"\f026"}
942 .icon-volume-off:before{content:"\f026"}
943 .icon-volume-down:before{content:"\f027"}
943 .icon-volume-down:before{content:"\f027"}
944 .icon-volume-up:before{content:"\f028"}
944 .icon-volume-up:before{content:"\f028"}
945 .icon-qrcode:before{content:"\f029"}
945 .icon-qrcode:before{content:"\f029"}
946 .icon-barcode:before{content:"\f02a"}
946 .icon-barcode:before{content:"\f02a"}
947 .icon-tag:before{content:"\f02b"}
947 .icon-tag:before{content:"\f02b"}
948 .icon-tags:before{content:"\f02c"}
948 .icon-tags:before{content:"\f02c"}
949 .icon-book:before{content:"\f02d"}
949 .icon-book:before{content:"\f02d"}
950 .icon-bookmark:before{content:"\f02e"}
950 .icon-bookmark:before{content:"\f02e"}
951 .icon-print:before{content:"\f02f"}
951 .icon-print:before{content:"\f02f"}
952 .icon-camera:before{content:"\f030"}
952 .icon-camera:before{content:"\f030"}
953 .icon-font:before{content:"\f031"}
953 .icon-font:before{content:"\f031"}
954 .icon-bold:before{content:"\f032"}
954 .icon-bold:before{content:"\f032"}
955 .icon-italic:before{content:"\f033"}
955 .icon-italic:before{content:"\f033"}
956 .icon-text-height:before{content:"\f034"}
956 .icon-text-height:before{content:"\f034"}
957 .icon-text-width:before{content:"\f035"}
957 .icon-text-width:before{content:"\f035"}
958 .icon-align-left:before{content:"\f036"}
958 .icon-align-left:before{content:"\f036"}
959 .icon-align-center:before{content:"\f037"}
959 .icon-align-center:before{content:"\f037"}
960 .icon-align-right:before{content:"\f038"}
960 .icon-align-right:before{content:"\f038"}
961 .icon-align-justify:before{content:"\f039"}
961 .icon-align-justify:before{content:"\f039"}
962 .icon-list:before{content:"\f03a"}
962 .icon-list:before{content:"\f03a"}
963 .icon-indent-left:before{content:"\f03b"}
963 .icon-indent-left:before{content:"\f03b"}
964 .icon-indent-right:before{content:"\f03c"}
964 .icon-indent-right:before{content:"\f03c"}
965 .icon-facetime-video:before{content:"\f03d"}
965 .icon-facetime-video:before{content:"\f03d"}
966 .icon-picture:before{content:"\f03e"}
966 .icon-picture:before{content:"\f03e"}
967 .icon-pencil:before{content:"\f040"}
967 .icon-pencil:before{content:"\f040"}
968 .icon-map-marker:before{content:"\f041"}
968 .icon-map-marker:before{content:"\f041"}
969 .icon-adjust:before{content:"\f042"}
969 .icon-adjust:before{content:"\f042"}
970 .icon-tint:before{content:"\f043"}
970 .icon-tint:before{content:"\f043"}
971 .icon-edit:before{content:"\f044"}
971 .icon-edit:before{content:"\f044"}
972 .icon-share:before{content:"\f045"}
972 .icon-share:before{content:"\f045"}
973 .icon-check:before{content:"\f046"}
973 .icon-check:before{content:"\f046"}
974 .icon-move:before{content:"\f047"}
974 .icon-move:before{content:"\f047"}
975 .icon-step-backward:before{content:"\f048"}
975 .icon-step-backward:before{content:"\f048"}
976 .icon-fast-backward:before{content:"\f049"}
976 .icon-fast-backward:before{content:"\f049"}
977 .icon-backward:before{content:"\f04a"}
977 .icon-backward:before{content:"\f04a"}
978 .icon-play:before{content:"\f04b"}
978 .icon-play:before{content:"\f04b"}
979 .icon-pause:before{content:"\f04c"}
979 .icon-pause:before{content:"\f04c"}
980 .icon-stop:before{content:"\f04d"}
980 .icon-stop:before{content:"\f04d"}
981 .icon-forward:before{content:"\f04e"}
981 .icon-forward:before{content:"\f04e"}
982 .icon-fast-forward:before{content:"\f050"}
982 .icon-fast-forward:before{content:"\f050"}
983 .icon-step-forward:before{content:"\f051"}
983 .icon-step-forward:before{content:"\f051"}
984 .icon-eject:before{content:"\f052"}
984 .icon-eject:before{content:"\f052"}
985 .icon-chevron-left:before{content:"\f053"}
985 .icon-chevron-left:before{content:"\f053"}
986 .icon-chevron-right:before{content:"\f054"}
986 .icon-chevron-right:before{content:"\f054"}
987 .icon-plus-sign:before{content:"\f055"}
987 .icon-plus-sign:before{content:"\f055"}
988 .icon-minus-sign:before{content:"\f056"}
988 .icon-minus-sign:before{content:"\f056"}
989 .icon-remove-sign:before{content:"\f057"}
989 .icon-remove-sign:before{content:"\f057"}
990 .icon-ok-sign:before{content:"\f058"}
990 .icon-ok-sign:before{content:"\f058"}
991 .icon-question-sign:before{content:"\f059"}
991 .icon-question-sign:before{content:"\f059"}
992 .icon-info-sign:before{content:"\f05a"}
992 .icon-info-sign:before{content:"\f05a"}
993 .icon-screenshot:before{content:"\f05b"}
993 .icon-screenshot:before{content:"\f05b"}
994 .icon-remove-circle:before{content:"\f05c"}
994 .icon-remove-circle:before{content:"\f05c"}
995 .icon-ok-circle:before{content:"\f05d"}
995 .icon-ok-circle:before{content:"\f05d"}
996 .icon-ban-circle:before{content:"\f05e"}
996 .icon-ban-circle:before{content:"\f05e"}
997 .icon-arrow-left:before{content:"\f060"}
997 .icon-arrow-left:before{content:"\f060"}
998 .icon-arrow-right:before{content:"\f061"}
998 .icon-arrow-right:before{content:"\f061"}
999 .icon-arrow-up:before{content:"\f062"}
999 .icon-arrow-up:before{content:"\f062"}
1000 .icon-arrow-down:before{content:"\f063"}
1000 .icon-arrow-down:before{content:"\f063"}
1001 .icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}
1001 .icon-mail-forward:before,.icon-share-alt:before{content:"\f064"}
1002 .icon-resize-full:before{content:"\f065"}
1002 .icon-resize-full:before{content:"\f065"}
1003 .icon-resize-small:before{content:"\f066"}
1003 .icon-resize-small:before{content:"\f066"}
1004 .icon-plus:before{content:"\f067"}
1004 .icon-plus:before{content:"\f067"}
1005 .icon-minus:before{content:"\f068"}
1005 .icon-minus:before{content:"\f068"}
1006 .icon-asterisk:before{content:"\f069"}
1006 .icon-asterisk:before{content:"\f069"}
1007 .icon-exclamation-sign:before{content:"\f06a"}
1007 .icon-exclamation-sign:before{content:"\f06a"}
1008 .icon-gift:before{content:"\f06b"}
1008 .icon-gift:before{content:"\f06b"}
1009 .icon-leaf:before{content:"\f06c"}
1009 .icon-leaf:before{content:"\f06c"}
1010 .icon-fire:before{content:"\f06d"}
1010 .icon-fire:before{content:"\f06d"}
1011 .icon-eye-open:before{content:"\f06e"}
1011 .icon-eye-open:before{content:"\f06e"}
1012 .icon-eye-close:before{content:"\f070"}
1012 .icon-eye-close:before{content:"\f070"}
1013 .icon-warning-sign:before{content:"\f071"}
1013 .icon-warning-sign:before{content:"\f071"}
1014 .icon-plane:before{content:"\f072"}
1014 .icon-plane:before{content:"\f072"}
1015 .icon-calendar:before{content:"\f073"}
1015 .icon-calendar:before{content:"\f073"}
1016 .icon-random:before{content:"\f074"}
1016 .icon-random:before{content:"\f074"}
1017 .icon-comment:before{content:"\f075"}
1017 .icon-comment:before{content:"\f075"}
1018 .icon-magnet:before{content:"\f076"}
1018 .icon-magnet:before{content:"\f076"}
1019 .icon-chevron-up:before{content:"\f077"}
1019 .icon-chevron-up:before{content:"\f077"}
1020 .icon-chevron-down:before{content:"\f078"}
1020 .icon-chevron-down:before{content:"\f078"}
1021 .icon-retweet:before{content:"\f079"}
1021 .icon-retweet:before{content:"\f079"}
1022 .icon-shopping-cart:before{content:"\f07a"}
1022 .icon-shopping-cart:before{content:"\f07a"}
1023 .icon-folder-close:before{content:"\f07b"}
1023 .icon-folder-close:before{content:"\f07b"}
1024 .icon-folder-open:before{content:"\f07c"}
1024 .icon-folder-open:before{content:"\f07c"}
1025 .icon-resize-vertical:before{content:"\f07d"}
1025 .icon-resize-vertical:before{content:"\f07d"}
1026 .icon-resize-horizontal:before{content:"\f07e"}
1026 .icon-resize-horizontal:before{content:"\f07e"}
1027 .icon-bar-chart:before{content:"\f080"}
1027 .icon-bar-chart:before{content:"\f080"}
1028 .icon-twitter-sign:before{content:"\f081"}
1028 .icon-twitter-sign:before{content:"\f081"}
1029 .icon-facebook-sign:before{content:"\f082"}
1029 .icon-facebook-sign:before{content:"\f082"}
1030 .icon-camera-retro:before{content:"\f083"}
1030 .icon-camera-retro:before{content:"\f083"}
1031 .icon-key:before{content:"\f084"}
1031 .icon-key:before{content:"\f084"}
1032 .icon-gears:before,.icon-cogs:before{content:"\f085"}
1032 .icon-gears:before,.icon-cogs:before{content:"\f085"}
1033 .icon-comments:before{content:"\f086"}
1033 .icon-comments:before{content:"\f086"}
1034 .icon-thumbs-up-alt:before{content:"\f087"}
1034 .icon-thumbs-up-alt:before{content:"\f087"}
1035 .icon-thumbs-down-alt:before{content:"\f088"}
1035 .icon-thumbs-down-alt:before{content:"\f088"}
1036 .icon-star-half:before{content:"\f089"}
1036 .icon-star-half:before{content:"\f089"}
1037 .icon-heart-empty:before{content:"\f08a"}
1037 .icon-heart-empty:before{content:"\f08a"}
1038 .icon-signout:before{content:"\f08b"}
1038 .icon-signout:before{content:"\f08b"}
1039 .icon-linkedin-sign:before{content:"\f08c"}
1039 .icon-linkedin-sign:before{content:"\f08c"}
1040 .icon-pushpin:before{content:"\f08d"}
1040 .icon-pushpin:before{content:"\f08d"}
1041 .icon-external-link:before{content:"\f08e"}
1041 .icon-external-link:before{content:"\f08e"}
1042 .icon-signin:before{content:"\f090"}
1042 .icon-signin:before{content:"\f090"}
1043 .icon-trophy:before{content:"\f091"}
1043 .icon-trophy:before{content:"\f091"}
1044 .icon-github-sign:before{content:"\f092"}
1044 .icon-github-sign:before{content:"\f092"}
1045 .icon-upload-alt:before{content:"\f093"}
1045 .icon-upload-alt:before{content:"\f093"}
1046 .icon-lemon:before{content:"\f094"}
1046 .icon-lemon:before{content:"\f094"}
1047 .icon-phone:before{content:"\f095"}
1047 .icon-phone:before{content:"\f095"}
1048 .icon-unchecked:before,.icon-check-empty:before{content:"\f096"}
1048 .icon-unchecked:before,.icon-check-empty:before{content:"\f096"}
1049 .icon-bookmark-empty:before{content:"\f097"}
1049 .icon-bookmark-empty:before{content:"\f097"}
1050 .icon-phone-sign:before{content:"\f098"}
1050 .icon-phone-sign:before{content:"\f098"}
1051 .icon-twitter:before{content:"\f099"}
1051 .icon-twitter:before{content:"\f099"}
1052 .icon-facebook:before{content:"\f09a"}
1052 .icon-facebook:before{content:"\f09a"}
1053 .icon-github:before{content:"\f09b"}
1053 .icon-github:before{content:"\f09b"}
1054 .icon-unlock:before{content:"\f09c"}
1054 .icon-unlock:before{content:"\f09c"}
1055 .icon-credit-card:before{content:"\f09d"}
1055 .icon-credit-card:before{content:"\f09d"}
1056 .icon-rss:before{content:"\f09e"}
1056 .icon-rss:before{content:"\f09e"}
1057 .icon-hdd:before{content:"\f0a0"}
1057 .icon-hdd:before{content:"\f0a0"}
1058 .icon-bullhorn:before{content:"\f0a1"}
1058 .icon-bullhorn:before{content:"\f0a1"}
1059 .icon-bell:before{content:"\f0a2"}
1059 .icon-bell:before{content:"\f0a2"}
1060 .icon-certificate:before{content:"\f0a3"}
1060 .icon-certificate:before{content:"\f0a3"}
1061 .icon-hand-right:before{content:"\f0a4"}
1061 .icon-hand-right:before{content:"\f0a4"}
1062 .icon-hand-left:before{content:"\f0a5"}
1062 .icon-hand-left:before{content:"\f0a5"}
1063 .icon-hand-up:before{content:"\f0a6"}
1063 .icon-hand-up:before{content:"\f0a6"}
1064 .icon-hand-down:before{content:"\f0a7"}
1064 .icon-hand-down:before{content:"\f0a7"}
1065 .icon-circle-arrow-left:before{content:"\f0a8"}
1065 .icon-circle-arrow-left:before{content:"\f0a8"}
1066 .icon-circle-arrow-right:before{content:"\f0a9"}
1066 .icon-circle-arrow-right:before{content:"\f0a9"}
1067 .icon-circle-arrow-up:before{content:"\f0aa"}
1067 .icon-circle-arrow-up:before{content:"\f0aa"}
1068 .icon-circle-arrow-down:before{content:"\f0ab"}
1068 .icon-circle-arrow-down:before{content:"\f0ab"}
1069 .icon-globe:before{content:"\f0ac"}
1069 .icon-globe:before{content:"\f0ac"}
1070 .icon-wrench:before{content:"\f0ad"}
1070 .icon-wrench:before{content:"\f0ad"}
1071 .icon-tasks:before{content:"\f0ae"}
1071 .icon-tasks:before{content:"\f0ae"}
1072 .icon-filter:before{content:"\f0b0"}
1072 .icon-filter:before{content:"\f0b0"}
1073 .icon-briefcase:before{content:"\f0b1"}
1073 .icon-briefcase:before{content:"\f0b1"}
1074 .icon-fullscreen:before{content:"\f0b2"}
1074 .icon-fullscreen:before{content:"\f0b2"}
1075 .icon-group:before{content:"\f0c0"}
1075 .icon-group:before{content:"\f0c0"}
1076 .icon-link:before{content:"\f0c1"}
1076 .icon-link:before{content:"\f0c1"}
1077 .icon-cloud:before{content:"\f0c2"}
1077 .icon-cloud:before{content:"\f0c2"}
1078 .icon-beaker:before{content:"\f0c3"}
1078 .icon-beaker:before{content:"\f0c3"}
1079 .icon-cut:before{content:"\f0c4"}
1079 .icon-cut:before{content:"\f0c4"}
1080 .icon-copy:before{content:"\f0c5"}
1080 .icon-copy:before{content:"\f0c5"}
1081 .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}
1081 .icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6"}
1082 .icon-save:before{content:"\f0c7"}
1082 .icon-save:before{content:"\f0c7"}
1083 .icon-sign-blank:before{content:"\f0c8"}
1083 .icon-sign-blank:before{content:"\f0c8"}
1084 .icon-reorder:before{content:"\f0c9"}
1084 .icon-reorder:before{content:"\f0c9"}
1085 .icon-list-ul:before{content:"\f0ca"}
1085 .icon-list-ul:before{content:"\f0ca"}
1086 .icon-list-ol:before{content:"\f0cb"}
1086 .icon-list-ol:before{content:"\f0cb"}
1087 .icon-strikethrough:before{content:"\f0cc"}
1087 .icon-strikethrough:before{content:"\f0cc"}
1088 .icon-underline:before{content:"\f0cd"}
1088 .icon-underline:before{content:"\f0cd"}
1089 .icon-table:before{content:"\f0ce"}
1089 .icon-table:before{content:"\f0ce"}
1090 .icon-magic:before{content:"\f0d0"}
1090 .icon-magic:before{content:"\f0d0"}
1091 .icon-truck:before{content:"\f0d1"}
1091 .icon-truck:before{content:"\f0d1"}
1092 .icon-pinterest:before{content:"\f0d2"}
1092 .icon-pinterest:before{content:"\f0d2"}
1093 .icon-pinterest-sign:before{content:"\f0d3"}
1093 .icon-pinterest-sign:before{content:"\f0d3"}
1094 .icon-google-plus-sign:before{content:"\f0d4"}
1094 .icon-google-plus-sign:before{content:"\f0d4"}
1095 .icon-google-plus:before{content:"\f0d5"}
1095 .icon-google-plus:before{content:"\f0d5"}
1096 .icon-money:before{content:"\f0d6"}
1096 .icon-money:before{content:"\f0d6"}
1097 .icon-caret-down:before{content:"\f0d7"}
1097 .icon-caret-down:before{content:"\f0d7"}
1098 .icon-caret-up:before{content:"\f0d8"}
1098 .icon-caret-up:before{content:"\f0d8"}
1099 .icon-caret-left:before{content:"\f0d9"}
1099 .icon-caret-left:before{content:"\f0d9"}
1100 .icon-caret-right:before{content:"\f0da"}
1100 .icon-caret-right:before{content:"\f0da"}
1101 .icon-columns:before{content:"\f0db"}
1101 .icon-columns:before{content:"\f0db"}
1102 .icon-sort:before{content:"\f0dc"}
1102 .icon-sort:before{content:"\f0dc"}
1103 .icon-sort-down:before{content:"\f0dd"}
1103 .icon-sort-down:before{content:"\f0dd"}
1104 .icon-sort-up:before{content:"\f0de"}
1104 .icon-sort-up:before{content:"\f0de"}
1105 .icon-envelope:before{content:"\f0e0"}
1105 .icon-envelope:before{content:"\f0e0"}
1106 .icon-linkedin:before{content:"\f0e1"}
1106 .icon-linkedin:before{content:"\f0e1"}
1107 .icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}
1107 .icon-rotate-left:before,.icon-undo:before{content:"\f0e2"}
1108 .icon-legal:before{content:"\f0e3"}
1108 .icon-legal:before{content:"\f0e3"}
1109 .icon-dashboard:before{content:"\f0e4"}
1109 .icon-dashboard:before{content:"\f0e4"}
1110 .icon-comment-alt:before{content:"\f0e5"}
1110 .icon-comment-alt:before{content:"\f0e5"}
1111 .icon-comments-alt:before{content:"\f0e6"}
1111 .icon-comments-alt:before{content:"\f0e6"}
1112 .icon-bolt:before{content:"\f0e7"}
1112 .icon-bolt:before{content:"\f0e7"}
1113 .icon-sitemap:before{content:"\f0e8"}
1113 .icon-sitemap:before{content:"\f0e8"}
1114 .icon-umbrella:before{content:"\f0e9"}
1114 .icon-umbrella:before{content:"\f0e9"}
1115 .icon-paste:before{content:"\f0ea"}
1115 .icon-paste:before{content:"\f0ea"}
1116 .icon-lightbulb:before{content:"\f0eb"}
1116 .icon-lightbulb:before{content:"\f0eb"}
1117 .icon-exchange:before{content:"\f0ec"}
1117 .icon-exchange:before{content:"\f0ec"}
1118 .icon-cloud-download:before{content:"\f0ed"}
1118 .icon-cloud-download:before{content:"\f0ed"}
1119 .icon-cloud-upload:before{content:"\f0ee"}
1119 .icon-cloud-upload:before{content:"\f0ee"}
1120 .icon-user-md:before{content:"\f0f0"}
1120 .icon-user-md:before{content:"\f0f0"}
1121 .icon-stethoscope:before{content:"\f0f1"}
1121 .icon-stethoscope:before{content:"\f0f1"}
1122 .icon-suitcase:before{content:"\f0f2"}
1122 .icon-suitcase:before{content:"\f0f2"}
1123 .icon-bell-alt:before{content:"\f0f3"}
1123 .icon-bell-alt:before{content:"\f0f3"}
1124 .icon-coffee:before{content:"\f0f4"}
1124 .icon-coffee:before{content:"\f0f4"}
1125 .icon-food:before{content:"\f0f5"}
1125 .icon-food:before{content:"\f0f5"}
1126 .icon-file-text-alt:before{content:"\f0f6"}
1126 .icon-file-text-alt:before{content:"\f0f6"}
1127 .icon-building:before{content:"\f0f7"}
1127 .icon-building:before{content:"\f0f7"}
1128 .icon-hospital:before{content:"\f0f8"}
1128 .icon-hospital:before{content:"\f0f8"}
1129 .icon-ambulance:before{content:"\f0f9"}
1129 .icon-ambulance:before{content:"\f0f9"}
1130 .icon-medkit:before{content:"\f0fa"}
1130 .icon-medkit:before{content:"\f0fa"}
1131 .icon-fighter-jet:before{content:"\f0fb"}
1131 .icon-fighter-jet:before{content:"\f0fb"}
1132 .icon-beer:before{content:"\f0fc"}
1132 .icon-beer:before{content:"\f0fc"}
1133 .icon-h-sign:before{content:"\f0fd"}
1133 .icon-h-sign:before{content:"\f0fd"}
1134 .icon-plus-sign-alt:before{content:"\f0fe"}
1134 .icon-plus-sign-alt:before{content:"\f0fe"}
1135 .icon-double-angle-left:before{content:"\f100"}
1135 .icon-double-angle-left:before{content:"\f100"}
1136 .icon-double-angle-right:before{content:"\f101"}
1136 .icon-double-angle-right:before{content:"\f101"}
1137 .icon-double-angle-up:before{content:"\f102"}
1137 .icon-double-angle-up:before{content:"\f102"}
1138 .icon-double-angle-down:before{content:"\f103"}
1138 .icon-double-angle-down:before{content:"\f103"}
1139 .icon-angle-left:before{content:"\f104"}
1139 .icon-angle-left:before{content:"\f104"}
1140 .icon-angle-right:before{content:"\f105"}
1140 .icon-angle-right:before{content:"\f105"}
1141 .icon-angle-up:before{content:"\f106"}
1141 .icon-angle-up:before{content:"\f106"}
1142 .icon-angle-down:before{content:"\f107"}
1142 .icon-angle-down:before{content:"\f107"}
1143 .icon-desktop:before{content:"\f108"}
1143 .icon-desktop:before{content:"\f108"}
1144 .icon-laptop:before{content:"\f109"}
1144 .icon-laptop:before{content:"\f109"}
1145 .icon-tablet:before{content:"\f10a"}
1145 .icon-tablet:before{content:"\f10a"}
1146 .icon-mobile-phone:before{content:"\f10b"}
1146 .icon-mobile-phone:before{content:"\f10b"}
1147 .icon-circle-blank:before{content:"\f10c"}
1147 .icon-circle-blank:before{content:"\f10c"}
1148 .icon-quote-left:before{content:"\f10d"}
1148 .icon-quote-left:before{content:"\f10d"}
1149 .icon-quote-right:before{content:"\f10e"}
1149 .icon-quote-right:before{content:"\f10e"}
1150 .icon-spinner:before{content:"\f110"}
1150 .icon-spinner:before{content:"\f110"}
1151 .icon-circle:before{content:"\f111"}
1151 .icon-circle:before{content:"\f111"}
1152 .icon-mail-reply:before,.icon-reply:before{content:"\f112"}
1152 .icon-mail-reply:before,.icon-reply:before{content:"\f112"}
1153 .icon-github-alt:before{content:"\f113"}
1153 .icon-github-alt:before{content:"\f113"}
1154 .icon-folder-close-alt:before{content:"\f114"}
1154 .icon-folder-close-alt:before{content:"\f114"}
1155 .icon-folder-open-alt:before{content:"\f115"}
1155 .icon-folder-open-alt:before{content:"\f115"}
1156 .icon-expand-alt:before{content:"\f116"}
1156 .icon-expand-alt:before{content:"\f116"}
1157 .icon-collapse-alt:before{content:"\f117"}
1157 .icon-collapse-alt:before{content:"\f117"}
1158 .icon-smile:before{content:"\f118"}
1158 .icon-smile:before{content:"\f118"}
1159 .icon-frown:before{content:"\f119"}
1159 .icon-frown:before{content:"\f119"}
1160 .icon-meh:before{content:"\f11a"}
1160 .icon-meh:before{content:"\f11a"}
1161 .icon-gamepad:before{content:"\f11b"}
1161 .icon-gamepad:before{content:"\f11b"}
1162 .icon-keyboard:before{content:"\f11c"}
1162 .icon-keyboard:before{content:"\f11c"}
1163 .icon-flag-alt:before{content:"\f11d"}
1163 .icon-flag-alt:before{content:"\f11d"}
1164 .icon-flag-checkered:before{content:"\f11e"}
1164 .icon-flag-checkered:before{content:"\f11e"}
1165 .icon-terminal:before{content:"\f120"}
1165 .icon-terminal:before{content:"\f120"}
1166 .icon-code:before{content:"\f121"}
1166 .icon-code:before{content:"\f121"}
1167 .icon-reply-all:before{content:"\f122"}
1167 .icon-reply-all:before{content:"\f122"}
1168 .icon-mail-reply-all:before{content:"\f122"}
1168 .icon-mail-reply-all:before{content:"\f122"}
1169 .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}
1169 .icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}
1170 .icon-location-arrow:before{content:"\f124"}
1170 .icon-location-arrow:before{content:"\f124"}
1171 .icon-crop:before{content:"\f125"}
1171 .icon-crop:before{content:"\f125"}
1172 .icon-code-fork:before{content:"\f126"}
1172 .icon-code-fork:before{content:"\f126"}
1173 .icon-unlink:before{content:"\f127"}
1173 .icon-unlink:before{content:"\f127"}
1174 .icon-question:before{content:"\f128"}
1174 .icon-question:before{content:"\f128"}
1175 .icon-info:before{content:"\f129"}
1175 .icon-info:before{content:"\f129"}
1176 .icon-exclamation:before{content:"\f12a"}
1176 .icon-exclamation:before{content:"\f12a"}
1177 .icon-superscript:before{content:"\f12b"}
1177 .icon-superscript:before{content:"\f12b"}
1178 .icon-subscript:before{content:"\f12c"}
1178 .icon-subscript:before{content:"\f12c"}
1179 .icon-eraser:before{content:"\f12d"}
1179 .icon-eraser:before{content:"\f12d"}
1180 .icon-puzzle-piece:before{content:"\f12e"}
1180 .icon-puzzle-piece:before{content:"\f12e"}
1181 .icon-microphone:before{content:"\f130"}
1181 .icon-microphone:before{content:"\f130"}
1182 .icon-microphone-off:before{content:"\f131"}
1182 .icon-microphone-off:before{content:"\f131"}
1183 .icon-shield:before{content:"\f132"}
1183 .icon-shield:before{content:"\f132"}
1184 .icon-calendar-empty:before{content:"\f133"}
1184 .icon-calendar-empty:before{content:"\f133"}
1185 .icon-fire-extinguisher:before{content:"\f134"}
1185 .icon-fire-extinguisher:before{content:"\f134"}
1186 .icon-rocket:before{content:"\f135"}
1186 .icon-rocket:before{content:"\f135"}
1187 .icon-maxcdn:before{content:"\f136"}
1187 .icon-maxcdn:before{content:"\f136"}
1188 .icon-chevron-sign-left:before{content:"\f137"}
1188 .icon-chevron-sign-left:before{content:"\f137"}
1189 .icon-chevron-sign-right:before{content:"\f138"}
1189 .icon-chevron-sign-right:before{content:"\f138"}
1190 .icon-chevron-sign-up:before{content:"\f139"}
1190 .icon-chevron-sign-up:before{content:"\f139"}
1191 .icon-chevron-sign-down:before{content:"\f13a"}
1191 .icon-chevron-sign-down:before{content:"\f13a"}
1192 .icon-html5:before{content:"\f13b"}
1192 .icon-html5:before{content:"\f13b"}
1193 .icon-css3:before{content:"\f13c"}
1193 .icon-css3:before{content:"\f13c"}
1194 .icon-anchor:before{content:"\f13d"}
1194 .icon-anchor:before{content:"\f13d"}
1195 .icon-unlock-alt:before{content:"\f13e"}
1195 .icon-unlock-alt:before{content:"\f13e"}
1196 .icon-bullseye:before{content:"\f140"}
1196 .icon-bullseye:before{content:"\f140"}
1197 .icon-ellipsis-horizontal:before{content:"\f141"}
1197 .icon-ellipsis-horizontal:before{content:"\f141"}
1198 .icon-ellipsis-vertical:before{content:"\f142"}
1198 .icon-ellipsis-vertical:before{content:"\f142"}
1199 .icon-rss-sign:before{content:"\f143"}
1199 .icon-rss-sign:before{content:"\f143"}
1200 .icon-play-sign:before{content:"\f144"}
1200 .icon-play-sign:before{content:"\f144"}
1201 .icon-ticket:before{content:"\f145"}
1201 .icon-ticket:before{content:"\f145"}
1202 .icon-minus-sign-alt:before{content:"\f146"}
1202 .icon-minus-sign-alt:before{content:"\f146"}
1203 .icon-check-minus:before{content:"\f147"}
1203 .icon-check-minus:before{content:"\f147"}
1204 .icon-level-up:before{content:"\f148"}
1204 .icon-level-up:before{content:"\f148"}
1205 .icon-level-down:before{content:"\f149"}
1205 .icon-level-down:before{content:"\f149"}
1206 .icon-check-sign:before{content:"\f14a"}
1206 .icon-check-sign:before{content:"\f14a"}
1207 .icon-edit-sign:before{content:"\f14b"}
1207 .icon-edit-sign:before{content:"\f14b"}
1208 .icon-external-link-sign:before{content:"\f14c"}
1208 .icon-external-link-sign:before{content:"\f14c"}
1209 .icon-share-sign:before{content:"\f14d"}
1209 .icon-share-sign:before{content:"\f14d"}
1210 .icon-compass:before{content:"\f14e"}
1210 .icon-compass:before{content:"\f14e"}
1211 .icon-collapse:before{content:"\f150"}
1211 .icon-collapse:before{content:"\f150"}
1212 .icon-collapse-top:before{content:"\f151"}
1212 .icon-collapse-top:before{content:"\f151"}
1213 .icon-expand:before{content:"\f152"}
1213 .icon-expand:before{content:"\f152"}
1214 .icon-euro:before,.icon-eur:before{content:"\f153"}
1214 .icon-euro:before,.icon-eur:before{content:"\f153"}
1215 .icon-gbp:before{content:"\f154"}
1215 .icon-gbp:before{content:"\f154"}
1216 .icon-dollar:before,.icon-usd:before{content:"\f155"}
1216 .icon-dollar:before,.icon-usd:before{content:"\f155"}
1217 .icon-rupee:before,.icon-inr:before{content:"\f156"}
1217 .icon-rupee:before,.icon-inr:before{content:"\f156"}
1218 .icon-yen:before,.icon-jpy:before{content:"\f157"}
1218 .icon-yen:before,.icon-jpy:before{content:"\f157"}
1219 .icon-renminbi:before,.icon-cny:before{content:"\f158"}
1219 .icon-renminbi:before,.icon-cny:before{content:"\f158"}
1220 .icon-won:before,.icon-krw:before{content:"\f159"}
1220 .icon-won:before,.icon-krw:before{content:"\f159"}
1221 .icon-bitcoin:before,.icon-btc:before{content:"\f15a"}
1221 .icon-bitcoin:before,.icon-btc:before{content:"\f15a"}
1222 .icon-file:before{content:"\f15b"}
1222 .icon-file:before{content:"\f15b"}
1223 .icon-file-text:before{content:"\f15c"}
1223 .icon-file-text:before{content:"\f15c"}
1224 .icon-sort-by-alphabet:before{content:"\f15d"}
1224 .icon-sort-by-alphabet:before{content:"\f15d"}
1225 .icon-sort-by-alphabet-alt:before{content:"\f15e"}
1225 .icon-sort-by-alphabet-alt:before{content:"\f15e"}
1226 .icon-sort-by-attributes:before{content:"\f160"}
1226 .icon-sort-by-attributes:before{content:"\f160"}
1227 .icon-sort-by-attributes-alt:before{content:"\f161"}
1227 .icon-sort-by-attributes-alt:before{content:"\f161"}
1228 .icon-sort-by-order:before{content:"\f162"}
1228 .icon-sort-by-order:before{content:"\f162"}
1229 .icon-sort-by-order-alt:before{content:"\f163"}
1229 .icon-sort-by-order-alt:before{content:"\f163"}
1230 .icon-thumbs-up:before{content:"\f164"}
1230 .icon-thumbs-up:before{content:"\f164"}
1231 .icon-thumbs-down:before{content:"\f165"}
1231 .icon-thumbs-down:before{content:"\f165"}
1232 .icon-youtube-sign:before{content:"\f166"}
1232 .icon-youtube-sign:before{content:"\f166"}
1233 .icon-youtube:before{content:"\f167"}
1233 .icon-youtube:before{content:"\f167"}
1234 .icon-xing:before{content:"\f168"}
1234 .icon-xing:before{content:"\f168"}
1235 .icon-xing-sign:before{content:"\f169"}
1235 .icon-xing-sign:before{content:"\f169"}
1236 .icon-youtube-play:before{content:"\f16a"}
1236 .icon-youtube-play:before{content:"\f16a"}
1237 .icon-dropbox:before{content:"\f16b"}
1237 .icon-dropbox:before{content:"\f16b"}
1238 .icon-stackexchange:before{content:"\f16c"}
1238 .icon-stackexchange:before{content:"\f16c"}
1239 .icon-instagram:before{content:"\f16d"}
1239 .icon-instagram:before{content:"\f16d"}
1240 .icon-flickr:before{content:"\f16e"}
1240 .icon-flickr:before{content:"\f16e"}
1241 .icon-adn:before{content:"\f170"}
1241 .icon-adn:before{content:"\f170"}
1242 .icon-bitbucket:before{content:"\f171"}
1242 .icon-bitbucket:before{content:"\f171"}
1243 .icon-bitbucket-sign:before{content:"\f172"}
1243 .icon-bitbucket-sign:before{content:"\f172"}
1244 .icon-tumblr:before{content:"\f173"}
1244 .icon-tumblr:before{content:"\f173"}
1245 .icon-tumblr-sign:before{content:"\f174"}
1245 .icon-tumblr-sign:before{content:"\f174"}
1246 .icon-long-arrow-down:before{content:"\f175"}
1246 .icon-long-arrow-down:before{content:"\f175"}
1247 .icon-long-arrow-up:before{content:"\f176"}
1247 .icon-long-arrow-up:before{content:"\f176"}
1248 .icon-long-arrow-left:before{content:"\f177"}
1248 .icon-long-arrow-left:before{content:"\f177"}
1249 .icon-long-arrow-right:before{content:"\f178"}
1249 .icon-long-arrow-right:before{content:"\f178"}
1250 .icon-apple:before{content:"\f179"}
1250 .icon-apple:before{content:"\f179"}
1251 .icon-windows:before{content:"\f17a"}
1251 .icon-windows:before{content:"\f17a"}
1252 .icon-android:before{content:"\f17b"}
1252 .icon-android:before{content:"\f17b"}
1253 .icon-linux:before{content:"\f17c"}
1253 .icon-linux:before{content:"\f17c"}
1254 .icon-dribbble:before{content:"\f17d"}
1254 .icon-dribbble:before{content:"\f17d"}
1255 .icon-skype:before{content:"\f17e"}
1255 .icon-skype:before{content:"\f17e"}
1256 .icon-foursquare:before{content:"\f180"}
1256 .icon-foursquare:before{content:"\f180"}
1257 .icon-trello:before{content:"\f181"}
1257 .icon-trello:before{content:"\f181"}
1258 .icon-female:before{content:"\f182"}
1258 .icon-female:before{content:"\f182"}
1259 .icon-male:before{content:"\f183"}
1259 .icon-male:before{content:"\f183"}
1260 .icon-gittip:before{content:"\f184"}
1260 .icon-gittip:before{content:"\f184"}
1261 .icon-sun:before{content:"\f185"}
1261 .icon-sun:before{content:"\f185"}
1262 .icon-moon:before{content:"\f186"}
1262 .icon-moon:before{content:"\f186"}
1263 .icon-archive:before{content:"\f187"}
1263 .icon-archive:before{content:"\f187"}
1264 .icon-bug:before{content:"\f188"}
1264 .icon-bug:before{content:"\f188"}
1265 .icon-vk:before{content:"\f189"}
1265 .icon-vk:before{content:"\f189"}
1266 .icon-weibo:before{content:"\f18a"}
1266 .icon-weibo:before{content:"\f18a"}
1267 .icon-renren:before{content:"\f18b"}
1267 .icon-renren:before{content:"\f18b"}
1268 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1268 .border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1269 .corner-all{border-radius:4px}
1269 .corner-all{border-radius:4px}
1270 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1270 .hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1271 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:auto}
1271 .hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:auto}
1272 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1272 .vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1273 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:auto}
1273 .vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:auto}
1274 .reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:column-reverse}
1274 .reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:column-reverse}
1275 .box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:auto}
1275 .box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:auto}
1276 .box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1276 .box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1277 .box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1277 .box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1278 .box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1278 .box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1279 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
1279 .box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}
1280 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
1280 .box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}
1281 .start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
1281 .start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}
1282 .end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
1282 .end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}
1283 .center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
1283 .center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}
1284 .align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-content:flex-start}
1284 .align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-content:flex-start}
1285 .align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-content:flex-end}
1285 .align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-content:flex-end}
1286 .align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-content:center}
1286 .align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-content:center}
1287 div.error{margin:2em;text-align:center}
1287 div.error{margin:2em;text-align:center}
1288 div.error>h1{font-size:500%;line-height:normal}
1288 div.error>h1{font-size:500%;line-height:normal}
1289 div.error>p{font-size:200%;line-height:normal}
1289 div.error>p{font-size:200%;line-height:normal}
1290 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
1290 div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}
1291 body{background-color:#fff;position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}
1291 body{background-color:#fff;position:absolute;left:0;right:0;top:0;bottom:0;overflow:visible}
1292 div#header{display:none}
1292 div#header{display:none}
1293 #ipython_notebook{padding-left:16px}
1293 #ipython_notebook{padding-left:16px}
1294 #noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:#f00;font-weight:bold}
1294 #noscript{width:auto;padding-top:16px;padding-bottom:16px;text-align:center;font-size:22px;color:#f00;font-weight:bold}
1295 #ipython_notebook img{font-family:Verdana,"Helvetica Neue",Arial,Helvetica,Geneva,sans-serif;height:24px;text-decoration:none;color:#000}
1295 #ipython_notebook img{font-family:Verdana,"Helvetica Neue",Arial,Helvetica,Geneva,sans-serif;height:24px;text-decoration:none;color:#000}
1296 #site{width:100%;display:none}
1296 #site{width:100%;display:none}
1297 .ui-button .ui-button-text{padding:.2em .8em;font-size:77%}
1297 .ui-button .ui-button-text{padding:.2em .8em;font-size:77%}
1298 input.ui-button{padding:.3em .9em}
1298 input.ui-button{padding:.3em .9em}
1299 .navbar span{margin-top:3px}
1299 .navbar span{margin-top:3px}
1300 span#login_widget{float:right}
1300 span#login_widget{float:right}
1301 .nav-header{text-transform:none}
1301 .nav-header{text-transform:none}
1302 .navbar-nobg{background-color:transparent;background-image:none}
1302 .navbar-nobg{background-color:transparent;background-image:none}
1303 #header>span{margin-top:10px}
1303 #header>span{margin-top:10px}
1304 .modal-body{max-height:500px}
1304 .modal-body{max-height:500px}
1305 .center-nav{display:inline-block;margin-bottom:-4px}
1305 .center-nav{display:inline-block;margin-bottom:-4px}
1306 .alternate_upload{background-color:none;display:inline}
1306 .alternate_upload{background-color:none;display:inline}
1307 .alternate_upload.form{padding:0;margin:0}
1307 .alternate_upload.form{padding:0;margin:0}
1308 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
1308 .alternate_upload input.fileinput{background-color:#f00;position:relative;opacity:0;z-index:2;width:295px;margin-left:163px;cursor:pointer;height:26px}
1309 ul#tabs{margin-bottom:4px}
1309 ul#tabs{margin-bottom:4px}
1310 ul#tabs a{padding-top:4px;padding-bottom:4px}
1310 ul#tabs a{padding-top:4px;padding-bottom:4px}
1311 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
1311 ul.breadcrumb a:focus,ul.breadcrumb a:hover{text-decoration:none}
1312 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
1312 ul.breadcrumb i.icon-home{font-size:16px;margin-right:4px}
1313 ul.breadcrumb span{color:#5e5e5e}
1313 ul.breadcrumb span{color:#5e5e5e}
1314 .list_toolbar{padding:4px 0 4px 0}
1314 .list_toolbar{padding:4px 0 4px 0}
1315 .list_toolbar [class*="span"]{min-height:26px}
1315 .list_toolbar [class*="span"]{min-height:26px}
1316 .list_header{font-weight:bold}
1316 .list_header{font-weight:bold}
1317 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
1317 .list_container{margin-top:4px;margin-bottom:20px;border:1px solid #ababab;border-radius:4px}
1318 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
1318 .list_container>div{border-bottom:1px solid #ababab}.list_container>div:hover .list-item{background-color:#f00}
1319 .list_container>div:last-child{border:none}
1319 .list_container>div:last-child{border:none}
1320 .list_item:hover .list_item{background-color:#ddd}
1320 .list_item:hover .list_item{background-color:#ddd}
1321 .list_item a{text-decoration:none}
1321 .list_item a{text-decoration:none}
1322 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
1322 .list_header>div,.list_item>div{padding-top:4px;padding-bottom:4px;padding-left:7px;padding-right:7px;height:22px;line-height:22px}
1323 .item_name{line-height:22px;height:26px}
1323 .item_name{line-height:22px;height:26px}
1324 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
1324 .item_icon{font-size:14px;color:#5e5e5e;margin-right:7px}
1325 .item_buttons{line-height:1em}
1325 .item_buttons{line-height:1em}
1326 .toolbar_info{height:26px;line-height:26px}
1326 .toolbar_info{height:26px;line-height:26px}
1327 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
1327 input.nbname_input,input.engine_num_input{padding-top:3px;padding-bottom:3px;height:14px;line-height:14px;margin:0}
1328 input.engine_num_input{width:60px}
1328 input.engine_num_input{width:60px}
1329 .highlight_text{color:#00f}
1329 .highlight_text{color:#00f}
1330 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
1330 #project_name>.breadcrumb{padding:0;margin-bottom:0;background-color:transparent;font-weight:bold}
1331 .ansibold{font-weight:bold}
1331 .ansibold{font-weight:bold}
1332 .ansiblack{color:#000}
1332 .ansiblack{color:#000}
1333 .ansired{color:#8b0000}
1333 .ansired{color:#8b0000}
1334 .ansigreen{color:#006400}
1334 .ansigreen{color:#006400}
1335 .ansiyellow{color:#a52a2a}
1335 .ansiyellow{color:#a52a2a}
1336 .ansiblue{color:#00008b}
1336 .ansiblue{color:#00008b}
1337 .ansipurple{color:#9400d3}
1337 .ansipurple{color:#9400d3}
1338 .ansicyan{color:#4682b4}
1338 .ansicyan{color:#4682b4}
1339 .ansigray{color:#808080}
1339 .ansigray{color:#808080}
1340 .ansibgblack{background-color:#000}
1340 .ansibgblack{background-color:#000}
1341 .ansibgred{background-color:#f00}
1341 .ansibgred{background-color:#f00}
1342 .ansibggreen{background-color:#008000}
1342 .ansibggreen{background-color:#008000}
1343 .ansibgyellow{background-color:#ff0}
1343 .ansibgyellow{background-color:#ff0}
1344 .ansibgblue{background-color:#00f}
1344 .ansibgblue{background-color:#00f}
1345 .ansibgpurple{background-color:#f0f}
1345 .ansibgpurple{background-color:#f0f}
1346 .ansibgcyan{background-color:#0ff}
1346 .ansibgcyan{background-color:#0ff}
1347 .ansibggray{background-color:#808080}
1347 .ansibggray{background-color:#808080}
1348 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
1348 div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}div.cell.selected{border-radius:4px;border:thin #ababab solid}
1349 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
1349 div.cell.edit_mode{border-radius:4px;border:thin #008000 solid}
1350 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
1350 div.cell{width:100%;padding:5px 5px 5px 0;margin:0;outline:none}
1351 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.231em}
1351 div.prompt{min-width:11ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.231em}
1352 div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1352 div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1353 div.prompt:empty{padding-top:0;padding-bottom:0}
1353 div.prompt:empty{padding-top:0;padding-bottom:0}
1354 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1354 div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1355 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1355 div.input_area{border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1356 div.input_prompt{color:#000080;border-top:1px solid transparent}
1356 div.input_prompt{color:#000080;border-top:1px solid transparent}
1357 .CodeMirror{line-height:1.231em;height:auto;background:none;}
1357 .CodeMirror{line-height:1.231em;height:auto;background:none;}
1358 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
1358 .CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}
1359 @-moz-document {.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
1359 @-moz-document {.CodeMirror-scroll{overflow-x:hidden}}.CodeMirror-lines{padding:.4em}
1360 .CodeMirror-linenumber{padding:0 8px 0 4px}
1360 .CodeMirror-linenumber{padding:0 8px 0 4px}
1361 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
1361 .CodeMirror-gutters{border-bottom-left-radius:4px;border-top-left-radius:4px}
1362 .CodeMirror pre{padding:0;border:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
1362 .CodeMirror pre{padding:0;border:0;border-radius:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
1363 pre code{display:block;padding:.5em}
1363 pre code{display:block;padding:.5em}
1364 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
1364 .highlight-base,pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{color:#000}
1365 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
1365 .highlight-string,pre .string,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{color:#ba2121}
1366 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
1366 .highlight-comment,pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{color:#408080;font-style:italic}
1367 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
1367 .highlight-number,pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{color:#080}
1368 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
1368 pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{color:#88f}
1369 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
1369 .highlight-keyword,pre .keyword,pre .id,pre .phpdoc,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status{color:#008000;font-weight:bold}
1370 .highlight-builtin,pre .built_in{color:#008000}
1370 .highlight-builtin,pre .built_in{color:#008000}
1371 pre .markdown .emphasis{font-style:italic}
1371 pre .markdown .emphasis{font-style:italic}
1372 pre .nginx .built_in{font-weight:normal}
1372 pre .nginx .built_in{font-weight:normal}
1373 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
1373 pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{opacity:.5}
1374 .cm-s-ipython span.cm-variable{color:#000}
1374 .cm-s-ipython span.cm-variable{color:#000}
1375 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
1375 .cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}
1376 .cm-s-ipython span.cm-number{color:#080}
1376 .cm-s-ipython span.cm-number{color:#080}
1377 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
1377 .cm-s-ipython span.cm-comment{color:#408080;font-style:italic}
1378 .cm-s-ipython span.cm-string{color:#ba2121}
1378 .cm-s-ipython span.cm-string{color:#ba2121}
1379 .cm-s-ipython span.cm-builtin{color:#008000}
1379 .cm-s-ipython span.cm-builtin{color:#008000}
1380 .cm-s-ipython span.cm-error{color:#f00}
1380 .cm-s-ipython span.cm-error{color:#f00}
1381 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
1381 .cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}
1382 .cm-s-ipython span.cm-meta{color:#a2f}
1382 .cm-s-ipython span.cm-meta{color:#a2f}
1383 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
1383 .cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}
1384 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1384 div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1385 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8)}
1385 div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:4px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);-moz-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8)}
1386 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1386 div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1387 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
1387 div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:4px}
1388 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
1388 div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;-moz-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}
1389 div.output_prompt{color:#8b0000}
1389 div.output_prompt{color:#8b0000}
1390 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
1390 div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}
1391 div.output_area .rendered_html table{margin-left:0;margin-right:0}
1391 div.output_area .rendered_html table{margin-left:0;margin-right:0}
1392 div.output_area .rendered_html img{margin-left:0;margin-right:0}
1392 div.output_area .rendered_html img{margin-left:0;margin-right:0}
1393 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1393 .output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1394 div.output_area pre{font-family:monospace;margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
1394 div.output_area pre{font-family:monospace;margin:0;padding:0;border:0;font-size:100%;vertical-align:baseline;color:#000;background-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;line-height:inherit}
1395 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1395 div.output_subarea{padding:.4em .4em 0 .4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}
1396 div.output_text{text-align:left;color:#000;font-family:monospace;line-height:1.231em}
1396 div.output_text{text-align:left;color:#000;font-family:monospace;line-height:1.231em}
1397 div.output_stderr{background:#fdd;}
1397 div.output_stderr{background:#fdd;}
1398 div.output_latex{text-align:left}
1398 div.output_latex{text-align:left}
1399 div.output_javascript:empty{padding:0}
1399 div.output_javascript:empty{padding:0}
1400 .js-error{color:#8b0000}
1400 .js-error{color:#8b0000}
1401 div.raw_input{padding-top:0;padding-bottom:0;height:1em;line-height:1em;font-family:monospace}
1401 div.raw_input{padding-top:0;padding-bottom:0;height:1em;line-height:1em;font-family:monospace}
1402 span.input_prompt{font-family:inherit}
1402 span.input_prompt{font-family:inherit}
1403 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;margin:-2px 0 0 1px;padding-left:1px;padding-top:2px;height:1em}
1403 input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;margin:-2px 0 0 1px;padding-left:1px;padding-top:2px;height:1em}
1404 p.p-space{margin-bottom:10px}
1404 p.p-space{margin-bottom:10px}
1405 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
1405 .rendered_html{color:#000;}.rendered_html em{font-style:italic}
1406 .rendered_html strong{font-weight:bold}
1406 .rendered_html strong{font-weight:bold}
1407 .rendered_html u{text-decoration:underline}
1407 .rendered_html u{text-decoration:underline}
1408 .rendered_html :link{text-decoration:underline}
1408 .rendered_html :link{text-decoration:underline}
1409 .rendered_html :visited{text-decoration:underline}
1409 .rendered_html :visited{text-decoration:underline}
1410 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
1410 .rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}
1411 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
1411 .rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}
1412 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
1412 .rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}
1413 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
1413 .rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}
1414 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1414 .rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1415 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1415 .rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}
1416 .rendered_html h1:first-child{margin-top:.538em}
1416 .rendered_html h1:first-child{margin-top:.538em}
1417 .rendered_html h2:first-child{margin-top:.636em}
1417 .rendered_html h2:first-child{margin-top:.636em}
1418 .rendered_html h3:first-child{margin-top:.777em}
1418 .rendered_html h3:first-child{margin-top:.777em}
1419 .rendered_html h4:first-child{margin-top:1em}
1419 .rendered_html h4:first-child{margin-top:1em}
1420 .rendered_html h5:first-child{margin-top:1em}
1420 .rendered_html h5:first-child{margin-top:1em}
1421 .rendered_html h6:first-child{margin-top:1em}
1421 .rendered_html h6:first-child{margin-top:1em}
1422 .rendered_html ul{list-style:disc;margin:0 2em}
1422 .rendered_html ul{list-style:disc;margin:0 2em}
1423 .rendered_html ul ul{list-style:square;margin:0 2em}
1423 .rendered_html ul ul{list-style:square;margin:0 2em}
1424 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
1424 .rendered_html ul ul ul{list-style:circle;margin:0 2em}
1425 .rendered_html ol{list-style:decimal;margin:0 2em}
1425 .rendered_html ol{list-style:decimal;margin:0 2em}
1426 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
1426 .rendered_html ol ol{list-style:upper-alpha;margin:0 2em}
1427 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
1427 .rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}
1428 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
1428 .rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}
1429 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
1429 .rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}
1430 .rendered_html *+ul{margin-top:1em}
1430 .rendered_html *+ul{margin-top:1em}
1431 .rendered_html *+ol{margin-top:1em}
1431 .rendered_html *+ol{margin-top:1em}
1432 .rendered_html hr{color:#000;background-color:#000}
1432 .rendered_html hr{color:#000;background-color:#000}
1433 .rendered_html pre{margin:1em 2em}
1433 .rendered_html pre{margin:1em 2em}
1434 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
1434 .rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}
1435 .rendered_html blockquote{margin:1em 2em}
1435 .rendered_html blockquote{margin:1em 2em}
1436 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
1436 .rendered_html table{margin-left:auto;margin-right:auto;border:1px solid #000;border-collapse:collapse}
1437 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
1437 .rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid #000;border-collapse:collapse;margin:1em 2em}
1438 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
1438 .rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}
1439 .rendered_html th{font-weight:bold}
1439 .rendered_html th{font-weight:bold}
1440 .rendered_html *+table{margin-top:1em}
1440 .rendered_html *+table{margin-top:1em}
1441 .rendered_html p{text-align:justify}
1441 .rendered_html p{text-align:justify}
1442 .rendered_html *+p{margin-top:1em}
1442 .rendered_html *+p{margin-top:1em}
1443 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
1443 .rendered_html img{display:block;margin-left:auto;margin-right:auto}
1444 .rendered_html *+img{margin-top:1em}
1444 .rendered_html *+img{margin-top:1em}
1445 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1445 div.text_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1446 div.text_cell_input{color:#000;border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1446 div.text_cell_input{color:#000;border:1px solid #cfcfcf;border-radius:4px;background:#f7f7f7}
1447 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
1447 div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000}
1448 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
1448 a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}
1449 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
1449 h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}
1450 div.cell.text_cell.rendered{padding:0}
1450 div.cell.text_cell.rendered{padding:0}
1451 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1451 .widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}
1452 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
1452 .widget-hlabel{min-width:10ex;padding-right:8px;padding-top:3px;text-align:right;vertical-align:text-top}
1453 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
1453 .widget-vlabel{padding-bottom:5px;text-align:center;vertical-align:text-bottom}
1454 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
1454 .widget-hreadout{padding-left:8px;padding-top:3px;text-align:left;vertical-align:text-top}
1455 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
1455 .widget-vreadout{padding-top:5px;text-align:center;vertical-align:text-top}
1456 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
1456 .slide-track{border:1px solid #ccc;background:#fff;border-radius:4px;}
1457 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
1457 .widget-hslider{padding-left:8px;padding-right:5px;overflow:visible;width:348px;height:5px;max-height:5px;margin-top:11px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0 !important;background:none !important;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:14px !important;height:28px !important;margin-top:-8px !important}
1458 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
1458 .widget-vslider{padding-bottom:8px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:4px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0 !important;background:none !important;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px !important;height:14px !important;margin-left:-9px}
1459 .widget-text{width:350px;margin-bottom:0}
1459 .widget-text{width:350px;margin-bottom:0}
1460 .widget-listbox{width:364px;margin-bottom:0}
1460 .widget-listbox{width:364px;margin-bottom:0}
1461 .widget-numeric-text{width:150px}
1461 .widget-numeric-text{width:150px}
1462 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
1462 .widget-progress{width:363px}.widget-progress .bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}
1463 .widget-combo-btn{min-width:138px;}
1463 .widget-combo-btn{min-width:138px;}
1464 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1464 .widget-box{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1465 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1465 .widget-hbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}
1466 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
1466 .widget-hbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;height:30px}
1467 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1467 .widget-vbox{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch}
1468 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
1468 .widget-vbox-single{margin:5px;-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;width:100%;display:flex;flex-direction:column;align-items:stretch;width:30px}
1469 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
1469 .widget-modal{overflow:hidden;position:absolute !important;top:0;left:0;margin-left:0 !important}
1470 .widget-modal-body{max-height:none !important}
1470 .widget-modal-body{max-height:none !important}
1471 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1471 .widget-container{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1472 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
1472 .docked-widget-modal{overflow:hidden;position:relative !important;top:0 !important;left:0 !important;margin-left:0 !important}
1473 body{background-color:#fff}
1473 body{background-color:#fff}
1474 body.notebook_app{overflow:hidden}
1474 body.notebook_app{overflow:hidden}
1475 span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%}
1475 span#notebook_name{height:1em;line-height:1em;padding:3px;border:none;font-size:146.5%}
1476 div#notebook_panel{margin:0 0 0 0;padding:0;-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}
1476 div#notebook_panel{margin:0 0 0 0;padding:0;-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}
1477 div#notebook{overflow-y:scroll;overflow-x:auto;width:100%;padding:1em 0 1em 0;margin:0;border-top:1px solid #ababab;outline:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1477 div#notebook{overflow-y:scroll;overflow-x:auto;width:100%;padding:1em 0 1em 0;margin:0;border-top:1px solid #ababab;outline:none;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}
1478 div.ui-widget-content{border:1px solid #ababab;outline:none}
1478 div.ui-widget-content{border:1px solid #ababab;outline:none}
1479 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:.4em;padding-left:2em}
1479 pre.dialog{background-color:#f7f7f7;border:1px solid #ddd;border-radius:4px;padding:.4em;padding-left:2em}
1480 p.dialog{padding:.2em}
1480 p.dialog{padding:.2em}
1481 pre,code,kbd,samp{white-space:pre-wrap}
1481 pre,code,kbd,samp{white-space:pre-wrap}
1482 #fonttest{font-family:monospace}
1482 #fonttest{font-family:monospace}
1483 p{margin-bottom:0}
1483 p{margin-bottom:0}
1484 .end_space{height:200px}
1484 .end_space{height:200px}
1485 .celltoolbar{border:thin solid #cfcfcf;border-bottom:none;background:#eee;border-radius:3px 3px 0 0;width:100%;-webkit-box-pack:end;height:22px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:column-reverse}
1485 .celltoolbar{border:thin solid #cfcfcf;border-bottom:none;background:#eee;border-radius:3px 3px 0 0;width:100%;-webkit-box-pack:end;height:22px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:column-reverse}
1486 .ctb_hideshow{display:none;vertical-align:bottom;padding-right:2px}
1486 .ctb_hideshow{display:none;vertical-align:bottom;padding-right:2px}
1487 .celltoolbar>div{padding-top:0}
1487 .celltoolbar>div{padding-top:0}
1488 .ctb_global_show .ctb_show.ctb_hideshow{display:block}
1488 .ctb_global_show .ctb_show.ctb_hideshow{display:block}
1489 .ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input{border-top-right-radius:0;border-top-left-radius:0}
1489 .ctb_global_show .ctb_show+.input_area,.ctb_global_show .ctb_show+div.text_cell_input{border-top-right-radius:0;border-top-left-radius:0}
1490 .celltoolbar .button_container select{margin:10px;margin-top:1px;margin-bottom:0;padding:0;font-size:87%;width:auto;display:inline-block;height:18px;line-height:18px;vertical-align:top}
1490 .celltoolbar .button_container select{margin:10px;margin-top:1px;margin-bottom:0;padding:0;font-size:87%;width:auto;display:inline-block;height:18px;line-height:18px;vertical-align:top}
1491 .celltoolbar label{display:inline-block;height:15px;line-height:15px;vertical-align:top}
1491 .celltoolbar label{display:inline-block;height:15px;line-height:15px;vertical-align:top}
1492 .celltoolbar label span{font-size:85%}
1492 .celltoolbar label span{font-size:85%}
1493 .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px}
1493 .celltoolbar input[type=checkbox]{margin:0;margin-left:4px;margin-right:4px}
1494 .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px}
1494 .celltoolbar .ui-button{border:none;vertical-align:top;height:20px;min-width:30px}
1495 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:4px;-webkit-box-shadow:0 6px 10px -1px #adadad;-moz-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad}
1495 .completions{position:absolute;z-index:10;overflow:hidden;border:1px solid #ababab;border-radius:4px;-webkit-box-shadow:0 6px 10px -1px #adadad;-moz-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad}
1496 .completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000}
1496 .completions select{background:#fff;outline:none;border:none;padding:0;margin:0;overflow:auto;font-family:monospace;font-size:110%;color:#000}
1497 .completions select option.context{color:#0064cd}
1497 .completions select option.context{color:#0064cd}
1498 #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px}
1498 #menubar .navbar-inner{min-height:28px;border-top:1px;border-radius:0 0 4px 4px}
1499 #menubar .navbar{margin-bottom:8px}
1499 #menubar .navbar{margin-bottom:8px}
1500 .nav-wrapper{border-bottom:1px solid #d4d4d4}
1500 .nav-wrapper{border-bottom:1px solid #d4d4d4}
1501 #menubar li.dropdown{line-height:12px}
1501 #menubar li.dropdown{line-height:12px}
1502 i.menu-icon{padding-top:4px}
1502 i.menu-icon{padding-top:4px}
1503 ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}
1503 ul#help_menu li a{overflow:hidden;padding-right:2.2em}ul#help_menu li a i{margin-right:-1.2em}
1504 #notification_area{z-index:10}
1504 #notification_area{z-index:10}
1505 .indicator_area{color:#777;padding:4px 3px;margin:0;width:11px;z-index:10;text-align:center}
1506 #kernel_indicator{margin-right:-16px}
1505 .notification_widget{color:#777;padding:1px 12px;margin:2px 4px;z-index:10;border:1px solid #ccc;border-radius:4px;background:rgba(240,240,240,0.5)}.notification_widget.span{padding-right:2px}
1507 .notification_widget{color:#777;padding:1px 12px;margin:2px 4px;z-index:10;border:1px solid #ccc;border-radius:4px;background:rgba(240,240,240,0.5)}.notification_widget.span{padding-right:2px}
1506 #indicator_area{color:#777;padding:2px 2px;margin:2px -9px 2px 4px;z-index:10}
1507 div#pager_splitter{height:8px}
1508 div#pager_splitter{height:8px}
1508 #pager-container{position:relative;padding:15px 0}
1509 #pager-container{position:relative;padding:15px 0}
1509 div#pager{overflow:auto;display:none}div#pager pre{font-size:13px;line-height:1.231em;color:#000;background-color:#f7f7f7;padding:.4em}
1510 div#pager{overflow:auto;display:none}div#pager pre{font-size:13px;line-height:1.231em;color:#000;background-color:#f7f7f7;padding:.4em}
1510 .shortcut_key{display:inline-block;width:15ex;text-align:right;font-family:monospace}
1511 .shortcut_key{display:inline-block;width:15ex;text-align:right;font-family:monospace}
1511 .shortcut_descr{display:inline-block}
1512 .shortcut_descr{display:inline-block}
1512 span#save_widget{padding:0 5px;margin-top:12px}
1513 span#save_widget{padding:0 5px;margin-top:12px}
1513 span#checkpoint_status,span#autosave_status{font-size:small}
1514 span#checkpoint_status,span#autosave_status{font-size:small}
1514 @media (max-width:767px){span#save_widget{font-size:small} span#checkpoint_status,span#autosave_status{font-size:x-small}}@media (max-width:767px){span#checkpoint_status,span#autosave_status{display:none}}@media (min-width:768px) and (max-width:979px){span#checkpoint_status{display:none} span#autosave_status{font-size:x-small}}.toolbar{padding:0 10px;margin-top:-5px}.toolbar select,.toolbar label{width:auto;height:26px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:0;padding-top:3px}
1515 @media (max-width:767px){span#save_widget{font-size:small} span#checkpoint_status,span#autosave_status{font-size:x-small}}@media (max-width:767px){span#checkpoint_status,span#autosave_status{display:none}}@media (min-width:768px) and (max-width:979px){span#checkpoint_status{display:none} span#autosave_status{font-size:x-small}}.toolbar{padding:0 10px;margin-top:-5px}.toolbar select,.toolbar label{width:auto;height:26px;vertical-align:middle;margin-right:2px;margin-bottom:0;display:inline;font-size:92%;margin-left:.3em;margin-right:.3em;padding:0;padding-top:3px}
1515 .toolbar .btn{padding:2px 8px}
1516 .toolbar .btn{padding:2px 8px}
1516 .toolbar .btn-group{margin-top:0}
1517 .toolbar .btn-group{margin-top:0}
1517 .toolbar-inner{border:none !important;-webkit-box-shadow:none !important;-moz-box-shadow:none !important;box-shadow:none !important}
1518 .toolbar-inner{border:none !important;-webkit-box-shadow:none !important;-moz-box-shadow:none !important;box-shadow:none !important}
1518 #maintoolbar{margin-bottom:0}
1519 #maintoolbar{margin-bottom:0}
1519 @-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}
1520 @-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}
1520 .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}
1521 .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}
1521 .tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}
1522 .tooltipbuttons{position:absolute;padding-right:15px;top:0;right:0}
1522 .tooltiptext{padding-right:30px}
1523 .tooltiptext{padding-right:30px}
1523 .ipython_tooltip{max-width:700px;-webkit-animation:fadeOut 400ms;-moz-animation:fadeOut 400ms;animation:fadeOut 400ms;-webkit-animation:fadeIn 400ms;-moz-animation:fadeIn 400ms;animation:fadeIn 400ms;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:#ababab 1px solid;outline:none;padding:3px;margin:0;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:4px;position:absolute;z-index:2}.ipython_tooltip a{float:right}
1524 .ipython_tooltip{max-width:700px;-webkit-animation:fadeOut 400ms;-moz-animation:fadeOut 400ms;animation:fadeOut 400ms;-webkit-animation:fadeIn 400ms;-moz-animation:fadeIn 400ms;animation:fadeIn 400ms;vertical-align:middle;background-color:#f7f7f7;overflow:visible;border:#ababab 1px solid;outline:none;padding:3px;margin:0;padding-left:7px;font-family:monospace;min-height:50px;-moz-box-shadow:0 6px 10px -1px #adadad;-webkit-box-shadow:0 6px 10px -1px #adadad;box-shadow:0 6px 10px -1px #adadad;border-radius:4px;position:absolute;z-index:2}.ipython_tooltip a{float:right}
1524 .ipython_tooltip .tooltiptext pre{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;font-size:100%;background-color:#f7f7f7}
1525 .ipython_tooltip .tooltiptext pre{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;font-size:100%;background-color:#f7f7f7}
1525 .pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}
1526 .pretooltiparrow{left:0;margin:0;top:-16px;width:40px;height:16px;overflow:hidden;position:absolute}
1526 .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)}
1527 .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,199 +1,196 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // NotebookList
9 // NotebookList
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 ClusterList = function (selector) {
17 var ClusterList = function (selector, options) {
18 this.selector = selector;
18 this.selector = selector;
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
21 this.style();
21 this.style();
22 this.bind_events();
22 this.bind_events();
23 }
23 }
24 };
24 options = options || {};
25
25 this.options = options;
26 ClusterList.prototype.baseProjectUrl = function(){
26 this.base_url = options.base_url || utils.get_body_data("baseUrl");
27 return this._baseProjectUrl || $('body').data('baseProjectUrl');
27 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
28 };
28 };
29
29
30 ClusterList.prototype.style = function () {
30 ClusterList.prototype.style = function () {
31 $('#cluster_list').addClass('list_container');
31 $('#cluster_list').addClass('list_container');
32 $('#cluster_toolbar').addClass('list_toolbar');
32 $('#cluster_toolbar').addClass('list_toolbar');
33 $('#cluster_list_info').addClass('toolbar_info');
33 $('#cluster_list_info').addClass('toolbar_info');
34 $('#cluster_buttons').addClass('toolbar_buttons');
34 $('#cluster_buttons').addClass('toolbar_buttons');
35 };
35 };
36
36
37
37
38 ClusterList.prototype.bind_events = function () {
38 ClusterList.prototype.bind_events = function () {
39 var that = this;
39 var that = this;
40 $('#refresh_cluster_list').click(function () {
40 $('#refresh_cluster_list').click(function () {
41 that.load_list();
41 that.load_list();
42 });
42 });
43 };
43 };
44
44
45
45
46 ClusterList.prototype.load_list = function () {
46 ClusterList.prototype.load_list = function () {
47 var settings = {
47 var settings = {
48 processData : false,
48 processData : false,
49 cache : false,
49 cache : false,
50 type : "GET",
50 type : "GET",
51 dataType : "json",
51 dataType : "json",
52 success : $.proxy(this.load_list_success, this)
52 success : $.proxy(this.load_list_success, this)
53 };
53 };
54 var url = utils.url_join_encode(this.baseProjectUrl(), 'clusters');
54 var url = utils.url_join_encode(this.base_url, 'clusters');
55 $.ajax(url, settings);
55 $.ajax(url, settings);
56 };
56 };
57
57
58
58
59 ClusterList.prototype.clear_list = function () {
59 ClusterList.prototype.clear_list = function () {
60 this.element.children('.list_item').remove();
60 this.element.children('.list_item').remove();
61 };
61 };
62
62
63 ClusterList.prototype.load_list_success = function (data, status, xhr) {
63 ClusterList.prototype.load_list_success = function (data, status, xhr) {
64 this.clear_list();
64 this.clear_list();
65 var len = data.length;
65 var len = data.length;
66 for (var i=0; i<len; i++) {
66 for (var i=0; i<len; i++) {
67 var element = $('<div/>');
67 var element = $('<div/>');
68 var item = new ClusterItem(element);
68 var item = new ClusterItem(element, this.options);
69 item.update_state(data[i]);
69 item.update_state(data[i]);
70 element.data('item', item);
70 element.data('item', item);
71 this.element.append(element);
71 this.element.append(element);
72 }
72 }
73 };
73 };
74
74
75
75
76 var ClusterItem = function (element) {
76 var ClusterItem = function (element, options) {
77 this.element = $(element);
77 this.element = $(element);
78 this.base_url = options.base_url || utils.get_body_data("baseUrl");
79 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
78 this.data = null;
80 this.data = null;
79 this.style();
81 this.style();
80 };
82 };
81
83
82 ClusterItem.prototype.baseProjectUrl = function(){
83 return this._baseProjectUrl || $('body').data('baseProjectUrl');
84 };
85
86
87 ClusterItem.prototype.style = function () {
84 ClusterItem.prototype.style = function () {
88 this.element.addClass('list_item').addClass("row-fluid");
85 this.element.addClass('list_item').addClass("row-fluid");
89 };
86 };
90
87
91 ClusterItem.prototype.update_state = function (data) {
88 ClusterItem.prototype.update_state = function (data) {
92 this.data = data;
89 this.data = data;
93 if (data.status === 'running') {
90 if (data.status === 'running') {
94 this.state_running();
91 this.state_running();
95 } else if (data.status === 'stopped') {
92 } else if (data.status === 'stopped') {
96 this.state_stopped();
93 this.state_stopped();
97 }
94 }
98 };
95 };
99
96
100
97
101 ClusterItem.prototype.state_stopped = function () {
98 ClusterItem.prototype.state_stopped = function () {
102 var that = this;
99 var that = this;
103 var profile_col = $('<div/>').addClass('profile_col span4').text(this.data.profile);
100 var profile_col = $('<div/>').addClass('profile_col span4').text(this.data.profile);
104 var status_col = $('<div/>').addClass('status_col span3').text('stopped');
101 var status_col = $('<div/>').addClass('status_col span3').text('stopped');
105 var engines_col = $('<div/>').addClass('engine_col span3');
102 var engines_col = $('<div/>').addClass('engine_col span3');
106 var input = $('<input/>').attr('type','number')
103 var input = $('<input/>').attr('type','number')
107 .attr('min',1)
104 .attr('min',1)
108 .attr('size',3)
105 .attr('size',3)
109 .addClass('engine_num_input');
106 .addClass('engine_num_input');
110 engines_col.append(input);
107 engines_col.append(input);
111 var start_button = $('<button/>').addClass("btn btn-mini").text("Start");
108 var start_button = $('<button/>').addClass("btn btn-mini").text("Start");
112 var action_col = $('<div/>').addClass('action_col span2').append(
109 var action_col = $('<div/>').addClass('action_col span2').append(
113 $("<span/>").addClass("item_buttons btn-group").append(
110 $("<span/>").addClass("item_buttons btn-group").append(
114 start_button
111 start_button
115 )
112 )
116 );
113 );
117 this.element.empty()
114 this.element.empty()
118 .append(profile_col)
115 .append(profile_col)
119 .append(status_col)
116 .append(status_col)
120 .append(engines_col)
117 .append(engines_col)
121 .append(action_col);
118 .append(action_col);
122 start_button.click(function (e) {
119 start_button.click(function (e) {
123 var n = that.element.find('.engine_num_input').val();
120 var n = that.element.find('.engine_num_input').val();
124 if (!/^\d+$/.test(n) && n.length>0) {
121 if (!/^\d+$/.test(n) && n.length>0) {
125 status_col.text('invalid engine #');
122 status_col.text('invalid engine #');
126 } else {
123 } else {
127 var settings = {
124 var settings = {
128 cache : false,
125 cache : false,
129 data : {n:n},
126 data : {n:n},
130 type : "POST",
127 type : "POST",
131 dataType : "json",
128 dataType : "json",
132 success : function (data, status, xhr) {
129 success : function (data, status, xhr) {
133 that.update_state(data);
130 that.update_state(data);
134 },
131 },
135 error : function (data, status, xhr) {
132 error : function (data, status, xhr) {
136 status_col.text("error starting cluster");
133 status_col.text("error starting cluster");
137 }
134 }
138 };
135 };
139 status_col.text('starting');
136 status_col.text('starting');
140 var url = utils.url_join_encode(
137 var url = utils.url_join_encode(
141 that.baseProjectUrl(),
138 that.base_url,
142 'clusters',
139 'clusters',
143 that.data.profile,
140 that.data.profile,
144 'start'
141 'start'
145 );
142 );
146 $.ajax(url, settings);
143 $.ajax(url, settings);
147 }
144 }
148 });
145 });
149 };
146 };
150
147
151
148
152 ClusterItem.prototype.state_running = function () {
149 ClusterItem.prototype.state_running = function () {
153 var that = this;
150 var that = this;
154 var profile_col = $('<div/>').addClass('profile_col span4').text(this.data.profile);
151 var profile_col = $('<div/>').addClass('profile_col span4').text(this.data.profile);
155 var status_col = $('<div/>').addClass('status_col span3').text('running');
152 var status_col = $('<div/>').addClass('status_col span3').text('running');
156 var engines_col = $('<div/>').addClass('engines_col span3').text(this.data.n);
153 var engines_col = $('<div/>').addClass('engines_col span3').text(this.data.n);
157 var stop_button = $('<button/>').addClass("btn btn-mini").text("Stop");
154 var stop_button = $('<button/>').addClass("btn btn-mini").text("Stop");
158 var action_col = $('<div/>').addClass('action_col span2').append(
155 var action_col = $('<div/>').addClass('action_col span2').append(
159 $("<span/>").addClass("item_buttons btn-group").append(
156 $("<span/>").addClass("item_buttons btn-group").append(
160 stop_button
157 stop_button
161 )
158 )
162 );
159 );
163 this.element.empty()
160 this.element.empty()
164 .append(profile_col)
161 .append(profile_col)
165 .append(status_col)
162 .append(status_col)
166 .append(engines_col)
163 .append(engines_col)
167 .append(action_col);
164 .append(action_col);
168 stop_button.click(function (e) {
165 stop_button.click(function (e) {
169 var settings = {
166 var settings = {
170 cache : false,
167 cache : false,
171 type : "POST",
168 type : "POST",
172 dataType : "json",
169 dataType : "json",
173 success : function (data, status, xhr) {
170 success : function (data, status, xhr) {
174 that.update_state(data);
171 that.update_state(data);
175 },
172 },
176 error : function (data, status, xhr) {
173 error : function (data, status, xhr) {
177 console.log('error',data);
174 console.log('error',data);
178 status_col.text("error stopping cluster");
175 status_col.text("error stopping cluster");
179 }
176 }
180 };
177 };
181 status_col.text('stopping');
178 status_col.text('stopping');
182 var url = utils.url_join_encode(
179 var url = utils.url_join_encode(
183 that.baseProjectUrl(),
180 that.base_url,
184 'clusters',
181 'clusters',
185 that.data.profile,
182 that.data.profile,
186 'stop'
183 'stop'
187 );
184 );
188 $.ajax(url, settings);
185 $.ajax(url, settings);
189 });
186 });
190 };
187 };
191
188
192
189
193 IPython.ClusterList = ClusterList;
190 IPython.ClusterList = ClusterList;
194 IPython.ClusterItem = ClusterItem;
191 IPython.ClusterItem = ClusterItem;
195
192
196 return IPython;
193 return IPython;
197
194
198 }(IPython));
195 }(IPython));
199
196
@@ -1,85 +1,89 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 // On document ready
9 // On document ready
10 //============================================================================
10 //============================================================================
11
11
12
12
13 $(document).ready(function () {
13 $(document).ready(function () {
14
14
15 IPython.page = new IPython.Page();
15 IPython.page = new IPython.Page();
16
16
17 $('#new_notebook').button().click(function (e) {
17 $('#new_notebook').button().click(function (e) {
18 IPython.notebook_list.new_notebook($('body').data('baseProjectUrl'))
18 IPython.notebook_list.new_notebook()
19 });
19 });
20
20
21 IPython.notebook_list = new IPython.NotebookList('#notebook_list');
21 var opts = {
22 IPython.cluster_list = new IPython.ClusterList('#cluster_list');
22 base_url : IPython.utils.get_body_data("baseUrl"),
23 IPython.login_widget = new IPython.LoginWidget('#login_widget');
23 notebook_path : IPython.utils.get_body_data("notebookPath"),
24 };
25 IPython.notebook_list = new IPython.NotebookList('#notebook_list', opts);
26 IPython.cluster_list = new IPython.ClusterList('#cluster_list', opts);
27 IPython.login_widget = new IPython.LoginWidget('#login_widget', opts);
24
28
25 var interval_id=0;
29 var interval_id=0;
26 // auto refresh every xx secondes, no need to be fast,
30 // auto refresh every xx secondes, no need to be fast,
27 // update is done at least when page get focus
31 // update is done at least when page get focus
28 var time_refresh = 60; // in sec
32 var time_refresh = 60; // in sec
29
33
30 var enable_autorefresh = function(){
34 var enable_autorefresh = function(){
31 //refresh immediately , then start interval
35 //refresh immediately , then start interval
32 if($('.upload_button').length == 0)
36 if($('.upload_button').length == 0)
33 {
37 {
34 IPython.notebook_list.load_sessions();
38 IPython.notebook_list.load_sessions();
35 IPython.cluster_list.load_list();
39 IPython.cluster_list.load_list();
36 }
40 }
37 if (!interval_id){
41 if (!interval_id){
38 interval_id = setInterval(function(){
42 interval_id = setInterval(function(){
39 if($('.upload_button').length == 0)
43 if($('.upload_button').length == 0)
40 {
44 {
41 IPython.notebook_list.load_sessions();
45 IPython.notebook_list.load_sessions();
42 IPython.cluster_list.load_list();
46 IPython.cluster_list.load_list();
43 }
47 }
44 }, time_refresh*1000);
48 }, time_refresh*1000);
45 }
49 }
46 }
50 }
47
51
48 var disable_autorefresh = function(){
52 var disable_autorefresh = function(){
49 clearInterval(interval_id);
53 clearInterval(interval_id);
50 interval_id = 0;
54 interval_id = 0;
51 }
55 }
52
56
53 // stop autorefresh when page lose focus
57 // stop autorefresh when page lose focus
54 $(window).blur(function() {
58 $(window).blur(function() {
55 disable_autorefresh();
59 disable_autorefresh();
56 })
60 })
57
61
58 //re-enable when page get focus back
62 //re-enable when page get focus back
59 $(window).focus(function() {
63 $(window).focus(function() {
60 enable_autorefresh();
64 enable_autorefresh();
61 });
65 });
62
66
63 // finally start it, it will refresh immediately
67 // finally start it, it will refresh immediately
64 enable_autorefresh();
68 enable_autorefresh();
65
69
66 IPython.page.show();
70 IPython.page.show();
67
71
68 // bound the upload method to the on change of the file select list
72 // bound the upload method to the on change of the file select list
69 $("#alternate_upload").change(function (event){
73 $("#alternate_upload").change(function (event){
70 IPython.notebook_list.handelFilesUpload(event,'form');
74 IPython.notebook_list.handelFilesUpload(event,'form');
71 });
75 });
72
76
73 // set hash on tab click
77 // set hash on tab click
74 $("#tabs").find("a").click(function() {
78 $("#tabs").find("a").click(function() {
75 window.location.hash = $(this).attr("href");
79 window.location.hash = $(this).attr("href");
76 })
80 })
77
81
78 // load tab if url hash
82 // load tab if url hash
79 if (window.location.hash) {
83 if (window.location.hash) {
80 $("#tabs").find("a[href=" + window.location.hash + "]").click();
84 $("#tabs").find("a[href=" + window.location.hash + "]").click();
81 }
85 }
82
86
83
87
84 });
88 });
85
89
@@ -1,437 +1,431 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2011 The IPython Development Team
2 // Copyright (C) 2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // NotebookList
9 // NotebookList
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 NotebookList = function (selector) {
17 var NotebookList = function (selector, options) {
18 this.selector = selector;
18 this.selector = selector;
19 if (this.selector !== undefined) {
19 if (this.selector !== undefined) {
20 this.element = $(selector);
20 this.element = $(selector);
21 this.style();
21 this.style();
22 this.bind_events();
22 this.bind_events();
23 }
23 }
24 this.notebooks_list = [];
24 this.notebooks_list = [];
25 this.sessions = {};
25 this.sessions = {};
26 this.base_url = options.base_url || utils.get_body_data("baseUrl");
27 this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
26 };
28 };
27
29
28 NotebookList.prototype.baseProjectUrl = function () {
29 return $('body').data('baseProjectUrl');
30 };
31
32 NotebookList.prototype.notebookPath = function() {
33 return $('body').data('notebookPath');
34 };
35
36 NotebookList.prototype.style = function () {
30 NotebookList.prototype.style = function () {
37 $('#notebook_toolbar').addClass('list_toolbar');
31 $('#notebook_toolbar').addClass('list_toolbar');
38 $('#drag_info').addClass('toolbar_info');
32 $('#drag_info').addClass('toolbar_info');
39 $('#notebook_buttons').addClass('toolbar_buttons');
33 $('#notebook_buttons').addClass('toolbar_buttons');
40 $('#notebook_list_header').addClass('list_header');
34 $('#notebook_list_header').addClass('list_header');
41 this.element.addClass("list_container");
35 this.element.addClass("list_container");
42 };
36 };
43
37
44
38
45 NotebookList.prototype.bind_events = function () {
39 NotebookList.prototype.bind_events = function () {
46 var that = this;
40 var that = this;
47 $('#refresh_notebook_list').click(function () {
41 $('#refresh_notebook_list').click(function () {
48 that.load_list();
42 that.load_list();
49 });
43 });
50 this.element.bind('dragover', function () {
44 this.element.bind('dragover', function () {
51 return false;
45 return false;
52 });
46 });
53 this.element.bind('drop', function(event){
47 this.element.bind('drop', function(event){
54 that.handelFilesUpload(event,'drop');
48 that.handelFilesUpload(event,'drop');
55 return false;
49 return false;
56 });
50 });
57 };
51 };
58
52
59 NotebookList.prototype.handelFilesUpload = function(event, dropOrForm) {
53 NotebookList.prototype.handelFilesUpload = function(event, dropOrForm) {
60 var that = this;
54 var that = this;
61 var files;
55 var files;
62 if(dropOrForm =='drop'){
56 if(dropOrForm =='drop'){
63 files = event.originalEvent.dataTransfer.files;
57 files = event.originalEvent.dataTransfer.files;
64 } else
58 } else
65 {
59 {
66 files = event.originalEvent.target.files;
60 files = event.originalEvent.target.files;
67 }
61 }
68 for (var i = 0; i < files.length; i++) {
62 for (var i = 0; i < files.length; i++) {
69 var f = files[i];
63 var f = files[i];
70 var reader = new FileReader();
64 var reader = new FileReader();
71 reader.readAsText(f);
65 reader.readAsText(f);
72 var name_and_ext = utils.splitext(f.name);
66 var name_and_ext = utils.splitext(f.name);
73 var file_ext = name_and_ext[1];
67 var file_ext = name_and_ext[1];
74 if (file_ext === '.ipynb') {
68 if (file_ext === '.ipynb') {
75 var item = that.new_notebook_item(0);
69 var item = that.new_notebook_item(0);
76 that.add_name_input(f.name, item);
70 that.add_name_input(f.name, item);
77 // Store the notebook item in the reader so we can use it later
71 // Store the notebook item in the reader so we can use it later
78 // to know which item it belongs to.
72 // to know which item it belongs to.
79 $(reader).data('item', item);
73 $(reader).data('item', item);
80 reader.onload = function (event) {
74 reader.onload = function (event) {
81 var nbitem = $(event.target).data('item');
75 var nbitem = $(event.target).data('item');
82 that.add_notebook_data(event.target.result, nbitem);
76 that.add_notebook_data(event.target.result, nbitem);
83 that.add_upload_button(nbitem);
77 that.add_upload_button(nbitem);
84 };
78 };
85 } else {
79 } else {
86 var dialog = 'Uploaded notebooks must be .ipynb files';
80 var dialog = 'Uploaded notebooks must be .ipynb files';
87 IPython.dialog.modal({
81 IPython.dialog.modal({
88 title : 'Invalid file type',
82 title : 'Invalid file type',
89 body : dialog,
83 body : dialog,
90 buttons : {'OK' : {'class' : 'btn-primary'}}
84 buttons : {'OK' : {'class' : 'btn-primary'}}
91 });
85 });
92 }
86 }
93 }
87 }
94 // Replace the file input form wth a clone of itself. This is required to
88 // Replace the file input form wth a clone of itself. This is required to
95 // reset the form. Otherwise, if you upload a file, delete it and try to
89 // reset the form. Otherwise, if you upload a file, delete it and try to
96 // upload it again, the changed event won't fire.
90 // upload it again, the changed event won't fire.
97 var form = $('input.fileinput');
91 var form = $('input.fileinput');
98 form.replaceWith(form.clone(true));
92 form.replaceWith(form.clone(true));
99 return false;
93 return false;
100 };
94 };
101
95
102 NotebookList.prototype.clear_list = function () {
96 NotebookList.prototype.clear_list = function () {
103 this.element.children('.list_item').remove();
97 this.element.children('.list_item').remove();
104 };
98 };
105
99
106 NotebookList.prototype.load_sessions = function(){
100 NotebookList.prototype.load_sessions = function(){
107 var that = this;
101 var that = this;
108 var settings = {
102 var settings = {
109 processData : false,
103 processData : false,
110 cache : false,
104 cache : false,
111 type : "GET",
105 type : "GET",
112 dataType : "json",
106 dataType : "json",
113 success : $.proxy(that.sessions_loaded, this)
107 success : $.proxy(that.sessions_loaded, this)
114 };
108 };
115 var url = this.baseProjectUrl() + 'api/sessions';
109 var url = utils.url_join_encode(this.base_url, 'api/sessions');
116 $.ajax(url,settings);
110 $.ajax(url,settings);
117 };
111 };
118
112
119
113
120 NotebookList.prototype.sessions_loaded = function(data){
114 NotebookList.prototype.sessions_loaded = function(data){
121 this.sessions = {};
115 this.sessions = {};
122 var len = data.length;
116 var len = data.length;
123 if (len > 0) {
117 if (len > 0) {
124 for (var i=0; i<len; i++) {
118 for (var i=0; i<len; i++) {
125 var nb_path;
119 var nb_path;
126 if (!data[i].notebook.path) {
120 if (!data[i].notebook.path) {
127 nb_path = data[i].notebook.name;
121 nb_path = data[i].notebook.name;
128 }
122 }
129 else {
123 else {
130 nb_path = utils.url_path_join(
124 nb_path = utils.url_path_join(
131 data[i].notebook.path,
125 data[i].notebook.path,
132 data[i].notebook.name
126 data[i].notebook.name
133 );
127 );
134 }
128 }
135 this.sessions[nb_path] = data[i].id;
129 this.sessions[nb_path] = data[i].id;
136 }
130 }
137 }
131 }
138 this.load_list();
132 this.load_list();
139 };
133 };
140
134
141 NotebookList.prototype.load_list = function () {
135 NotebookList.prototype.load_list = function () {
142 var that = this;
136 var that = this;
143 var settings = {
137 var settings = {
144 processData : false,
138 processData : false,
145 cache : false,
139 cache : false,
146 type : "GET",
140 type : "GET",
147 dataType : "json",
141 dataType : "json",
148 success : $.proxy(this.list_loaded, this),
142 success : $.proxy(this.list_loaded, this),
149 error : $.proxy( function(){
143 error : $.proxy( function(){
150 that.list_loaded([], null, null, {msg:"Error connecting to server."});
144 that.list_loaded([], null, null, {msg:"Error connecting to server."});
151 },this)
145 },this)
152 };
146 };
153
147
154 var url = utils.url_join_encode(
148 var url = utils.url_join_encode(
155 this.baseProjectUrl(),
149 this.base_url,
156 'api',
150 'api',
157 'notebooks',
151 'notebooks',
158 this.notebookPath()
152 this.notebook_path
159 );
153 );
160 $.ajax(url, settings);
154 $.ajax(url, settings);
161 };
155 };
162
156
163
157
164 NotebookList.prototype.list_loaded = function (data, status, xhr, param) {
158 NotebookList.prototype.list_loaded = function (data, status, xhr, param) {
165 var message = 'Notebook list empty.';
159 var message = 'Notebook list empty.';
166 if (param !== undefined && param.msg) {
160 if (param !== undefined && param.msg) {
167 message = param.msg;
161 message = param.msg;
168 }
162 }
169 var item = null;
163 var item = null;
170 var len = data.length;
164 var len = data.length;
171 this.clear_list();
165 this.clear_list();
172 if (len === 0) {
166 if (len === 0) {
173 item = this.new_notebook_item(0);
167 item = this.new_notebook_item(0);
174 var span12 = item.children().first();
168 var span12 = item.children().first();
175 span12.empty();
169 span12.empty();
176 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
170 span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
177 }
171 }
178 var path = this.notebookPath();
172 var path = this.notebook_path;
179 var offset = 0;
173 var offset = 0;
180 if (path !== '') {
174 if (path !== '') {
181 item = this.new_notebook_item(0);
175 item = this.new_notebook_item(0);
182 this.add_dir(path, '..', item);
176 this.add_dir(path, '..', item);
183 offset = 1;
177 offset = 1;
184 }
178 }
185 for (var i=0; i<len; i++) {
179 for (var i=0; i<len; i++) {
186 if (data[i].type === 'directory') {
180 if (data[i].type === 'directory') {
187 var name = data[i].name;
181 var name = data[i].name;
188 item = this.new_notebook_item(i+offset);
182 item = this.new_notebook_item(i+offset);
189 this.add_dir(path, name, item);
183 this.add_dir(path, name, item);
190 } else {
184 } else {
191 var name = data[i].name;
185 var name = data[i].name;
192 item = this.new_notebook_item(i+offset);
186 item = this.new_notebook_item(i+offset);
193 this.add_link(path, name, item);
187 this.add_link(path, name, item);
194 name = utils.url_path_join(path, name);
188 name = utils.url_path_join(path, name);
195 if(this.sessions[name] === undefined){
189 if(this.sessions[name] === undefined){
196 this.add_delete_button(item);
190 this.add_delete_button(item);
197 } else {
191 } else {
198 this.add_shutdown_button(item,this.sessions[name]);
192 this.add_shutdown_button(item,this.sessions[name]);
199 }
193 }
200 }
194 }
201 }
195 }
202 };
196 };
203
197
204
198
205 NotebookList.prototype.new_notebook_item = function (index) {
199 NotebookList.prototype.new_notebook_item = function (index) {
206 var item = $('<div/>').addClass("list_item").addClass("row-fluid");
200 var item = $('<div/>').addClass("list_item").addClass("row-fluid");
207 // item.addClass('list_item ui-widget ui-widget-content ui-helper-clearfix');
201 // item.addClass('list_item ui-widget ui-widget-content ui-helper-clearfix');
208 // item.css('border-top-style','none');
202 // item.css('border-top-style','none');
209 item.append($("<div/>").addClass("span12").append(
203 item.append($("<div/>").addClass("span12").append(
210 $('<i/>').addClass('item_icon')
204 $('<i/>').addClass('item_icon')
211 ).append(
205 ).append(
212 $("<a/>").addClass("item_link").append(
206 $("<a/>").addClass("item_link").append(
213 $("<span/>").addClass("item_name")
207 $("<span/>").addClass("item_name")
214 )
208 )
215 ).append(
209 ).append(
216 $('<div/>').addClass("item_buttons btn-group pull-right")
210 $('<div/>').addClass("item_buttons btn-group pull-right")
217 ));
211 ));
218
212
219 if (index === -1) {
213 if (index === -1) {
220 this.element.append(item);
214 this.element.append(item);
221 } else {
215 } else {
222 this.element.children().eq(index).after(item);
216 this.element.children().eq(index).after(item);
223 }
217 }
224 return item;
218 return item;
225 };
219 };
226
220
227
221
228 NotebookList.prototype.add_dir = function (path, name, item) {
222 NotebookList.prototype.add_dir = function (path, name, item) {
229 item.data('name', name);
223 item.data('name', name);
230 item.data('path', path);
224 item.data('path', path);
231 item.find(".item_name").text(name);
225 item.find(".item_name").text(name);
232 item.find(".item_icon").addClass('icon-folder-open');
226 item.find(".item_icon").addClass('icon-folder-open');
233 item.find("a.item_link")
227 item.find("a.item_link")
234 .attr('href',
228 .attr('href',
235 utils.url_join_encode(
229 utils.url_join_encode(
236 this.baseProjectUrl(),
230 this.base_url,
237 "tree",
231 "tree",
238 path,
232 path,
239 name
233 name
240 )
234 )
241 );
235 );
242 };
236 };
243
237
244
238
245 NotebookList.prototype.add_link = function (path, nbname, item) {
239 NotebookList.prototype.add_link = function (path, nbname, item) {
246 item.data('nbname', nbname);
240 item.data('nbname', nbname);
247 item.data('path', path);
241 item.data('path', path);
248 item.find(".item_name").text(nbname);
242 item.find(".item_name").text(nbname);
249 item.find(".item_icon").addClass('icon-book');
243 item.find(".item_icon").addClass('icon-book');
250 item.find("a.item_link")
244 item.find("a.item_link")
251 .attr('href',
245 .attr('href',
252 utils.url_join_encode(
246 utils.url_join_encode(
253 this.baseProjectUrl(),
247 this.base_url,
254 "notebooks",
248 "notebooks",
255 path,
249 path,
256 nbname
250 nbname
257 )
251 )
258 ).attr('target','_blank');
252 ).attr('target','_blank');
259 };
253 };
260
254
261
255
262 NotebookList.prototype.add_name_input = function (nbname, item) {
256 NotebookList.prototype.add_name_input = function (nbname, item) {
263 item.data('nbname', nbname);
257 item.data('nbname', nbname);
264 item.find(".item_icon").addClass('icon-book');
258 item.find(".item_icon").addClass('icon-book');
265 item.find(".item_name").empty().append(
259 item.find(".item_name").empty().append(
266 $('<input/>')
260 $('<input/>')
267 .addClass("nbname_input")
261 .addClass("nbname_input")
268 .attr('value', utils.splitext(nbname)[0])
262 .attr('value', utils.splitext(nbname)[0])
269 .attr('size', '30')
263 .attr('size', '30')
270 .attr('type', 'text')
264 .attr('type', 'text')
271 );
265 );
272 };
266 };
273
267
274
268
275 NotebookList.prototype.add_notebook_data = function (data, item) {
269 NotebookList.prototype.add_notebook_data = function (data, item) {
276 item.data('nbdata', data);
270 item.data('nbdata', data);
277 };
271 };
278
272
279
273
280 NotebookList.prototype.add_shutdown_button = function (item, session) {
274 NotebookList.prototype.add_shutdown_button = function (item, session) {
281 var that = this;
275 var that = this;
282 var shutdown_button = $("<button/>").text("Shutdown").addClass("btn btn-mini btn-danger").
276 var shutdown_button = $("<button/>").text("Shutdown").addClass("btn btn-mini btn-danger").
283 click(function (e) {
277 click(function (e) {
284 var settings = {
278 var settings = {
285 processData : false,
279 processData : false,
286 cache : false,
280 cache : false,
287 type : "DELETE",
281 type : "DELETE",
288 dataType : "json",
282 dataType : "json",
289 success : function () {
283 success : function () {
290 that.load_sessions();
284 that.load_sessions();
291 }
285 }
292 };
286 };
293 var url = utils.url_join_encode(
287 var url = utils.url_join_encode(
294 that.baseProjectUrl(),
288 that.base_url,
295 'api/sessions',
289 'api/sessions',
296 session
290 session
297 );
291 );
298 $.ajax(url, settings);
292 $.ajax(url, settings);
299 return false;
293 return false;
300 });
294 });
301 // var new_buttons = item.find('a'); // shutdown_button;
295 // var new_buttons = item.find('a'); // shutdown_button;
302 item.find(".item_buttons").text("").append(shutdown_button);
296 item.find(".item_buttons").text("").append(shutdown_button);
303 };
297 };
304
298
305 NotebookList.prototype.add_delete_button = function (item) {
299 NotebookList.prototype.add_delete_button = function (item) {
306 var new_buttons = $('<span/>').addClass("btn-group pull-right");
300 var new_buttons = $('<span/>').addClass("btn-group pull-right");
307 var notebooklist = this;
301 var notebooklist = this;
308 var delete_button = $("<button/>").text("Delete").addClass("btn btn-mini").
302 var delete_button = $("<button/>").text("Delete").addClass("btn btn-mini").
309 click(function (e) {
303 click(function (e) {
310 // $(this) is the button that was clicked.
304 // $(this) is the button that was clicked.
311 var that = $(this);
305 var that = $(this);
312 // We use the nbname and notebook_id from the parent notebook_item element's
306 // We use the nbname and notebook_id from the parent notebook_item element's
313 // data because the outer scopes values change as we iterate through the loop.
307 // data because the outer scopes values change as we iterate through the loop.
314 var parent_item = that.parents('div.list_item');
308 var parent_item = that.parents('div.list_item');
315 var nbname = parent_item.data('nbname');
309 var nbname = parent_item.data('nbname');
316 var message = 'Are you sure you want to permanently delete the notebook: ' + nbname + '?';
310 var message = 'Are you sure you want to permanently delete the notebook: ' + nbname + '?';
317 IPython.dialog.modal({
311 IPython.dialog.modal({
318 title : "Delete notebook",
312 title : "Delete notebook",
319 body : message,
313 body : message,
320 buttons : {
314 buttons : {
321 Delete : {
315 Delete : {
322 class: "btn-danger",
316 class: "btn-danger",
323 click: function() {
317 click: function() {
324 var settings = {
318 var settings = {
325 processData : false,
319 processData : false,
326 cache : false,
320 cache : false,
327 type : "DELETE",
321 type : "DELETE",
328 dataType : "json",
322 dataType : "json",
329 success : function (data, status, xhr) {
323 success : function (data, status, xhr) {
330 parent_item.remove();
324 parent_item.remove();
331 }
325 }
332 };
326 };
333 var url = utils.url_join_encode(
327 var url = utils.url_join_encode(
334 notebooklist.baseProjectUrl(),
328 notebooklist.base_url,
335 'api/notebooks',
329 'api/notebooks',
336 notebooklist.notebookPath(),
330 notebooklist.notebook_path,
337 nbname
331 nbname
338 );
332 );
339 $.ajax(url, settings);
333 $.ajax(url, settings);
340 }
334 }
341 },
335 },
342 Cancel : {}
336 Cancel : {}
343 }
337 }
344 });
338 });
345 return false;
339 return false;
346 });
340 });
347 item.find(".item_buttons").text("").append(delete_button);
341 item.find(".item_buttons").text("").append(delete_button);
348 };
342 };
349
343
350
344
351 NotebookList.prototype.add_upload_button = function (item) {
345 NotebookList.prototype.add_upload_button = function (item) {
352 var that = this;
346 var that = this;
353 var upload_button = $('<button/>').text("Upload")
347 var upload_button = $('<button/>').text("Upload")
354 .addClass('btn btn-primary btn-mini upload_button')
348 .addClass('btn btn-primary btn-mini upload_button')
355 .click(function (e) {
349 .click(function (e) {
356 var nbname = item.find('.item_name > input').val();
350 var nbname = item.find('.item_name > input').val();
357 if (nbname.slice(nbname.length-6, nbname.length) != ".ipynb") {
351 if (nbname.slice(nbname.length-6, nbname.length) != ".ipynb") {
358 nbname = nbname + ".ipynb";
352 nbname = nbname + ".ipynb";
359 }
353 }
360 var path = that.notebookPath();
354 var path = that.notebook_path;
361 var nbdata = item.data('nbdata');
355 var nbdata = item.data('nbdata');
362 var content_type = 'application/json';
356 var content_type = 'application/json';
363 var model = {
357 var model = {
364 content : JSON.parse(nbdata),
358 content : JSON.parse(nbdata),
365 };
359 };
366 var settings = {
360 var settings = {
367 processData : false,
361 processData : false,
368 cache : false,
362 cache : false,
369 type : 'PUT',
363 type : 'PUT',
370 dataType : 'json',
364 dataType : 'json',
371 data : JSON.stringify(model),
365 data : JSON.stringify(model),
372 headers : {'Content-Type': content_type},
366 headers : {'Content-Type': content_type},
373 success : function (data, status, xhr) {
367 success : function (data, status, xhr) {
374 that.add_link(path, nbname, item);
368 that.add_link(path, nbname, item);
375 that.add_delete_button(item);
369 that.add_delete_button(item);
376 },
370 },
377 error : function (data, status, xhr) {
371 error : function (data, status, xhr) {
378 console.log(data, status);
372 console.log(data, status);
379 }
373 }
380 };
374 };
381
375
382 var url = utils.url_join_encode(
376 var url = utils.url_join_encode(
383 that.baseProjectUrl(),
377 that.base_url,
384 'api/notebooks',
378 'api/notebooks',
385 that.notebookPath(),
379 that.notebook_path,
386 nbname
380 nbname
387 );
381 );
388 $.ajax(url, settings);
382 $.ajax(url, settings);
389 return false;
383 return false;
390 });
384 });
391 var cancel_button = $('<button/>').text("Cancel")
385 var cancel_button = $('<button/>').text("Cancel")
392 .addClass("btn btn-mini")
386 .addClass("btn btn-mini")
393 .click(function (e) {
387 .click(function (e) {
394 console.log('cancel click');
388 console.log('cancel click');
395 item.remove();
389 item.remove();
396 return false;
390 return false;
397 });
391 });
398 item.find(".item_buttons").empty()
392 item.find(".item_buttons").empty()
399 .append(upload_button)
393 .append(upload_button)
400 .append(cancel_button);
394 .append(cancel_button);
401 };
395 };
402
396
403
397
404 NotebookList.prototype.new_notebook = function(){
398 NotebookList.prototype.new_notebook = function(){
405 var path = this.notebookPath();
399 var path = this.notebook_path;
406 var base_project_url = this.baseProjectUrl();
400 var base_url = this.base_url;
407 var settings = {
401 var settings = {
408 processData : false,
402 processData : false,
409 cache : false,
403 cache : false,
410 type : "POST",
404 type : "POST",
411 dataType : "json",
405 dataType : "json",
412 async : false,
406 async : false,
413 success : function (data, status, xhr) {
407 success : function (data, status, xhr) {
414 var notebook_name = data.name;
408 var notebook_name = data.name;
415 window.open(
409 window.open(
416 utils.url_join_encode(
410 utils.url_join_encode(
417 base_project_url,
411 base_url,
418 'notebooks',
412 'notebooks',
419 path,
413 path,
420 notebook_name),
414 notebook_name),
421 '_blank'
415 '_blank'
422 );
416 );
423 }
417 }
424 };
418 };
425 var url = utils.url_join_encode(
419 var url = utils.url_join_encode(
426 base_project_url,
420 base_url,
427 'api/notebooks',
421 'api/notebooks',
428 path
422 path
429 );
423 );
430 $.ajax(url, settings);
424 $.ajax(url, settings);
431 };
425 };
432
426
433 IPython.NotebookList = NotebookList;
427 IPython.NotebookList = NotebookList;
434
428
435 return IPython;
429 return IPython;
436
430
437 }(IPython));
431 }(IPython));
@@ -1,52 +1,52 b''
1 {% extends "page.html" %}
1 {% extends "page.html" %}
2
2
3
3
4 {% block stylesheet %}
4 {% block stylesheet %}
5 {{super()}}
5 {{super()}}
6 <link rel="stylesheet" href="{{ static_url("auth/css/override.css") }}" type="text/css" />
6 <link rel="stylesheet" href="{{ static_url("auth/css/override.css") }}" type="text/css" />
7 {% endblock %}
7 {% endblock %}
8
8
9 {% block login_widget %}
9 {% block login_widget %}
10 {% endblock %}
10 {% endblock %}
11
11
12 {% block site %}
12 {% block site %}
13
13
14 <div id="ipython-main-app" class="container">
14 <div id="ipython-main-app" class="container">
15
15
16 {% if login_available %}
16 {% if login_available %}
17 <div class="row">
17 <div class="row">
18 <div class="navbar span8 offset2">
18 <div class="navbar span8 offset2">
19 <div class="navbar-inner">
19 <div class="navbar-inner">
20 <div class="container">
20 <div class="container">
21 <div class="center-nav">
21 <div class="center-nav">
22 <p class="navbar-text nav">Password:</p>
22 <p class="navbar-text nav">Password:</p>
23 <form action="{{base_project_url}}login?next={{next}}" method="post" class="navbar-form pull-left">
23 <form action="{{base_url}}login?next={{next}}" method="post" class="navbar-form pull-left">
24 <input type="password" name="password" id="password_input">
24 <input type="password" name="password" id="password_input">
25 <button type="submit" id="login_submit">Log in</button>
25 <button type="submit" id="login_submit">Log in</button>
26 </form>
26 </form>
27 </div>
27 </div>
28 </div>
28 </div>
29 </div>
29 </div>
30 </div>
30 </div>
31 </div>
31 </div>
32 {% endif %}
32 {% endif %}
33 {% if message %}
33 {% if message %}
34 <div class="row">
34 <div class="row">
35 {% for key in message %}
35 {% for key in message %}
36 <div class="message {{key}}">
36 <div class="message {{key}}">
37 {{message[key]}}
37 {{message[key]}}
38 </div>
38 </div>
39 {% endfor %}
39 {% endfor %}
40 </div>
40 </div>
41 {% endif %}
41 {% endif %}
42
42
43 <div/>
43 <div/>
44
44
45 {% endblock %}
45 {% endblock %}
46
46
47
47
48 {% block script %}
48 {% block script %}
49
49
50 <script src="{{static_url("auth/js/loginmain.js") }}" type="text/javascript" charset="utf-8"></script>
50 <script src="{{static_url("auth/js/loginmain.js") }}" type="text/javascript" charset="utf-8"></script>
51
51
52 {% endblock %}
52 {% endblock %}
@@ -1,38 +1,38 b''
1 {% extends "page.html" %}
1 {% extends "page.html" %}
2
2
3 {% block stylesheet %}
3 {% block stylesheet %}
4 {{super()}}
4 {{super()}}
5 <link rel="stylesheet" href="{{ static_url("auth/css/override.css") }}" type="text/css" />
5 <link rel="stylesheet" href="{{ static_url("auth/css/override.css") }}" type="text/css" />
6 {% endblock %}
6 {% endblock %}
7
7
8 {% block login_widget %}
8 {% block login_widget %}
9 {% endblock %}
9 {% endblock %}
10
10
11 {% block site %}
11 {% block site %}
12
12
13 <div id="ipython-main-app" class="container">
13 <div id="ipython-main-app" class="container">
14
14
15 {% if message %}
15 {% if message %}
16 {% for key in message %}
16 {% for key in message %}
17 <div class="message {{key}}">
17 <div class="message {{key}}">
18 {{message[key]}}
18 {{message[key]}}
19 </div>
19 </div>
20 {% endfor %}
20 {% endfor %}
21 {% endif %}
21 {% endif %}
22
22
23 {% if not login_available %}
23 {% if not login_available %}
24 Proceed to the <a href="{{base_project_url}}">dashboard</a>.
24 Proceed to the <a href="{{base_url}}">dashboard</a>.
25 {% else %}
25 {% else %}
26 Proceed to the <a href="{{base_project_url}}login">login page</a>.
26 Proceed to the <a href="{{base_url}}login">login page</a>.
27 {% endif %}
27 {% endif %}
28
28
29
29
30 <div/>
30 <div/>
31
31
32 {% endblock %}
32 {% endblock %}
33
33
34 {% block script %}
34 {% block script %}
35
35
36 <script src="{{static_url("auth/js/logoutmain.js") }}" type="text/javascript" charset="utf-8"></script>
36 <script src="{{static_url("auth/js/logoutmain.js") }}" type="text/javascript" charset="utf-8"></script>
37
37
38 {% endblock %}
38 {% endblock %}
@@ -1,349 +1,352 b''
1 {% extends "page.html" %}
1 {% extends "page.html" %}
2
2
3 {% block stylesheet %}
3 {% block stylesheet %}
4
4
5 {% if mathjax_url %}
5 {% if mathjax_url %}
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
7 {% endif %}
7 {% endif %}
8 <script type="text/javascript">
8 <script type="text/javascript">
9 // MathJax disabled, set as null to distingish from *missing* MathJax,
9 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 // where it will be undefined, and should prompt a dialog later.
10 // where it will be undefined, and should prompt a dialog later.
11 window.mathjax_url = "{{mathjax_url}}";
11 window.mathjax_url = "{{mathjax_url}}";
12 </script>
12 </script>
13
13
14 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
14 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
15
15
16 {{super()}}
16 {{super()}}
17
17
18 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
18 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
19
19
20 {% endblock %}
20 {% endblock %}
21
21
22 {% block params %}
22 {% block params %}
23
23
24 data-project="{{project}}"
24 data-project="{{project}}"
25 data-base-project-url="{{base_project_url}}"
25 data-base-url="{{base_url}}"
26 data-base-kernel-url="{{base_kernel_url}}"
26 data-base-kernel-url="{{base_kernel_url}}"
27 data-notebook-name="{{notebook_name}}"
27 data-notebook-name="{{notebook_name}}"
28 data-notebook-path="{{notebook_path}}"
28 data-notebook-path="{{notebook_path}}"
29 class="notebook_app"
29 class="notebook_app"
30
30
31 {% endblock %}
31 {% endblock %}
32
32
33
33
34 {% block header %}
34 {% block header %}
35
35
36 <span id="save_widget" class="nav pull-left">
36 <span id="save_widget" class="nav pull-left">
37 <span id="notebook_name"></span>
37 <span id="notebook_name"></span>
38 <span id="checkpoint_status"></span>
38 <span id="checkpoint_status"></span>
39 <span id="autosave_status"></span>
39 <span id="autosave_status"></span>
40 </span>
40 </span>
41
41
42 {% endblock %}
42 {% endblock %}
43
43
44
44
45 {% block site %}
45 {% block site %}
46
46
47 <div id="menubar-container" class="container">
47 <div id="menubar-container" class="container">
48 <div id="menubar">
48 <div id="menubar">
49 <div class="navbar">
49 <div class="navbar">
50 <div class="navbar-inner">
50 <div class="navbar-inner">
51 <div class="container">
51 <div class="container">
52 <ul id="menus" class="nav">
52 <ul id="menus" class="nav">
53 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
53 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
54 <ul id="file_menu" class="dropdown-menu">
54 <ul id="file_menu" class="dropdown-menu">
55 <li id="new_notebook"
55 <li id="new_notebook"
56 title="Make a new notebook (Opens a new window)">
56 title="Make a new notebook (Opens a new window)">
57 <a href="#">New</a></li>
57 <a href="#">New</a></li>
58 <li id="open_notebook"
58 <li id="open_notebook"
59 title="Opens a new window with the Dashboard view">
59 title="Opens a new window with the Dashboard view">
60 <a href="#">Open...</a></li>
60 <a href="#">Open...</a></li>
61 <!-- <hr/> -->
61 <!-- <hr/> -->
62 <li class="divider"></li>
62 <li class="divider"></li>
63 <li id="copy_notebook"
63 <li id="copy_notebook"
64 title="Open a copy of this notebook's contents and start a new kernel">
64 title="Open a copy of this notebook's contents and start a new kernel">
65 <a href="#">Make a Copy...</a></li>
65 <a href="#">Make a Copy...</a></li>
66 <li id="rename_notebook"><a href="#">Rename...</a></li>
66 <li id="rename_notebook"><a href="#">Rename...</a></li>
67 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
67 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
68 <!-- <hr/> -->
68 <!-- <hr/> -->
69 <li class="divider"></li>
69 <li class="divider"></li>
70 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
70 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
71 <ul class="dropdown-menu">
71 <ul class="dropdown-menu">
72 <li><a href="#"></a></li>
72 <li><a href="#"></a></li>
73 <li><a href="#"></a></li>
73 <li><a href="#"></a></li>
74 <li><a href="#"></a></li>
74 <li><a href="#"></a></li>
75 <li><a href="#"></a></li>
75 <li><a href="#"></a></li>
76 <li><a href="#"></a></li>
76 <li><a href="#"></a></li>
77 </ul>
77 </ul>
78 </li>
78 </li>
79 <li class="divider"></li>
79 <li class="divider"></li>
80 <li id="print_preview"><a href="#">Print Preview</a></li>
80 <li id="print_preview"><a href="#">Print Preview</a></li>
81 <li class="dropdown-submenu"><a href="#">Download as</a>
81 <li class="dropdown-submenu"><a href="#">Download as</a>
82 <ul class="dropdown-menu">
82 <ul class="dropdown-menu">
83 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
83 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
84 <li id="download_py"><a href="#">Python (.py)</a></li>
84 <li id="download_py"><a href="#">Python (.py)</a></li>
85 <li id="download_html"><a href="#">HTML (.html)</a></li>
85 <li id="download_html"><a href="#">HTML (.html)</a></li>
86 <li id="download_rst"><a href="#">reST (.rst)</a></li>
86 <li id="download_rst"><a href="#">reST (.rst)</a></li>
87 </ul>
87 </ul>
88 </li>
88 </li>
89 <li class="divider"></li>
89 <li class="divider"></li>
90
90
91 <li id="kill_and_exit"
91 <li id="kill_and_exit"
92 title="Shutdown this notebook's kernel, and close this window">
92 title="Shutdown this notebook's kernel, and close this window">
93 <a href="#" >Close and halt</a></li>
93 <a href="#" >Close and halt</a></li>
94 </ul>
94 </ul>
95 </li>
95 </li>
96 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
96 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
97 <ul id="edit_menu" class="dropdown-menu">
97 <ul id="edit_menu" class="dropdown-menu">
98 <li id="cut_cell"><a href="#">Cut Cell</a></li>
98 <li id="cut_cell"><a href="#">Cut Cell</a></li>
99 <li id="copy_cell"><a href="#">Copy Cell</a></li>
99 <li id="copy_cell"><a href="#">Copy Cell</a></li>
100 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
100 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
101 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
101 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
102 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
102 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
103 <li id="delete_cell"><a href="#">Delete Cell</a></li>
103 <li id="delete_cell"><a href="#">Delete Cell</a></li>
104 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
104 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
105 <li class="divider"></li>
105 <li class="divider"></li>
106 <li id="split_cell"><a href="#">Split Cell</a></li>
106 <li id="split_cell"><a href="#">Split Cell</a></li>
107 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
107 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
108 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
108 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
109 <li class="divider"></li>
109 <li class="divider"></li>
110 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
110 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
111 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
111 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
112 <li class="divider"></li>
112 <li class="divider"></li>
113 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
113 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
114 </ul>
114 </ul>
115 </li>
115 </li>
116 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
116 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
117 <ul id="view_menu" class="dropdown-menu">
117 <ul id="view_menu" class="dropdown-menu">
118 <li id="toggle_header"
118 <li id="toggle_header"
119 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
119 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
120 <a href="#">Toggle Header</a></li>
120 <a href="#">Toggle Header</a></li>
121 <li id="toggle_toolbar"
121 <li id="toggle_toolbar"
122 title="Show/Hide the action icons (below menu bar)">
122 title="Show/Hide the action icons (below menu bar)">
123 <a href="#">Toggle Toolbar</a></li>
123 <a href="#">Toggle Toolbar</a></li>
124 </ul>
124 </ul>
125 </li>
125 </li>
126 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
126 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
127 <ul id="insert_menu" class="dropdown-menu">
127 <ul id="insert_menu" class="dropdown-menu">
128 <li id="insert_cell_above"
128 <li id="insert_cell_above"
129 title="Insert an empty Code cell above the currently active cell">
129 title="Insert an empty Code cell above the currently active cell">
130 <a href="#">Insert Cell Above</a></li>
130 <a href="#">Insert Cell Above</a></li>
131 <li id="insert_cell_below"
131 <li id="insert_cell_below"
132 title="Insert an empty Code cell below the currently active cell">
132 title="Insert an empty Code cell below the currently active cell">
133 <a href="#">Insert Cell Below</a></li>
133 <a href="#">Insert Cell Below</a></li>
134 </ul>
134 </ul>
135 </li>
135 </li>
136 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
136 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
137 <ul id="cell_menu" class="dropdown-menu">
137 <ul id="cell_menu" class="dropdown-menu">
138 <li id="run_cell" title="Run this cell, and move cursor to the next one">
138 <li id="run_cell" title="Run this cell, and move cursor to the next one">
139 <a href="#">Run</a></li>
139 <a href="#">Run</a></li>
140 <li id="run_cell_select_below" title="Run this cell, select below">
140 <li id="run_cell_select_below" title="Run this cell, select below">
141 <a href="#">Run and Select Below</a></li>
141 <a href="#">Run and Select Below</a></li>
142 <li id="run_cell_insert_below" title="Run this cell, insert below">
142 <li id="run_cell_insert_below" title="Run this cell, insert below">
143 <a href="#">Run and Insert Below</a></li>
143 <a href="#">Run and Insert Below</a></li>
144 <li id="run_all_cells" title="Run all cells in the notebook">
144 <li id="run_all_cells" title="Run all cells in the notebook">
145 <a href="#">Run All</a></li>
145 <a href="#">Run All</a></li>
146 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
146 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
147 <a href="#">Run All Above</a></li>
147 <a href="#">Run All Above</a></li>
148 <li id="run_all_cells_below" title="Run this cell and all cells below it">
148 <li id="run_all_cells_below" title="Run this cell and all cells below it">
149 <a href="#">Run All Below</a></li>
149 <a href="#">Run All Below</a></li>
150 <li class="divider"></li>
150 <li class="divider"></li>
151 <li id="change_cell_type" class="dropdown-submenu"
151 <li id="change_cell_type" class="dropdown-submenu"
152 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
152 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
153 <a href="#">Cell Type</a>
153 <a href="#">Cell Type</a>
154 <ul class="dropdown-menu">
154 <ul class="dropdown-menu">
155 <li id="to_code"
155 <li id="to_code"
156 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
156 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
157 <a href="#">Code</a></li>
157 <a href="#">Code</a></li>
158 <li id="to_markdown"
158 <li id="to_markdown"
159 title="Contents will be rendered as HTML and serve as explanatory text">
159 title="Contents will be rendered as HTML and serve as explanatory text">
160 <a href="#">Markdown</a></li>
160 <a href="#">Markdown</a></li>
161 <li id="to_raw"
161 <li id="to_raw"
162 title="Contents will pass through nbconvert unmodified">
162 title="Contents will pass through nbconvert unmodified">
163 <a href="#">Raw NBConvert</a></li>
163 <a href="#">Raw NBConvert</a></li>
164 <li id="to_heading1"><a href="#">Heading 1</a></li>
164 <li id="to_heading1"><a href="#">Heading 1</a></li>
165 <li id="to_heading2"><a href="#">Heading 2</a></li>
165 <li id="to_heading2"><a href="#">Heading 2</a></li>
166 <li id="to_heading3"><a href="#">Heading 3</a></li>
166 <li id="to_heading3"><a href="#">Heading 3</a></li>
167 <li id="to_heading4"><a href="#">Heading 4</a></li>
167 <li id="to_heading4"><a href="#">Heading 4</a></li>
168 <li id="to_heading5"><a href="#">Heading 5</a></li>
168 <li id="to_heading5"><a href="#">Heading 5</a></li>
169 <li id="to_heading6"><a href="#">Heading 6</a></li>
169 <li id="to_heading6"><a href="#">Heading 6</a></li>
170 </ul>
170 </ul>
171 </li>
171 </li>
172 <li class="divider"></li>
172 <li class="divider"></li>
173 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
173 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
174 <ul class="dropdown-menu">
174 <ul class="dropdown-menu">
175 <li id="toggle_current_output"
175 <li id="toggle_current_output"
176 title="Hide/Show the output of the current cell">
176 title="Hide/Show the output of the current cell">
177 <a href="#">Toggle</a>
177 <a href="#">Toggle</a>
178 </li>
178 </li>
179 <li id="toggle_current_output_scroll"
179 <li id="toggle_current_output_scroll"
180 title="Scroll the output of the current cell">
180 title="Scroll the output of the current cell">
181 <a href="#">Toggle Scrolling</a>
181 <a href="#">Toggle Scrolling</a>
182 </li>
182 </li>
183 <li id="clear_current_output"
183 <li id="clear_current_output"
184 title="Clear the output of the current cell">
184 title="Clear the output of the current cell">
185 <a href="#">Clear</a>
185 <a href="#">Clear</a>
186 </li>
186 </li>
187 </ul>
187 </ul>
188 </li>
188 </li>
189 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
189 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
190 <ul class="dropdown-menu">
190 <ul class="dropdown-menu">
191 <li id="toggle_all_output"
191 <li id="toggle_all_output"
192 title="Hide/Show the output of all cells">
192 title="Hide/Show the output of all cells">
193 <a href="#">Toggle</a>
193 <a href="#">Toggle</a>
194 </li>
194 </li>
195 <li id="toggle_all_output_scroll"
195 <li id="toggle_all_output_scroll"
196 title="Scroll the output of all cells">
196 title="Scroll the output of all cells">
197 <a href="#">Toggle Scrolling</a>
197 <a href="#">Toggle Scrolling</a>
198 </li>
198 </li>
199 <li id="clear_all_output"
199 <li id="clear_all_output"
200 title="Clear the output of all cells">
200 title="Clear the output of all cells">
201 <a href="#">Clear</a>
201 <a href="#">Clear</a>
202 </li>
202 </li>
203 </ul>
203 </ul>
204 </li>
204 </li>
205 </ul>
205 </ul>
206 </li>
206 </li>
207 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
207 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
208 <ul id="kernel_menu" class="dropdown-menu">
208 <ul id="kernel_menu" class="dropdown-menu">
209 <li id="int_kernel"
209 <li id="int_kernel"
210 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
210 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
211 <a href="#">Interrupt</a></li>
211 <a href="#">Interrupt</a></li>
212 <li id="restart_kernel"
212 <li id="restart_kernel"
213 title="Restart the Kernel">
213 title="Restart the Kernel">
214 <a href="#">Restart</a></li>
214 <a href="#">Restart</a></li>
215 </ul>
215 </ul>
216 </li>
216 </li>
217 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
217 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
218 <ul id="help_menu" class="dropdown-menu">
218 <ul id="help_menu" class="dropdown-menu">
219 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
219 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
220 <li class="divider"></li>
220 <li class="divider"></li>
221 {% set
221 {% set
222 sections = (
222 sections = (
223 (
223 (
224 ("http://ipython.org/documentation.html","IPython Help",True),
224 ("http://ipython.org/documentation.html","IPython Help",True),
225 ("http://nbviewer.ipython.org/github/ipython/ipython/tree/master/examples/notebooks/", "Notebook Examples", True),
225 ("http://nbviewer.ipython.org/github/ipython/ipython/tree/master/examples/notebooks/", "Notebook Examples", True),
226 ("http://ipython.org/ipython-doc/stable/interactive/notebook.html","Notebook Help",True),
226 ("http://ipython.org/ipython-doc/stable/interactive/notebook.html","Notebook Help",True),
227 ("http://ipython.org/ipython-doc/dev/interactive/cm_keyboard.html","Editor Shortcuts",True),
227 ("http://ipython.org/ipython-doc/dev/interactive/cm_keyboard.html","Editor Shortcuts",True),
228 ),(
228 ),(
229 ("http://docs.python.org","Python",True),
229 ("http://docs.python.org","Python",True),
230 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
230 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
231 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
231 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
232 ("http://matplotlib.org/contents.html","Matplotlib",True),
232 ("http://matplotlib.org/contents.html","Matplotlib",True),
233 ("http://docs.sympy.org/dev/index.html","SymPy",True),
233 ("http://docs.sympy.org/dev/index.html","SymPy",True),
234 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
234 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
235 )
235 )
236 )
236 )
237 %}
237 %}
238
238
239 {% for helplinks in sections %}
239 {% for helplinks in sections %}
240 {% for link in helplinks %}
240 {% for link in helplinks %}
241 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
241 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
242 {{'<i class="icon-external-link menu-icon pull-right"></i>' if link[2]}}
242 {{'<i class="icon-external-link menu-icon pull-right"></i>' if link[2]}}
243 {{link[1]}}
243 {{link[1]}}
244 </a></li>
244 </a></li>
245 {% endfor %}
245 {% endfor %}
246 {% if not loop.last %}
246 {% if not loop.last %}
247 <li class="divider"></li>
247 <li class="divider"></li>
248 {% endif %}
248 {% endif %}
249 {% endfor %}
249 {% endfor %}
250 </li>
250 </li>
251 </ul>
251 </ul>
252 </li>
252 </li>
253 </ul>
253 </ul>
254 <div class='pull-right' id="indicator_area">
254 <div id="kernel_indicator" class="indicator_area pull-right">
255 <div id="kernel_indicator"></div>
255 <i id="kernel_indicator_icon"></i>
256 </div>
257 <div id="modal_indicator" class="indicator_area pull-right">
258 <i id="modal_indicator_icon"></i>
256 </div>
259 </div>
257 <div id="notification_area"></div>
260 <div id="notification_area"></div>
258 </div>
261 </div>
259 </div>
262 </div>
260 </div>
263 </div>
261 </div>
264 </div>
262 <div id="maintoolbar" class="navbar">
265 <div id="maintoolbar" class="navbar">
263 <div class="toolbar-inner navbar-inner navbar-nobg">
266 <div class="toolbar-inner navbar-inner navbar-nobg">
264 <div id="maintoolbar-container" class="container"></div>
267 <div id="maintoolbar-container" class="container"></div>
265 </div>
268 </div>
266 </div>
269 </div>
267 </div>
270 </div>
268
271
269 <div id="ipython-main-app">
272 <div id="ipython-main-app">
270
273
271 <div id="notebook_panel">
274 <div id="notebook_panel">
272 <div id="notebook"></div>
275 <div id="notebook"></div>
273 <div id="pager_splitter"></div>
276 <div id="pager_splitter"></div>
274 <div id="pager">
277 <div id="pager">
275 <div id='pager_button_area'>
278 <div id='pager_button_area'>
276 </div>
279 </div>
277 <div id="pager-container" class="container"></div>
280 <div id="pager-container" class="container"></div>
278 </div>
281 </div>
279 </div>
282 </div>
280
283
281 </div>
284 </div>
282 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
285 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
283
286
284
287
285 {% endblock %}
288 {% endblock %}
286
289
287
290
288 {% block script %}
291 {% block script %}
289
292
290 {{super()}}
293 {{super()}}
291
294
292 <script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
295 <script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
293 <script type="text/javascript">
296 <script type="text/javascript">
294 CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js") }}";
297 CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js") }}";
295 </script>
298 </script>
296 <script src="{{ static_url("components/codemirror/addon/mode/loadmode.js") }}" charset="utf-8"></script>
299 <script src="{{ static_url("components/codemirror/addon/mode/loadmode.js") }}" charset="utf-8"></script>
297 <script src="{{ static_url("components/codemirror/addon/mode/multiplex.js") }}" charset="utf-8"></script>
300 <script src="{{ static_url("components/codemirror/addon/mode/multiplex.js") }}" charset="utf-8"></script>
298 <script src="{{ static_url("components/codemirror/addon/mode/overlay.js") }}" charset="utf-8"></script>
301 <script src="{{ static_url("components/codemirror/addon/mode/overlay.js") }}" charset="utf-8"></script>
299 <script src="{{ static_url("components/codemirror/addon/edit/matchbrackets.js") }}" charset="utf-8"></script>
302 <script src="{{ static_url("components/codemirror/addon/edit/matchbrackets.js") }}" charset="utf-8"></script>
300 <script src="{{ static_url("components/codemirror/addon/comment/comment.js") }}" charset="utf-8"></script>
303 <script src="{{ static_url("components/codemirror/addon/comment/comment.js") }}" charset="utf-8"></script>
301 <script src="{{ static_url("components/codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
304 <script src="{{ static_url("components/codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
302 <script src="{{ static_url("components/codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
305 <script src="{{ static_url("components/codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
303 <script src="{{ static_url("components/codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
306 <script src="{{ static_url("components/codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
304 <script src="{{ static_url("components/codemirror/mode/css/css.js") }}" charset="utf-8"></script>
307 <script src="{{ static_url("components/codemirror/mode/css/css.js") }}" charset="utf-8"></script>
305 <script src="{{ static_url("components/codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
308 <script src="{{ static_url("components/codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
306 <script src="{{ static_url("components/codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
309 <script src="{{ static_url("components/codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
307 <script src="{{ static_url("components/codemirror/mode/gfm/gfm.js") }}" charset="utf-8"></script>
310 <script src="{{ static_url("components/codemirror/mode/gfm/gfm.js") }}" charset="utf-8"></script>
308 <script src="{{ static_url("components/codemirror/mode/python/python.js") }}" charset="utf-8"></script>
311 <script src="{{ static_url("components/codemirror/mode/python/python.js") }}" charset="utf-8"></script>
309 <script src="{{ static_url("notebook/js/codemirror-ipython.js") }}" charset="utf-8"></script>
312 <script src="{{ static_url("notebook/js/codemirror-ipython.js") }}" charset="utf-8"></script>
310
313
311 <script src="{{ static_url("components/highlight.js/build/highlight.pack.js") }}" charset="utf-8"></script>
314 <script src="{{ static_url("components/highlight.js/build/highlight.pack.js") }}" charset="utf-8"></script>
312
315
313 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
316 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
314
317
315 <script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
318 <script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
316 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
319 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
317 <script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
320 <script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
318 <script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
321 <script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
319 <script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
322 <script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
320 <script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
323 <script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
321 <script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
324 <script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
322 <script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
325 <script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
323 <script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
326 <script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
324 <script src="{{ static_url("notebook/js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
327 <script src="{{ static_url("notebook/js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
325 <script src="{{ static_url("notebook/js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
328 <script src="{{ static_url("notebook/js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
326 <script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
329 <script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
327 <script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
330 <script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
328 <script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
331 <script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
329 <script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
332 <script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
330 <script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
333 <script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
331 <script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
334 <script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
332 <script src="{{ static_url("notebook/js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
335 <script src="{{ static_url("notebook/js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
333 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
336 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
334 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
337 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
335 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
338 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
336 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
339 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
337 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
340 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
338 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
341 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
339 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
342 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
340 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
343 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
341 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
344 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
342
345
343 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
346 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
344
347
345 <script src="{{ static_url("notebook/js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
348 <script src="{{ static_url("notebook/js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
346 <script src="{{ static_url("notebook/js/celltoolbarpresets/rawcell.js") }}" type="text/javascript" charset="utf-8"></script>
349 <script src="{{ static_url("notebook/js/celltoolbarpresets/rawcell.js") }}" type="text/javascript" charset="utf-8"></script>
347 <script src="{{ static_url("notebook/js/celltoolbarpresets/slideshow.js") }}" type="text/javascript" charset="utf-8"></script>
350 <script src="{{ static_url("notebook/js/celltoolbarpresets/slideshow.js") }}" type="text/javascript" charset="utf-8"></script>
348
351
349 {% endblock %}
352 {% endblock %}
@@ -1,96 +1,96 b''
1
1
2
2
3 <!DOCTYPE HTML>
3 <!DOCTYPE HTML>
4 <html>
4 <html>
5
5
6 <head>
6 <head>
7 <meta charset="utf-8">
7 <meta charset="utf-8">
8
8
9 <title>{% block title %}IPython Notebook{% endblock %}</title>
9 <title>{% block title %}IPython Notebook{% endblock %}</title>
10 <link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">
10 <link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">
11 <meta http-equiv="X-UA-Compatible" content="chrome=1">
11 <meta http-equiv="X-UA-Compatible" content="chrome=1">
12 <link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" />
12 <link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" />
13 <meta name="viewport" content="width=device-width, initial-scale=1.0">
13 <meta name="viewport" content="width=device-width, initial-scale=1.0">
14
14
15 {% block stylesheet %}
15 {% block stylesheet %}
16 <link rel="stylesheet" href="{{ static_url("style/style.min.css") }}" type="text/css"/>
16 <link rel="stylesheet" href="{{ static_url("style/style.min.css") }}" type="text/css"/>
17 {% endblock %}
17 {% endblock %}
18 <link rel="stylesheet" href="{{ static_url("custom/custom.css") }}" type="text/css" />
18 <link rel="stylesheet" href="{{ static_url("custom/custom.css") }}" type="text/css" />
19 <script src="{{static_url("components/requirejs/require.js") }}" type="text/javascript" charset="utf-8"></script>
19 <script src="{{static_url("components/requirejs/require.js") }}" type="text/javascript" charset="utf-8"></script>
20 <script>
20 <script>
21 require.config({
21 require.config({
22 baseUrl: '{{static_url("")}}',
22 baseUrl: '{{static_url("")}}',
23 paths: {
23 paths: {
24 nbextensions : '{{ base_project_url }}nbextensions',
24 nbextensions : '{{ base_url }}nbextensions',
25 underscore : '{{static_url("components/underscore/underscore-min")}}',
25 underscore : '{{static_url("components/underscore/underscore-min")}}',
26 backbone : '{{static_url("components/backbone/backbone-min")}}',
26 backbone : '{{static_url("components/backbone/backbone-min")}}',
27 },
27 },
28 shim: {
28 shim: {
29 underscore: {
29 underscore: {
30 exports: '_'
30 exports: '_'
31 },
31 },
32 backbone: {
32 backbone: {
33 deps: ["underscore", "jquery"],
33 deps: ["underscore", "jquery"],
34 exports: "Backbone"
34 exports: "Backbone"
35 }
35 }
36 }
36 }
37 });
37 });
38 </script>
38 </script>
39
39
40 {% block meta %}
40 {% block meta %}
41 {% endblock %}
41 {% endblock %}
42
42
43 </head>
43 </head>
44
44
45 <body {% block params %}{% endblock %}>
45 <body {% block params %}{% endblock %}>
46
46
47 <noscript>
47 <noscript>
48 <div id='noscript'>
48 <div id='noscript'>
49 IPython Notebook requires JavaScript.<br>
49 IPython Notebook requires JavaScript.<br>
50 Please enable it to proceed.
50 Please enable it to proceed.
51 </div>
51 </div>
52 </noscript>
52 </noscript>
53
53
54 <div id="header" class="navbar navbar-static-top">
54 <div id="header" class="navbar navbar-static-top">
55 <div class="navbar-inner navbar-nobg">
55 <div class="navbar-inner navbar-nobg">
56 <div class="container">
56 <div class="container">
57 <div id="ipython_notebook" class="nav brand pull-left"><a href="{{base_project_url}}tree/{{notebook_path}}" alt='dashboard'><img src='{{static_url("base/images/ipynblogo.png") }}' alt='IPython Notebook'/></a></div>
57 <div id="ipython_notebook" class="nav brand pull-left"><a href="{{base_url}}tree/{{notebook_path}}" alt='dashboard'><img src='{{static_url("base/images/ipynblogo.png") }}' alt='IPython Notebook'/></a></div>
58
58
59 {% block login_widget %}
59 {% block login_widget %}
60
60
61 <span id="login_widget">
61 <span id="login_widget">
62 {% if logged_in %}
62 {% if logged_in %}
63 <button id="logout">Logout</button>
63 <button id="logout">Logout</button>
64 {% elif login_available and not logged_in %}
64 {% elif login_available and not logged_in %}
65 <button id="login">Login</button>
65 <button id="login">Login</button>
66 {% endif %}
66 {% endif %}
67 </span>
67 </span>
68
68
69 {% endblock %}
69 {% endblock %}
70
70
71 {% block header %}
71 {% block header %}
72 {% endblock %}
72 {% endblock %}
73 </div>
73 </div>
74 </div>
74 </div>
75 </div>
75 </div>
76
76
77 <div id="site">
77 <div id="site">
78 {% block site %}
78 {% block site %}
79 {% endblock %}
79 {% endblock %}
80 </div>
80 </div>
81
81
82 <script src="{{static_url("components/jquery/jquery.min.js") }}" type="text/javascript" charset="utf-8"></script>
82 <script src="{{static_url("components/jquery/jquery.min.js") }}" type="text/javascript" charset="utf-8"></script>
83 <script src="{{static_url("components/jquery-ui/ui/minified/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
83 <script src="{{static_url("components/jquery-ui/ui/minified/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
84 <script src="{{static_url("components/bootstrap/bootstrap/js/bootstrap.min.js") }}" type="text/javascript" charset="utf-8"></script>
84 <script src="{{static_url("components/bootstrap/bootstrap/js/bootstrap.min.js") }}" type="text/javascript" charset="utf-8"></script>
85 <script src="{{static_url("base/js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
85 <script src="{{static_url("base/js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
86 <script src="{{static_url("base/js/page.js") }}" type="text/javascript" charset="utf-8"></script>
86 <script src="{{static_url("base/js/page.js") }}" type="text/javascript" charset="utf-8"></script>
87 <script src="{{static_url("auth/js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
87 <script src="{{static_url("auth/js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
88
88
89 {% block script %}
89 {% block script %}
90 {% endblock %}
90 {% endblock %}
91
91
92 <script src="{{static_url("custom/custom.js") }}" type="text/javascript" charset="utf-8"></script>
92 <script src="{{static_url("custom/custom.js") }}" type="text/javascript" charset="utf-8"></script>
93
93
94 </body>
94 </body>
95
95
96 </html>
96 </html>
@@ -1,99 +1,99 b''
1 {% extends "page.html" %}
1 {% extends "page.html" %}
2
2
3 {% block title %}{{page_title}}{% endblock %}
3 {% block title %}{{page_title}}{% endblock %}
4
4
5
5
6 {% block stylesheet %}
6 {% block stylesheet %}
7 {{super()}}
7 {{super()}}
8 <link rel="stylesheet" href="{{ static_url("tree/css/override.css") }}" type="text/css" />
8 <link rel="stylesheet" href="{{ static_url("tree/css/override.css") }}" type="text/css" />
9 {% endblock %}
9 {% endblock %}
10
10
11 {% block params %}
11 {% block params %}
12
12
13 data-project="{{project}}"
13 data-project="{{project}}"
14 data-base-project-url="{{base_project_url}}"
14 data-base-url="{{base_url}}"
15 data-notebook-path="{{notebook_path}}"
15 data-notebook-path="{{notebook_path}}"
16 data-base-kernel-url="{{base_kernel_url}}"
16 data-base-kernel-url="{{base_kernel_url}}"
17
17
18 {% endblock %}
18 {% endblock %}
19
19
20
20
21 {% block site %}
21 {% block site %}
22
22
23 <div id="ipython-main-app" class="container">
23 <div id="ipython-main-app" class="container">
24
24
25 <div id="tab_content" class="tabbable">
25 <div id="tab_content" class="tabbable">
26 <ul id="tabs" class="nav nav-tabs">
26 <ul id="tabs" class="nav nav-tabs">
27 <li class="active"><a href="#notebooks" data-toggle="tab">Notebooks</a></li>
27 <li class="active"><a href="#notebooks" data-toggle="tab">Notebooks</a></li>
28 <li><a href="#clusters" data-toggle="tab">Clusters</a></li>
28 <li><a href="#clusters" data-toggle="tab">Clusters</a></li>
29 </ul>
29 </ul>
30
30
31 <div class="tab-content">
31 <div class="tab-content">
32 <div id="notebooks" class="tab-pane active">
32 <div id="notebooks" class="tab-pane active">
33 <div id="notebook_toolbar" class="row-fluid">
33 <div id="notebook_toolbar" class="row-fluid">
34 <div class="span8">
34 <div class="span8">
35 <form id='alternate_upload' class='alternate_upload' >
35 <form id='alternate_upload' class='alternate_upload' >
36 <span id="drag_info" style="position:absolute" >
36 <span id="drag_info" style="position:absolute" >
37 To import a notebook, drag the file onto the listing below or <strong>click here</strong>.
37 To import a notebook, drag the file onto the listing below or <strong>click here</strong>.
38 </span>
38 </span>
39 <input type="file" name="datafile" class="fileinput" multiple='multiple'>
39 <input type="file" name="datafile" class="fileinput" multiple='multiple'>
40 </form>
40 </form>
41 </div>
41 </div>
42 <div class="span4 clearfix">
42 <div class="span4 clearfix">
43 <span id="notebook_buttons" class="pull-right">
43 <span id="notebook_buttons" class="pull-right">
44 <button id="new_notebook" title="Create new notebook" class="btn btn-small">New Notebook</button>
44 <button id="new_notebook" title="Create new notebook" class="btn btn-small">New Notebook</button>
45 <button id="refresh_notebook_list" title="Refresh notebook list" class="btn btn-small"><i class="icon-refresh"></i></button>
45 <button id="refresh_notebook_list" title="Refresh notebook list" class="btn btn-small"><i class="icon-refresh"></i></button>
46 </span>
46 </span>
47 </div>
47 </div>
48 </div>
48 </div>
49
49
50 <div id="notebook_list">
50 <div id="notebook_list">
51 <div id="notebook_list_header" class="row-fluid list_header">
51 <div id="notebook_list_header" class="row-fluid list_header">
52 <div id="project_name">
52 <div id="project_name">
53 <ul class="breadcrumb">
53 <ul class="breadcrumb">
54 <li><a href="{{breadcrumbs[0][0]}}"><i class="icon-home"></i></a><span>/</span></li>
54 <li><a href="{{breadcrumbs[0][0]}}"><i class="icon-home"></i></a><span>/</span></li>
55 {% for crumb in breadcrumbs[1:] %}
55 {% for crumb in breadcrumbs[1:] %}
56 <li><a href="{{crumb[0]}}">{{crumb[1]}}</a> <span>/</span></li>
56 <li><a href="{{crumb[0]}}">{{crumb[1]}}</a> <span>/</span></li>
57 {% endfor %}
57 {% endfor %}
58 </ul>
58 </ul>
59 </div>
59 </div>
60 </div>
60 </div>
61 </div>
61 </div>
62 </div>
62 </div>
63
63
64 <div id="clusters" class="tab-pane">
64 <div id="clusters" class="tab-pane">
65
65
66 <div id="cluster_toolbar" class="row-fluid">
66 <div id="cluster_toolbar" class="row-fluid">
67 <div class="span8">
67 <div class="span8">
68 <span id="cluster_list_info">IPython parallel computing clusters</span>
68 <span id="cluster_list_info">IPython parallel computing clusters</span>
69 </div>
69 </div>
70 <div class="span4" class="clearfix">
70 <div class="span4" class="clearfix">
71 <span id="cluster_buttons" class="pull-right">
71 <span id="cluster_buttons" class="pull-right">
72 <button id="refresh_cluster_list" title="Refresh cluster list" class="btn btn-small"><i class="icon-refresh"></i></button>
72 <button id="refresh_cluster_list" title="Refresh cluster list" class="btn btn-small"><i class="icon-refresh"></i></button>
73 </span>
73 </span>
74 </div>
74 </div>
75 </div>
75 </div>
76
76
77 <div id="cluster_list">
77 <div id="cluster_list">
78 <div id="cluster_list_header" class="row-fluid list_header">
78 <div id="cluster_list_header" class="row-fluid list_header">
79 <div class="profile_col span4">profile</div>
79 <div class="profile_col span4">profile</div>
80 <div class="status_col span3">status</div>
80 <div class="status_col span3">status</div>
81 <div class="engines_col span3" title="Enter the number of engines to start or empty for default"># of engines</div>
81 <div class="engines_col span3" title="Enter the number of engines to start or empty for default"># of engines</div>
82 <div class="action_col span2">action</div>
82 <div class="action_col span2">action</div>
83 </div>
83 </div>
84 </div>
84 </div>
85 </div>
85 </div>
86 </div>
86 </div>
87
87
88 </div>
88 </div>
89
89
90 {% endblock %}
90 {% endblock %}
91
91
92 {% block script %}
92 {% block script %}
93 {{super()}}
93 {{super()}}
94 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
94 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
95 <script src="{{static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
95 <script src="{{static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
96 <script src="{{static_url("tree/js/notebooklist.js") }}" type="text/javascript" charset="utf-8"></script>
96 <script src="{{static_url("tree/js/notebooklist.js") }}" type="text/javascript" charset="utf-8"></script>
97 <script src="{{static_url("tree/js/clusterlist.js") }}" type="text/javascript" charset="utf-8"></script>
97 <script src="{{static_url("tree/js/clusterlist.js") }}" type="text/javascript" charset="utf-8"></script>
98 <script src="{{static_url("tree/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
98 <script src="{{static_url("tree/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
99 {% endblock %}
99 {% endblock %}
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/README.md to IPython/html/tests/README.md
NO CONTENT: file renamed from IPython/html/tests/casperjs/README.md to IPython/html/tests/README.md
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/misc_tests.js to IPython/html/tests/base/misc.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/misc_tests.js to IPython/html/tests/base/misc.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/nb_arrow_keys.js to IPython/html/tests/notebook/arrow_keys.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/nb_arrow_keys.js to IPython/html/tests/notebook/arrow_keys.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/display_image.js to IPython/html/tests/notebook/display_image.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/display_image.js to IPython/html/tests/notebook/display_image.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/empty_nb_arrow_keys.js to IPython/html/tests/notebook/empty_arrow_keys.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/empty_nb_arrow_keys.js to IPython/html/tests/notebook/empty_arrow_keys.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/execute_code_cell.js to IPython/html/tests/notebook/execute_code.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/execute_code_cell.js to IPython/html/tests/notebook/execute_code.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/inject_js.js to IPython/html/tests/notebook/inject_js.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/inject_js.js to IPython/html/tests/notebook/inject_js.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/check_interrupt.js to IPython/html/tests/notebook/interrupt.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/check_interrupt.js to IPython/html/tests/notebook/interrupt.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/isolated_svg.js to IPython/html/tests/notebook/isolated_svg.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/isolated_svg.js to IPython/html/tests/notebook/isolated_svg.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/render_markdown.js to IPython/html/tests/notebook/markdown.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/render_markdown.js to IPython/html/tests/notebook/markdown.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/merge_cells.js to IPython/html/tests/notebook/merge_cells.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/merge_cells.js to IPython/html/tests/notebook/merge_cells.js
@@ -1,246 +1,245 b''
1 // Test opening a rich notebook, saving it, and reopening it again.
1 // Test opening a rich notebook, saving it, and reopening it again.
2 //
2 //
3 //toJSON fromJSON toJSON and do a string comparison
3 //toJSON fromJSON toJSON and do a string comparison
4
4
5
5
6 // this is just a copy of OutputArea.mime_mape_r in IPython/html/static/notebook/js/outputarea.js
6 // this is just a copy of OutputArea.mime_mape_r in IPython/html/static/notebook/js/outputarea.js
7 mime = {
7 mime = {
8 "text" : "text/plain",
8 "text" : "text/plain",
9 "html" : "text/html",
9 "html" : "text/html",
10 "svg" : "image/svg+xml",
10 "svg" : "image/svg+xml",
11 "png" : "image/png",
11 "png" : "image/png",
12 "jpeg" : "image/jpeg",
12 "jpeg" : "image/jpeg",
13 "latex" : "text/latex",
13 "latex" : "text/latex",
14 "json" : "application/json",
14 "json" : "application/json",
15 "javascript" : "application/javascript",
15 "javascript" : "application/javascript",
16 };
16 };
17
17
18 var black_dot_jpeg="u\"\"\"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDACodICUgGiolIiUvLSoyP2lEPzo6P4FcYUxpmYagnpaG\nk5GovfLNqLPltZGT0v/V5fr/////o8v///////L/////2wBDAS0vLz83P3xERHz/rpOu////////\n////////////////////////////////////////////////////////////wgARCAABAAEDAREA\nAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAABP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEA\nAhADEAAAARn/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAA\nAAAAAAAA/9oACAEDAQE/AX//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AX//xAAUEAEA\nAAAAAAAAAAAAAAAAAAAA/9oACAEBAAY/An//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nIX//2gAMAwEAAgADAAAAEB//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/EH//xAAUEQEA\nAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/EH//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nEH//2Q==\"\"\"";
18 var black_dot_jpeg="u\"\"\"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDACodICUgGiolIiUvLSoyP2lEPzo6P4FcYUxpmYagnpaG\nk5GovfLNqLPltZGT0v/V5fr/////o8v///////L/////2wBDAS0vLz83P3xERHz/rpOu////////\n////////////////////////////////////////////////////////////wgARCAABAAEDAREA\nAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAABP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEA\nAhADEAAAARn/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAA\nAAAAAAAA/9oACAEDAQE/AX//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AX//xAAUEAEA\nAAAAAAAAAAAAAAAAAAAA/9oACAEBAAY/An//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nIX//2gAMAwEAAgADAAAAEB//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/EH//xAAUEQEA\nAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/EH//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nEH//2Q==\"\"\"";
19 var black_dot_png = 'u\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QA\\niAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AA\\nAAACAAHiIbwzAAAAAElFTkSuQmCC\"';
19 var black_dot_png = 'u\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QA\\niAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AA\\nAAACAAHiIbwzAAAAAElFTkSuQmCC\"';
20 var svg = "\"<svg width='1cm' height='1cm' viewBox='0 0 1000 500'><defs><style>rect {fill:red;}; </style></defs><rect id='r1' x='200' y='100' width='600' height='300' /></svg>\"";
20 var svg = "\"<svg width='1cm' height='1cm' viewBox='0 0 1000 500'><defs><style>rect {fill:red;}; </style></defs><rect id='r1' x='200' y='100' width='600' height='300' /></svg>\"";
21
21
22 // helper function to ensure that the short_name is found in the toJSON
22 // helper function to ensure that the short_name is found in the toJSON
23 // represetnation, while the original in-memory cell retains its long mimetype
23 // represetnation, while the original in-memory cell retains its long mimetype
24 // name, and that fromJSON also gets its long mimetype name
24 // name, and that fromJSON also gets its long mimetype name
25 function assert_has(short_name, json, result, result2) {
25 function assert_has(short_name, json, result, result2) {
26 long_name = mime[short_name];
26 long_name = mime[short_name];
27 this.test.assertTrue(json[0].hasOwnProperty(short_name),
27 this.test.assertTrue(json[0].hasOwnProperty(short_name),
28 'toJSON() representation uses ' + short_name);
28 'toJSON() representation uses ' + short_name);
29 this.test.assertTrue(result.hasOwnProperty(long_name),
29 this.test.assertTrue(result.hasOwnProperty(long_name),
30 'toJSON() original embedded JSON keeps ' + long_name);
30 'toJSON() original embedded JSON keeps ' + long_name);
31 this.test.assertTrue(result2.hasOwnProperty(long_name),
31 this.test.assertTrue(result2.hasOwnProperty(long_name),
32 'fromJSON() embedded ' + short_name + ' gets mime key ' + long_name);
32 'fromJSON() embedded ' + short_name + ' gets mime key ' + long_name);
33 }
33 }
34
34
35 // helper function for checkout that the first two cells have a particular
35 // helper function for checkout that the first two cells have a particular
36 // output_type (either 'pyout' or 'display_data'), and checks the to/fromJSON
36 // output_type (either 'pyout' or 'display_data'), and checks the to/fromJSON
37 // for a set of mimetype keys, using their short names ('javascript', 'text',
37 // for a set of mimetype keys, using their short names ('javascript', 'text',
38 // 'png', etc).
38 // 'png', etc).
39 function check_output_area(output_type, keys) {
39 function check_output_area(output_type, keys) {
40 this.wait_for_output(0);
40 this.wait_for_output(0);
41 json = this.evaluate(function() {
41 json = this.evaluate(function() {
42 var json = IPython.notebook.get_cell(0).output_area.toJSON();
42 var json = IPython.notebook.get_cell(0).output_area.toJSON();
43 // appended cell will initially be empty, let's add some output
43 // appended cell will initially be empty, let's add some output
44 IPython.notebook.get_cell(1).output_area.fromJSON(json);
44 IPython.notebook.get_cell(1).output_area.fromJSON(json);
45 return json;
45 return json;
46 });
46 });
47 // The evaluate call above happens asynchronously: wait for cell[1] to have output
47 // The evaluate call above happens asynchronously: wait for cell[1] to have output
48 this.wait_for_output(1);
48 this.wait_for_output(1);
49 var result = this.get_output_cell(0);
49 var result = this.get_output_cell(0);
50 var result2 = this.get_output_cell(1);
50 var result2 = this.get_output_cell(1);
51 this.test.assertEquals(result.output_type, output_type,
51 this.test.assertEquals(result.output_type, output_type,
52 'testing ' + output_type + ' for ' + keys.join(' and '));
52 'testing ' + output_type + ' for ' + keys.join(' and '));
53
53
54 for (var idx in keys) {
54 for (var idx in keys) {
55 assert_has.apply(this, [keys[idx], json, result, result2]);
55 assert_has.apply(this, [keys[idx], json, result, result2]);
56 }
56 }
57 }
57 }
58
58
59
59
60 // helper function to clear the first two cells, set the text of and execute
60 // helper function to clear the first two cells, set the text of and execute
61 // the first one
61 // the first one
62 function clear_and_execute(that, code) {
62 function clear_and_execute(that, code) {
63 that.evaluate(function() {
63 that.evaluate(function() {
64 IPython.notebook.get_cell(0).clear_output();
64 IPython.notebook.get_cell(0).clear_output();
65 IPython.notebook.get_cell(1).clear_output();
65 IPython.notebook.get_cell(1).clear_output();
66 });
66 });
67 that.set_cell_text(0, code);
67 that.then(function () {
68 that.execute_cell(0);
68 that.set_cell_text(0, code);
69 }
69 that.execute_cell(0);
70 that.wait_for_idle();
71 });
72 };
70
73
71 casper.notebook_test(function () {
74 casper.notebook_test(function () {
72 this.evaluate(function () {
75 this.evaluate(function () {
73 var cell = IPython.notebook.get_cell(0);
76 var cell = IPython.notebook.get_cell(0);
74 // "we have to make messes to find out who we are"
77 // "we have to make messes to find out who we are"
75 cell.set_text([
78 cell.set_text([
76 "%%javascript",
79 "%%javascript",
77 "IPython.notebook.insert_cell_below('code')"
80 "IPython.notebook.insert_cell_below('code')"
78 ].join('\n')
81 ].join('\n')
79 );
82 );
80
81 cell.execute();
82 });
83 });
83
84
84 this.wait_for_output(0);
85 this.execute_cell_then(0, function () {
85
86 this.then(function ( ) {
87 var result = this.get_output_cell(0);
86 var result = this.get_output_cell(0);
88 var num_cells = this.get_cells_length();
87 var num_cells = this.get_cells_length();
89 this.test.assertEquals(num_cells, 2, '%%javascript magic works');
88 this.test.assertEquals(num_cells, 2, '%%javascript magic works');
90 this.test.assertTrue(result.hasOwnProperty('application/javascript'),
89 this.test.assertTrue(result.hasOwnProperty('application/javascript'),
91 'testing JS embedded with mime key');
90 'testing JS embedded with mime key');
92 });
91 });
93
92
94 //this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
93 //this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
95 this.then(function () {
94 this.then(function () {
96 clear_and_execute(this, [
95 clear_and_execute(this, [
97 "%%javascript",
96 "%%javascript",
98 "var a=5;"
97 "var a=5;"
99 ].join('\n'));
98 ].join('\n'));
100 });
99 });
101
100
102
101
103 this.then(function () {
102 this.then(function () {
104 check_output_area.apply(this, ['display_data', ['javascript']]);
103 check_output_area.apply(this, ['display_data', ['javascript']]);
105
104
106 });
105 });
107
106
108 this.then(function() {
107 this.then(function() {
109 clear_and_execute(this, '%lsmagic');
108 clear_and_execute(this, '%lsmagic');
110 });
109 });
111
110
112 this.then(function () {
111 this.then(function () {
113 check_output_area.apply(this, ['pyout', ['text', 'json']]);
112 check_output_area.apply(this, ['pyout', ['text', 'json']]);
114 });
113 });
115
114
116 this.then(function() {
115 this.then(function() {
117 clear_and_execute(this,
116 clear_and_execute(this,
118 "x = %lsmagic\nfrom IPython.display import display; display(x)");
117 "x = %lsmagic\nfrom IPython.display import display; display(x)");
119 });
118 });
120
119
121 this.then(function ( ) {
120 this.then(function ( ) {
122 check_output_area.apply(this, ['display_data', ['text', 'json']]);
121 check_output_area.apply(this, ['display_data', ['text', 'json']]);
123 });
122 });
124
123
125 this.then(function() {
124 this.then(function() {
126 clear_and_execute(this,
125 clear_and_execute(this,
127 "from IPython.display import Latex; Latex('$X^2$')");
126 "from IPython.display import Latex; Latex('$X^2$')");
128 });
127 });
129
128
130 this.then(function ( ) {
129 this.then(function ( ) {
131 check_output_area.apply(this, ['pyout', ['text', 'latex']]);
130 check_output_area.apply(this, ['pyout', ['text', 'latex']]);
132 });
131 });
133
132
134 this.then(function() {
133 this.then(function() {
135 clear_and_execute(this,
134 clear_and_execute(this,
136 "from IPython.display import Latex, display; display(Latex('$X^2$'))");
135 "from IPython.display import Latex, display; display(Latex('$X^2$'))");
137 });
136 });
138
137
139 this.then(function ( ) {
138 this.then(function ( ) {
140 check_output_area.apply(this, ['display_data', ['text', 'latex']]);
139 check_output_area.apply(this, ['display_data', ['text', 'latex']]);
141 });
140 });
142
141
143 this.then(function() {
142 this.then(function() {
144 clear_and_execute(this,
143 clear_and_execute(this,
145 "from IPython.display import HTML; HTML('<b>it works!</b>')");
144 "from IPython.display import HTML; HTML('<b>it works!</b>')");
146 });
145 });
147
146
148 this.then(function ( ) {
147 this.then(function ( ) {
149 check_output_area.apply(this, ['pyout', ['text', 'html']]);
148 check_output_area.apply(this, ['pyout', ['text', 'html']]);
150 });
149 });
151
150
152 this.then(function() {
151 this.then(function() {
153 clear_and_execute(this,
152 clear_and_execute(this,
154 "from IPython.display import HTML, display; display(HTML('<b>it works!</b>'))");
153 "from IPython.display import HTML, display; display(HTML('<b>it works!</b>'))");
155 });
154 });
156
155
157 this.then(function ( ) {
156 this.then(function ( ) {
158 check_output_area.apply(this, ['display_data', ['text', 'html']]);
157 check_output_area.apply(this, ['display_data', ['text', 'html']]);
159 });
158 });
160
159
161
160
162 this.then(function() {
161 this.then(function() {
163 clear_and_execute(this,
162 clear_and_execute(this,
164 "from IPython.display import Image; Image(" + black_dot_png + ")");
163 "from IPython.display import Image; Image(" + black_dot_png + ")");
165 });
164 });
166 this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
165 this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
167
166
168 this.then(function ( ) {
167 this.then(function ( ) {
169 check_output_area.apply(this, ['pyout', ['text', 'png']]);
168 check_output_area.apply(this, ['pyout', ['text', 'png']]);
170 });
169 });
171
170
172 this.then(function() {
171 this.then(function() {
173 clear_and_execute(this,
172 clear_and_execute(this,
174 "from IPython.display import Image, display; display(Image(" + black_dot_png + "))");
173 "from IPython.display import Image, display; display(Image(" + black_dot_png + "))");
175 });
174 });
176
175
177 this.then(function ( ) {
176 this.then(function ( ) {
178 check_output_area.apply(this, ['display_data', ['text', 'png']]);
177 check_output_area.apply(this, ['display_data', ['text', 'png']]);
179 });
178 });
180
179
181
180
182 this.then(function() {
181 this.then(function() {
183 clear_and_execute(this,
182 clear_and_execute(this,
184 "from IPython.display import Image; Image(" + black_dot_jpeg + ", format='jpeg')");
183 "from IPython.display import Image; Image(" + black_dot_jpeg + ", format='jpeg')");
185 });
184 });
186
185
187 this.then(function ( ) {
186 this.then(function ( ) {
188 check_output_area.apply(this, ['pyout', ['text', 'jpeg']]);
187 check_output_area.apply(this, ['pyout', ['text', 'jpeg']]);
189 });
188 });
190
189
191 this.then(function() {
190 this.then(function() {
192 clear_and_execute(this,
191 clear_and_execute(this,
193 "from IPython.display import Image, display; display(Image(" + black_dot_jpeg + ", format='jpeg'))");
192 "from IPython.display import Image, display; display(Image(" + black_dot_jpeg + ", format='jpeg'))");
194 });
193 });
195
194
196 this.then(function ( ) {
195 this.then(function ( ) {
197 check_output_area.apply(this, ['display_data', ['text', 'jpeg']]);
196 check_output_area.apply(this, ['display_data', ['text', 'jpeg']]);
198 });
197 });
199
198
200 this.then(function() {
199 this.then(function() {
201 clear_and_execute(this,
200 clear_and_execute(this,
202 "from IPython.core.display import SVG; SVG(" + svg + ")");
201 "from IPython.core.display import SVG; SVG(" + svg + ")");
203 });
202 });
204
203
205 this.then(function ( ) {
204 this.then(function ( ) {
206 check_output_area.apply(this, ['pyout', ['text', 'svg']]);
205 check_output_area.apply(this, ['pyout', ['text', 'svg']]);
207 });
206 });
208
207
209 this.then(function() {
208 this.then(function() {
210 clear_and_execute(this,
209 clear_and_execute(this,
211 "from IPython.core.display import SVG, display; display(SVG(" + svg + "))");
210 "from IPython.core.display import SVG, display; display(SVG(" + svg + "))");
212 });
211 });
213
212
214 this.then(function ( ) {
213 this.then(function ( ) {
215 check_output_area.apply(this, ['display_data', ['text', 'svg']]);
214 check_output_area.apply(this, ['display_data', ['text', 'svg']]);
216 });
215 });
217
216
218 this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
217 this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
219
218
220 this.then(function() {
219 this.then(function() {
221 clear_and_execute(this, [
220 clear_and_execute(this, [
222 "from IPython.core.formatters import HTMLFormatter",
221 "from IPython.core.formatters import HTMLFormatter",
223 "x = HTMLFormatter()",
222 "x = HTMLFormatter()",
224 "x.format_type = 'text/superfancymimetype'",
223 "x.format_type = 'text/superfancymimetype'",
225 "get_ipython().display_formatter.formatters['text/superfancymimetype'] = x",
224 "get_ipython().display_formatter.formatters['text/superfancymimetype'] = x",
226 "from IPython.display import HTML, display",
225 "from IPython.display import HTML, display",
227 'display(HTML("yo"))',
226 'display(HTML("yo"))',
228 "HTML('hello')"].join('\n')
227 "HTML('hello')"].join('\n')
229 );
228 );
230
229
231 });
230 });
232
231
233 this.wait_for_output(0, 1);
232 this.wait_for_output(0, 1);
234
233
235 this.then(function () {
234 this.then(function () {
236 var long_name = 'text/superfancymimetype';
235 var long_name = 'text/superfancymimetype';
237 var result = this.get_output_cell(0);
236 var result = this.get_output_cell(0);
238 this.test.assertTrue(result.hasOwnProperty(long_name),
237 this.test.assertTrue(result.hasOwnProperty(long_name),
239 'display_data custom mimetype ' + long_name);
238 'display_data custom mimetype ' + long_name);
240 var result = this.get_output_cell(0, 1);
239 var result = this.get_output_cell(0, 1);
241 this.test.assertTrue(result.hasOwnProperty(long_name),
240 this.test.assertTrue(result.hasOwnProperty(long_name),
242 'pyout custom mimetype ' + long_name);
241 'pyout custom mimetype ' + long_name);
243
242
244 });
243 });
245
244
246 });
245 });
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/safe_append_output.js to IPython/html/tests/notebook/safe_append_output.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/safe_append_output.js to IPython/html/tests/notebook/safe_append_output.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/save_notebook.js to IPython/html/tests/notebook/save.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/save_notebook.js to IPython/html/tests/notebook/save.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/shutdown_notebook.js to IPython/html/tests/notebook/shutdown.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/shutdown_notebook.js to IPython/html/tests/notebook/shutdown.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/tooltip.js to IPython/html/tests/notebook/tooltip.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/tooltip.js to IPython/html/tests/notebook/tooltip.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/kernel_test.js to IPython/html/tests/services/kernel.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/kernel_test.js to IPython/html/tests/services/kernel.js
@@ -1,37 +1,40 b''
1
1
2
2
3 casper.get_list_items = function () {
3 casper.get_list_items = function () {
4 return this.evaluate(function () {
4 return this.evaluate(function () {
5 return $.makeArray($('.item_link').map(function () {
5 return $.makeArray($('.item_link').map(function () {
6 return {
6 return {
7 link: $(this).attr('href'),
7 link: $(this).attr('href'),
8 label: $(this).find('.item_name').text()
8 label: $(this).find('.item_name').text()
9 }
9 }
10 }));
10 }));
11 });
11 });
12 }
12 }
13
13
14 casper.test_items = function (baseUrl) {
14 casper.test_items = function (baseUrl) {
15 casper.then(function () {
15 casper.then(function () {
16 var items = casper.get_list_items();
16 var items = casper.get_list_items();
17 casper.each(items, function (self, item) {
17 casper.each(items, function (self, item) {
18 if (!item.label.match('.ipynb$')) {
18 if (!item.label.match('.ipynb$')) {
19 var followed_url = baseUrl+item.link;
19 var followed_url = baseUrl+item.link;
20 if (!followed_url.match('/\.\.$')) {
20 if (!followed_url.match('/\.\.$')) {
21 casper.thenOpen(baseUrl+item.link, function () {
21 casper.thenOpen(followed_url, function () {
22 casper.wait_for_dashboard();
22 casper.wait_for_dashboard();
23 this.test.assertEquals(this.getCurrentUrl(), followed_url, 'Testing dashboard link: '+followed_url);
23 // getCurrentUrl is with host, and url-decoded,
24 // but item.link is without host, and url-encoded
25 var expected = baseUrl + decodeURIComponent(item.link);
26 this.test.assertEquals(this.getCurrentUrl(), expected, 'Testing dashboard link: ' + expected);
24 casper.test_items(baseUrl);
27 casper.test_items(baseUrl);
25 this.back();
28 this.back();
26 });
29 });
27 }
30 }
28 }
31 }
29 });
32 });
30 });
33 });
31 }
34 }
32
35
33 casper.dashboard_test(function () {
36 casper.dashboard_test(function () {
34 baseUrl = this.get_notebook_server()
37 baseUrl = this.get_notebook_server();
35 casper.test_items(baseUrl);
38 casper.test_items(baseUrl);
36 })
39 })
37
40
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/util.js to IPython/html/tests/util.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/util.js to IPython/html/tests/util.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets.js to IPython/html/tests/widgets/widget.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets.js to IPython/html/tests/widgets/widget.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_bool.js to IPython/html/tests/widgets/widget_bool.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_bool.js to IPython/html/tests/widgets/widget_bool.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_button.js to IPython/html/tests/widgets/widget_button.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_button.js to IPython/html/tests/widgets/widget_button.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_container.js to IPython/html/tests/widgets/widget_container.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_container.js to IPython/html/tests/widgets/widget_container.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_float.js to IPython/html/tests/widgets/widget_float.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_float.js to IPython/html/tests/widgets/widget_float.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_image.js to IPython/html/tests/widgets/widget_image.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_image.js to IPython/html/tests/widgets/widget_image.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_int.js to IPython/html/tests/widgets/widget_int.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_int.js to IPython/html/tests/widgets/widget_int.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_multicontainer.js to IPython/html/tests/widgets/widget_multicontainer.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_multicontainer.js to IPython/html/tests/widgets/widget_multicontainer.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_selection.js to IPython/html/tests/widgets/widget_selection.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_selection.js to IPython/html/tests/widgets/widget_selection.js
1 NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_string.js to IPython/html/tests/widgets/widget_string.js
NO CONTENT: file renamed from IPython/html/tests/casperjs/test_cases/widgets_string.js to IPython/html/tests/widgets/widget_string.js
@@ -1,100 +1,100 b''
1 """Tornado handlers for the tree view.
1 """Tornado handlers for the tree view.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 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 import os
18 import os
19
19
20 from tornado import web
20 from tornado import web
21 from ..base.handlers import IPythonHandler, notebook_path_regex, path_regex
21 from ..base.handlers import IPythonHandler, notebook_path_regex, path_regex
22 from ..utils import url_path_join, path2url, url2path, url_escape, is_hidden
22 from ..utils import url_path_join, path2url, url2path, url_escape, is_hidden
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Handlers
25 # Handlers
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 class TreeHandler(IPythonHandler):
29 class TreeHandler(IPythonHandler):
30 """Render the tree view, listing notebooks, clusters, etc."""
30 """Render the tree view, listing notebooks, clusters, etc."""
31
31
32 def generate_breadcrumbs(self, path):
32 def generate_breadcrumbs(self, path):
33 breadcrumbs = [(url_escape(url_path_join(self.base_project_url, 'tree')), '')]
33 breadcrumbs = [(url_escape(url_path_join(self.base_url, 'tree')), '')]
34 comps = path.split('/')
34 comps = path.split('/')
35 ncomps = len(comps)
35 ncomps = len(comps)
36 for i in range(ncomps):
36 for i in range(ncomps):
37 if comps[i]:
37 if comps[i]:
38 link = url_escape(url_path_join(self.base_project_url, 'tree', *comps[0:i+1]))
38 link = url_escape(url_path_join(self.base_url, 'tree', *comps[0:i+1]))
39 breadcrumbs.append((link, comps[i]))
39 breadcrumbs.append((link, comps[i]))
40 return breadcrumbs
40 return breadcrumbs
41
41
42 def generate_page_title(self, path):
42 def generate_page_title(self, path):
43 comps = path.split('/')
43 comps = path.split('/')
44 if len(comps) > 3:
44 if len(comps) > 3:
45 for i in range(len(comps)-2):
45 for i in range(len(comps)-2):
46 comps.pop(0)
46 comps.pop(0)
47 page_title = url_escape(url_path_join(*comps))
47 page_title = url_escape(url_path_join(*comps))
48 if page_title:
48 if page_title:
49 return page_title+'/'
49 return page_title+'/'
50 else:
50 else:
51 return 'Home'
51 return 'Home'
52
52
53 @web.authenticated
53 @web.authenticated
54 def get(self, path='', name=None):
54 def get(self, path='', name=None):
55 path = path.strip('/')
55 path = path.strip('/')
56 nbm = self.notebook_manager
56 nbm = self.notebook_manager
57 if name is not None:
57 if name is not None:
58 # is a notebook, redirect to notebook handler
58 # is a notebook, redirect to notebook handler
59 url = url_escape(url_path_join(
59 url = url_escape(url_path_join(
60 self.base_project_url, 'notebooks', path, name
60 self.base_url, 'notebooks', path, name
61 ))
61 ))
62 self.log.debug("Redirecting %s to %s", self.request.path, url)
62 self.log.debug("Redirecting %s to %s", self.request.path, url)
63 self.redirect(url)
63 self.redirect(url)
64 else:
64 else:
65 if not nbm.path_exists(path=path) or nbm.is_hidden(path):
65 if not nbm.path_exists(path=path) or nbm.is_hidden(path):
66 # Directory is hidden or does not exist.
66 # Directory is hidden or does not exist.
67 raise web.HTTPError(404)
67 raise web.HTTPError(404)
68 breadcrumbs = self.generate_breadcrumbs(path)
68 breadcrumbs = self.generate_breadcrumbs(path)
69 page_title = self.generate_page_title(path)
69 page_title = self.generate_page_title(path)
70 self.write(self.render_template('tree.html',
70 self.write(self.render_template('tree.html',
71 project=self.project_dir,
71 project=self.project_dir,
72 page_title=page_title,
72 page_title=page_title,
73 notebook_path=path,
73 notebook_path=path,
74 breadcrumbs=breadcrumbs
74 breadcrumbs=breadcrumbs
75 ))
75 ))
76
76
77
77
78 class TreeRedirectHandler(IPythonHandler):
78 class TreeRedirectHandler(IPythonHandler):
79 """Redirect a request to the corresponding tree URL"""
79 """Redirect a request to the corresponding tree URL"""
80
80
81 @web.authenticated
81 @web.authenticated
82 def get(self, path=''):
82 def get(self, path=''):
83 url = url_escape(url_path_join(
83 url = url_escape(url_path_join(
84 self.base_project_url, 'tree', path.strip('/')
84 self.base_url, 'tree', path.strip('/')
85 ))
85 ))
86 self.log.debug("Redirecting %s to %s", self.request.path, url)
86 self.log.debug("Redirecting %s to %s", self.request.path, url)
87 self.redirect(url)
87 self.redirect(url)
88
88
89
89
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91 # URL to handler mappings
91 # URL to handler mappings
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93
93
94
94
95 default_handlers = [
95 default_handlers = [
96 (r"/tree%s" % notebook_path_regex, TreeHandler),
96 (r"/tree%s" % notebook_path_regex, TreeHandler),
97 (r"/tree%s" % path_regex, TreeHandler),
97 (r"/tree%s" % path_regex, TreeHandler),
98 (r"/tree", TreeHandler),
98 (r"/tree", TreeHandler),
99 (r"/", TreeRedirectHandler),
99 (r"/", TreeRedirectHandler),
100 ]
100 ]
@@ -1,251 +1,259 b''
1 """Interact with functions using widgets."""
1 """Interact with functions using widgets."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from __future__ import print_function
15 from __future__ import print_function
16
16
17 try: # Python >= 3.3
17 try: # Python >= 3.3
18 from inspect import signature, Parameter
18 from inspect import signature, Parameter
19 except ImportError:
19 except ImportError:
20 from IPython.utils.signatures import signature, Parameter
20 from IPython.utils.signatures import signature, Parameter
21 from inspect import getcallargs
21 from inspect import getcallargs
22
22
23 from IPython.core.getipython import get_ipython
23 from IPython.html.widgets import (Widget, TextWidget,
24 from IPython.html.widgets import (Widget, TextWidget,
24 FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
25 FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
25 ContainerWidget, DOMWidget)
26 ContainerWidget, DOMWidget)
26 from IPython.display import display, clear_output
27 from IPython.display import display, clear_output
27 from IPython.utils.py3compat import string_types, unicode_type
28 from IPython.utils.py3compat import string_types, unicode_type
28 from IPython.utils.traitlets import HasTraits, Any, Unicode
29 from IPython.utils.traitlets import HasTraits, Any, Unicode
29
30
30 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
31 # Classes and Functions
32 # Classes and Functions
32 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
33
34
34
35
35 def _matches(o, pattern):
36 def _matches(o, pattern):
36 """Match a pattern of types in a sequence."""
37 """Match a pattern of types in a sequence."""
37 if not len(o) == len(pattern):
38 if not len(o) == len(pattern):
38 return False
39 return False
39 comps = zip(o,pattern)
40 comps = zip(o,pattern)
40 return all(isinstance(obj,kind) for obj,kind in comps)
41 return all(isinstance(obj,kind) for obj,kind in comps)
41
42
42
43
43 def _get_min_max_value(min, max, value=None, step=None):
44 def _get_min_max_value(min, max, value=None, step=None):
44 """Return min, max, value given input values with possible None."""
45 """Return min, max, value given input values with possible None."""
45 if value is None:
46 if value is None:
46 if not max > min:
47 if not max > min:
47 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
48 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
48 value = min + abs(min-max)/2
49 value = min + abs(min-max)/2
49 value = type(min)(value)
50 value = type(min)(value)
50 elif min is None and max is None:
51 elif min is None and max is None:
51 if value == 0.0:
52 if value == 0.0:
52 min, max, value = 0.0, 1.0, 0.5
53 min, max, value = 0.0, 1.0, 0.5
53 elif value == 0:
54 elif value == 0:
54 min, max, value = 0, 1, 0
55 min, max, value = 0, 1, 0
55 elif isinstance(value, (int, float)):
56 elif isinstance(value, (int, float)):
56 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
57 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
57 else:
58 else:
58 raise TypeError('expected a number, got: %r' % value)
59 raise TypeError('expected a number, got: %r' % value)
59 else:
60 else:
60 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
61 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
61 if step is not None:
62 if step is not None:
62 # ensure value is on a step
63 # ensure value is on a step
63 r = (value - min) % step
64 r = (value - min) % step
64 value = value - r
65 value = value - r
65 return min, max, value
66 return min, max, value
66
67
67 def _widget_abbrev_single_value(o):
68 def _widget_abbrev_single_value(o):
68 """Make widgets from single values, which can be used as parameter defaults."""
69 """Make widgets from single values, which can be used as parameter defaults."""
69 if isinstance(o, string_types):
70 if isinstance(o, string_types):
70 return TextWidget(value=unicode_type(o))
71 return TextWidget(value=unicode_type(o))
71 elif isinstance(o, dict):
72 elif isinstance(o, dict):
72 return DropdownWidget(values=o)
73 return DropdownWidget(values=o)
73 elif isinstance(o, bool):
74 elif isinstance(o, bool):
74 return CheckboxWidget(value=o)
75 return CheckboxWidget(value=o)
75 elif isinstance(o, float):
76 elif isinstance(o, float):
76 min, max, value = _get_min_max_value(None, None, o)
77 min, max, value = _get_min_max_value(None, None, o)
77 return FloatSliderWidget(value=o, min=min, max=max)
78 return FloatSliderWidget(value=o, min=min, max=max)
78 elif isinstance(o, int):
79 elif isinstance(o, int):
79 min, max, value = _get_min_max_value(None, None, o)
80 min, max, value = _get_min_max_value(None, None, o)
80 return IntSliderWidget(value=o, min=min, max=max)
81 return IntSliderWidget(value=o, min=min, max=max)
81 else:
82 else:
82 return None
83 return None
83
84
84 def _widget_abbrev(o):
85 def _widget_abbrev(o):
85 """Make widgets from abbreviations: single values, lists or tuples."""
86 """Make widgets from abbreviations: single values, lists or tuples."""
86 float_or_int = (float, int)
87 float_or_int = (float, int)
87 if isinstance(o, (list, tuple)):
88 if isinstance(o, (list, tuple)):
88 if o and all(isinstance(x, string_types) for x in o):
89 if o and all(isinstance(x, string_types) for x in o):
89 return DropdownWidget(values=[unicode_type(k) for k in o])
90 return DropdownWidget(values=[unicode_type(k) for k in o])
90 elif _matches(o, (float_or_int, float_or_int)):
91 elif _matches(o, (float_or_int, float_or_int)):
91 min, max, value = _get_min_max_value(o[0], o[1])
92 min, max, value = _get_min_max_value(o[0], o[1])
92 if all(isinstance(_, int) for _ in o):
93 if all(isinstance(_, int) for _ in o):
93 cls = IntSliderWidget
94 cls = IntSliderWidget
94 else:
95 else:
95 cls = FloatSliderWidget
96 cls = FloatSliderWidget
96 return cls(value=value, min=min, max=max)
97 return cls(value=value, min=min, max=max)
97 elif _matches(o, (float_or_int, float_or_int, float_or_int)):
98 elif _matches(o, (float_or_int, float_or_int, float_or_int)):
98 step = o[2]
99 step = o[2]
99 if step <= 0:
100 if step <= 0:
100 raise ValueError("step must be >= 0, not %r" % step)
101 raise ValueError("step must be >= 0, not %r" % step)
101 min, max, value = _get_min_max_value(o[0], o[1], step=step)
102 min, max, value = _get_min_max_value(o[0], o[1], step=step)
102 if all(isinstance(_, int) for _ in o):
103 if all(isinstance(_, int) for _ in o):
103 cls = IntSliderWidget
104 cls = IntSliderWidget
104 else:
105 else:
105 cls = FloatSliderWidget
106 cls = FloatSliderWidget
106 return cls(value=value, min=min, max=max, step=step)
107 return cls(value=value, min=min, max=max, step=step)
107 else:
108 else:
108 return _widget_abbrev_single_value(o)
109 return _widget_abbrev_single_value(o)
109
110
110 def _widget_from_abbrev(abbrev):
111 def _widget_from_abbrev(abbrev):
111 """Build a Widget intstance given an abbreviation or Widget."""
112 """Build a Widget intstance given an abbreviation or Widget."""
112 if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
113 if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
113 return abbrev
114 return abbrev
114
115
115 widget = _widget_abbrev(abbrev)
116 widget = _widget_abbrev(abbrev)
116 if widget is None:
117 if widget is None:
117 raise ValueError("%r cannot be transformed to a Widget" % (abbrev,))
118 raise ValueError("%r cannot be transformed to a Widget" % (abbrev,))
118 return widget
119 return widget
119
120
120 def _yield_abbreviations_for_parameter(param, kwargs):
121 def _yield_abbreviations_for_parameter(param, kwargs):
121 """Get an abbreviation for a function parameter."""
122 """Get an abbreviation for a function parameter."""
122 name = param.name
123 name = param.name
123 kind = param.kind
124 kind = param.kind
124 ann = param.annotation
125 ann = param.annotation
125 default = param.default
126 default = param.default
126 empty = Parameter.empty
127 empty = Parameter.empty
127 not_found = (None, None)
128 not_found = (None, None)
128 if kind == Parameter.POSITIONAL_OR_KEYWORD:
129 if kind == Parameter.POSITIONAL_OR_KEYWORD:
129 if name in kwargs:
130 if name in kwargs:
130 yield name, kwargs.pop(name)
131 yield name, kwargs.pop(name)
131 elif ann is not empty:
132 elif ann is not empty:
132 if default is empty:
133 if default is empty:
133 yield name, ann
134 yield name, ann
134 else:
135 else:
135 yield name, ann
136 yield name, ann
136 elif default is not empty:
137 elif default is not empty:
137 yield name, default
138 yield name, default
138 else:
139 else:
139 yield not_found
140 yield not_found
140 elif kind == Parameter.KEYWORD_ONLY:
141 elif kind == Parameter.KEYWORD_ONLY:
141 if name in kwargs:
142 if name in kwargs:
142 yield name, kwargs.pop(name)
143 yield name, kwargs.pop(name)
143 elif ann is not empty:
144 elif ann is not empty:
144 yield name, ann
145 yield name, ann
145 elif default is not empty:
146 elif default is not empty:
146 yield name, default
147 yield name, default
147 else:
148 else:
148 yield not_found
149 yield not_found
149 elif kind == Parameter.VAR_KEYWORD:
150 elif kind == Parameter.VAR_KEYWORD:
150 # In this case name=kwargs and we yield the items in kwargs with their keys.
151 # In this case name=kwargs and we yield the items in kwargs with their keys.
151 for k, v in kwargs.copy().items():
152 for k, v in kwargs.copy().items():
152 kwargs.pop(k)
153 kwargs.pop(k)
153 yield k, v
154 yield k, v
154
155
155 def _find_abbreviations(f, kwargs):
156 def _find_abbreviations(f, kwargs):
156 """Find the abbreviations for a function and kwargs passed to interact."""
157 """Find the abbreviations for a function and kwargs passed to interact."""
157 new_kwargs = []
158 new_kwargs = []
158 for param in signature(f).parameters.values():
159 for param in signature(f).parameters.values():
159 for name, value in _yield_abbreviations_for_parameter(param, kwargs):
160 for name, value in _yield_abbreviations_for_parameter(param, kwargs):
160 if value is None:
161 if value is None:
161 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
162 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
162 new_kwargs.append((name, value))
163 new_kwargs.append((name, value))
163 return new_kwargs
164 return new_kwargs
164
165
165 def _widgets_from_abbreviations(seq):
166 def _widgets_from_abbreviations(seq):
166 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
167 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
167 result = []
168 result = []
168 for name, abbrev in seq:
169 for name, abbrev in seq:
169 widget = _widget_from_abbrev(abbrev)
170 widget = _widget_from_abbrev(abbrev)
170 widget.description = name
171 widget.description = name
171 result.append(widget)
172 result.append(widget)
172 return result
173 return result
173
174
174 def interactive(__interact_f, **kwargs):
175 def interactive(__interact_f, **kwargs):
175 """Build a group of widgets to interact with a function."""
176 """Build a group of widgets to interact with a function."""
176 f = __interact_f
177 f = __interact_f
177 co = kwargs.pop('clear_output', True)
178 co = kwargs.pop('clear_output', True)
178 kwargs_widgets = []
179 kwargs_widgets = []
179 container = ContainerWidget()
180 container = ContainerWidget()
180 container.result = None
181 container.result = None
181 container.args = []
182 container.args = []
182 container.kwargs = dict()
183 container.kwargs = dict()
183 kwargs = kwargs.copy()
184 kwargs = kwargs.copy()
184
185
185 new_kwargs = _find_abbreviations(f, kwargs)
186 new_kwargs = _find_abbreviations(f, kwargs)
186 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
187 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
187 # that will lead to a valid call of the function. This protects against unspecified
188 # that will lead to a valid call of the function. This protects against unspecified
188 # and doubly-specified arguments.
189 # and doubly-specified arguments.
189 getcallargs(f, **{n:v for n,v in new_kwargs})
190 getcallargs(f, **{n:v for n,v in new_kwargs})
190 # Now build the widgets from the abbreviations.
191 # Now build the widgets from the abbreviations.
191 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
192 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
192 kwargs_widgets.extend(_widgets_from_abbreviations(sorted(kwargs.items(), key = lambda x: x[0])))
193 kwargs_widgets.extend(_widgets_from_abbreviations(sorted(kwargs.items(), key = lambda x: x[0])))
193
194
194 # This has to be done as an assignment, not using container.children.append,
195 # This has to be done as an assignment, not using container.children.append,
195 # so that traitlets notices the update. We skip any objects (such as fixed) that
196 # so that traitlets notices the update. We skip any objects (such as fixed) that
196 # are not DOMWidgets.
197 # are not DOMWidgets.
197 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
198 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
198 container.children = c
199 container.children = c
199
200
200 # Build the callback
201 # Build the callback
201 def call_f(name, old, new):
202 def call_f(name, old, new):
202 container.kwargs = {}
203 container.kwargs = {}
203 for widget in kwargs_widgets:
204 for widget in kwargs_widgets:
204 value = widget.value
205 value = widget.value
205 container.kwargs[widget.description] = value
206 container.kwargs[widget.description] = value
206 if co:
207 if co:
207 clear_output(wait=True)
208 clear_output(wait=True)
208 container.result = f(**container.kwargs)
209 try:
210 container.result = f(**container.kwargs)
211 except Exception as e:
212 ip = get_ipython()
213 if ip is None:
214 container.log.warn("Exception in interact callback: %s", e, exc_info=True)
215 else:
216 ip.showtraceback()
209
217
210 # Wire up the widgets
218 # Wire up the widgets
211 for widget in kwargs_widgets:
219 for widget in kwargs_widgets:
212 widget.on_trait_change(call_f, 'value')
220 widget.on_trait_change(call_f, 'value')
213
221
214 container.on_displayed(lambda _: call_f(None, None, None))
222 container.on_displayed(lambda _: call_f(None, None, None))
215
223
216 return container
224 return container
217
225
218 def interact(__interact_f=None, **kwargs):
226 def interact(__interact_f=None, **kwargs):
219 """interact(f, **kwargs)
227 """interact(f, **kwargs)
220
228
221 Interact with a function using widgets."""
229 Interact with a function using widgets."""
222 # positional arg support in: https://gist.github.com/8851331
230 # positional arg support in: https://gist.github.com/8851331
223 if __interact_f is not None:
231 if __interact_f is not None:
224 # This branch handles the cases:
232 # This branch handles the cases:
225 # 1. interact(f, **kwargs)
233 # 1. interact(f, **kwargs)
226 # 2. @interact
234 # 2. @interact
227 # def f(*args, **kwargs):
235 # def f(*args, **kwargs):
228 # ...
236 # ...
229 f = __interact_f
237 f = __interact_f
230 w = interactive(f, **kwargs)
238 w = interactive(f, **kwargs)
231 f.widget = w
239 f.widget = w
232 display(w)
240 display(w)
233 return f
241 return f
234 else:
242 else:
235 # This branch handles the case:
243 # This branch handles the case:
236 # @interact(a=30, b=40)
244 # @interact(a=30, b=40)
237 # def f(*args, **kwargs):
245 # def f(*args, **kwargs):
238 # ...
246 # ...
239 def dec(f):
247 def dec(f):
240 w = interactive(f, **kwargs)
248 w = interactive(f, **kwargs)
241 f.widget = w
249 f.widget = w
242 display(w)
250 display(w)
243 return f
251 return f
244 return dec
252 return dec
245
253
246 class fixed(HasTraits):
254 class fixed(HasTraits):
247 """A pseudo-widget whose value is fixed and never synced to the client."""
255 """A pseudo-widget whose value is fixed and never synced to the client."""
248 value = Any(help="Any Python object")
256 value = Any(help="Any Python object")
249 description = Unicode('', help="Any Python object")
257 description = Unicode('', help="Any Python object")
250 def __init__(self, value, **kwargs):
258 def __init__(self, value, **kwargs):
251 super(fixed, self).__init__(value=value, **kwargs)
259 super(fixed, self).__init__(value=value, **kwargs)
@@ -1,423 +1,441 b''
1 """Base Widget class. Allows user to create widgets in the back-end that render
1 """Base Widget class. Allows user to create widgets in the back-end that render
2 in the IPython notebook front-end.
2 in the IPython notebook front-end.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2013, the IPython Development Team.
5 # Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 from contextlib import contextmanager
15 from contextlib import contextmanager
16
16
17 from IPython.core.getipython import get_ipython
17 from IPython.kernel.comm import Comm
18 from IPython.kernel.comm import Comm
18 from IPython.config import LoggingConfigurable
19 from IPython.config import LoggingConfigurable
19 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple
20 from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple
20 from IPython.utils.py3compat import string_types
21 from IPython.utils.py3compat import string_types
21
22
22 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
23 # Classes
24 # Classes
24 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
25 class CallbackDispatcher(LoggingConfigurable):
26 class CallbackDispatcher(LoggingConfigurable):
26 """A structure for registering and running callbacks"""
27 """A structure for registering and running callbacks"""
27 callbacks = List()
28 callbacks = List()
28
29
29 def __call__(self, *args, **kwargs):
30 def __call__(self, *args, **kwargs):
30 """Call all of the registered callbacks."""
31 """Call all of the registered callbacks."""
31 value = None
32 value = None
32 for callback in self.callbacks:
33 for callback in self.callbacks:
33 try:
34 try:
34 local_value = callback(*args, **kwargs)
35 local_value = callback(*args, **kwargs)
35 except Exception as e:
36 except Exception as e:
36 self.log.warn("Exception in callback %s: %s", callback, e)
37 ip = get_ipython()
38 if ip is None:
39 self.log.warn("Exception in callback %s: %s", callback, e, exc_info=True)
40 else:
41 ip.showtraceback()
37 else:
42 else:
38 value = local_value if local_value is not None else value
43 value = local_value if local_value is not None else value
39 return value
44 return value
40
45
41 def register_callback(self, callback, remove=False):
46 def register_callback(self, callback, remove=False):
42 """(Un)Register a callback
47 """(Un)Register a callback
43
48
44 Parameters
49 Parameters
45 ----------
50 ----------
46 callback: method handle
51 callback: method handle
47 Method to be registered or unregistered.
52 Method to be registered or unregistered.
48 remove=False: bool
53 remove=False: bool
49 Whether to unregister the callback."""
54 Whether to unregister the callback."""
50
55
51 # (Un)Register the callback.
56 # (Un)Register the callback.
52 if remove and callback in self.callbacks:
57 if remove and callback in self.callbacks:
53 self.callbacks.remove(callback)
58 self.callbacks.remove(callback)
54 elif not remove and callback not in self.callbacks:
59 elif not remove and callback not in self.callbacks:
55 self.callbacks.append(callback)
60 self.callbacks.append(callback)
56
61
62 def _show_traceback(method):
63 """decorator for showing tracebacks in IPython"""
64 def m(self, *args, **kwargs):
65 try:
66 return(method(self, *args, **kwargs))
67 except Exception as e:
68 ip = get_ipython()
69 if ip is None:
70 self.log.warn("Exception in widget method %s: %s", method, e, exc_info=True)
71 else:
72 ip.showtraceback()
73 return m
57
74
58 class Widget(LoggingConfigurable):
75 class Widget(LoggingConfigurable):
59 #-------------------------------------------------------------------------
76 #-------------------------------------------------------------------------
60 # Class attributes
77 # Class attributes
61 #-------------------------------------------------------------------------
78 #-------------------------------------------------------------------------
62 _widget_construction_callback = None
79 _widget_construction_callback = None
63 widgets = {}
80 widgets = {}
64
81
65 @staticmethod
82 @staticmethod
66 def on_widget_constructed(callback):
83 def on_widget_constructed(callback):
67 """Registers a callback to be called when a widget is constructed.
84 """Registers a callback to be called when a widget is constructed.
68
85
69 The callback must have the following signature:
86 The callback must have the following signature:
70 callback(widget)"""
87 callback(widget)"""
71 Widget._widget_construction_callback = callback
88 Widget._widget_construction_callback = callback
72
89
73 @staticmethod
90 @staticmethod
74 def _call_widget_constructed(widget):
91 def _call_widget_constructed(widget):
75 """Static method, called when a widget is constructed."""
92 """Static method, called when a widget is constructed."""
76 if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
93 if Widget._widget_construction_callback is not None and callable(Widget._widget_construction_callback):
77 Widget._widget_construction_callback(widget)
94 Widget._widget_construction_callback(widget)
78
95
79 #-------------------------------------------------------------------------
96 #-------------------------------------------------------------------------
80 # Traits
97 # Traits
81 #-------------------------------------------------------------------------
98 #-------------------------------------------------------------------------
82 _model_name = Unicode('WidgetModel', help="""Name of the backbone model
99 _model_name = Unicode('WidgetModel', help="""Name of the backbone model
83 registered in the front-end to create and sync this widget with.""")
100 registered in the front-end to create and sync this widget with.""")
84 _view_name = Unicode(help="""Default view registered in the front-end
101 _view_name = Unicode(help="""Default view registered in the front-end
85 to use to represent the widget.""", sync=True)
102 to use to represent the widget.""", sync=True)
86 _comm = Instance('IPython.kernel.comm.Comm')
103 _comm = Instance('IPython.kernel.comm.Comm')
87
104
88 closed = Bool(False)
105 closed = Bool(False)
89
106
90 keys = List()
107 keys = List()
91 def _keys_default(self):
108 def _keys_default(self):
92 return [name for name in self.traits(sync=True)]
109 return [name for name in self.traits(sync=True)]
93
110
94 _property_lock = Tuple((None, None))
111 _property_lock = Tuple((None, None))
95
112
96 _display_callbacks = Instance(CallbackDispatcher, ())
113 _display_callbacks = Instance(CallbackDispatcher, ())
97 _msg_callbacks = Instance(CallbackDispatcher, ())
114 _msg_callbacks = Instance(CallbackDispatcher, ())
98
115
99 #-------------------------------------------------------------------------
116 #-------------------------------------------------------------------------
100 # (Con/de)structor
117 # (Con/de)structor
101 #-------------------------------------------------------------------------
118 #-------------------------------------------------------------------------
102 def __init__(self, **kwargs):
119 def __init__(self, **kwargs):
103 """Public constructor"""
120 """Public constructor"""
104 super(Widget, self).__init__(**kwargs)
121 super(Widget, self).__init__(**kwargs)
105
122
106 self.on_trait_change(self._handle_property_changed, self.keys)
123 self.on_trait_change(self._handle_property_changed, self.keys)
107 Widget._call_widget_constructed(self)
124 Widget._call_widget_constructed(self)
108
125
109 def __del__(self):
126 def __del__(self):
110 """Object disposal"""
127 """Object disposal"""
111 self.close()
128 self.close()
112
129
113 #-------------------------------------------------------------------------
130 #-------------------------------------------------------------------------
114 # Properties
131 # Properties
115 #-------------------------------------------------------------------------
132 #-------------------------------------------------------------------------
116
133
117 @property
134 @property
118 def comm(self):
135 def comm(self):
119 """Gets the Comm associated with this widget.
136 """Gets the Comm associated with this widget.
120
137
121 If a Comm doesn't exist yet, a Comm will be created automagically."""
138 If a Comm doesn't exist yet, a Comm will be created automagically."""
122 if self._comm is None:
139 if self._comm is None:
123 # Create a comm.
140 # Create a comm.
124 self._comm = Comm(target_name=self._model_name)
141 self._comm = Comm(target_name=self._model_name)
125 self._comm.on_msg(self._handle_msg)
142 self._comm.on_msg(self._handle_msg)
126 self._comm.on_close(self._close)
143 self._comm.on_close(self._close)
127 Widget.widgets[self.model_id] = self
144 Widget.widgets[self.model_id] = self
128
145
129 # first update
146 # first update
130 self.send_state()
147 self.send_state()
131 return self._comm
148 return self._comm
132
149
133 @property
150 @property
134 def model_id(self):
151 def model_id(self):
135 """Gets the model id of this widget.
152 """Gets the model id of this widget.
136
153
137 If a Comm doesn't exist yet, a Comm will be created automagically."""
154 If a Comm doesn't exist yet, a Comm will be created automagically."""
138 return self.comm.comm_id
155 return self.comm.comm_id
139
156
140 #-------------------------------------------------------------------------
157 #-------------------------------------------------------------------------
141 # Methods
158 # Methods
142 #-------------------------------------------------------------------------
159 #-------------------------------------------------------------------------
143 def _close(self):
160 def _close(self):
144 """Private close - cleanup objects, registry entries"""
161 """Private close - cleanup objects, registry entries"""
145 del Widget.widgets[self.model_id]
162 del Widget.widgets[self.model_id]
146 self._comm = None
163 self._comm = None
147 self.closed = True
164 self.closed = True
148
165
149 def close(self):
166 def close(self):
150 """Close method.
167 """Close method.
151
168
152 Closes the widget which closes the underlying comm.
169 Closes the widget which closes the underlying comm.
153 When the comm is closed, all of the widget views are automatically
170 When the comm is closed, all of the widget views are automatically
154 removed from the front-end."""
171 removed from the front-end."""
155 if not self.closed:
172 if not self.closed:
156 self._comm.close()
173 self._comm.close()
157 self._close()
174 self._close()
158
175
159 def send_state(self, key=None):
176 def send_state(self, key=None):
160 """Sends the widget state, or a piece of it, to the front-end.
177 """Sends the widget state, or a piece of it, to the front-end.
161
178
162 Parameters
179 Parameters
163 ----------
180 ----------
164 key : unicode (optional)
181 key : unicode (optional)
165 A single property's name to sync with the front-end.
182 A single property's name to sync with the front-end.
166 """
183 """
167 self._send({
184 self._send({
168 "method" : "update",
185 "method" : "update",
169 "state" : self.get_state()
186 "state" : self.get_state()
170 })
187 })
171
188
172 def get_state(self, key=None):
189 def get_state(self, key=None):
173 """Gets the widget state, or a piece of it.
190 """Gets the widget state, or a piece of it.
174
191
175 Parameters
192 Parameters
176 ----------
193 ----------
177 key : unicode (optional)
194 key : unicode (optional)
178 A single property's name to get.
195 A single property's name to get.
179 """
196 """
180 keys = self.keys if key is None else [key]
197 keys = self.keys if key is None else [key]
181 return {k: self._pack_widgets(getattr(self, k)) for k in keys}
198 return {k: self._pack_widgets(getattr(self, k)) for k in keys}
182
199
183 def send(self, content):
200 def send(self, content):
184 """Sends a custom msg to the widget model in the front-end.
201 """Sends a custom msg to the widget model in the front-end.
185
202
186 Parameters
203 Parameters
187 ----------
204 ----------
188 content : dict
205 content : dict
189 Content of the message to send.
206 Content of the message to send.
190 """
207 """
191 self._send({"method": "custom", "content": content})
208 self._send({"method": "custom", "content": content})
192
209
193 def on_msg(self, callback, remove=False):
210 def on_msg(self, callback, remove=False):
194 """(Un)Register a custom msg receive callback.
211 """(Un)Register a custom msg receive callback.
195
212
196 Parameters
213 Parameters
197 ----------
214 ----------
198 callback: callable
215 callback: callable
199 callback will be passed two arguments when a message arrives::
216 callback will be passed two arguments when a message arrives::
200
217
201 callback(widget, content)
218 callback(widget, content)
202
219
203 remove: bool
220 remove: bool
204 True if the callback should be unregistered."""
221 True if the callback should be unregistered."""
205 self._msg_callbacks.register_callback(callback, remove=remove)
222 self._msg_callbacks.register_callback(callback, remove=remove)
206
223
207 def on_displayed(self, callback, remove=False):
224 def on_displayed(self, callback, remove=False):
208 """(Un)Register a widget displayed callback.
225 """(Un)Register a widget displayed callback.
209
226
210 Parameters
227 Parameters
211 ----------
228 ----------
212 callback: method handler
229 callback: method handler
213 Must have a signature of::
230 Must have a signature of::
214
231
215 callback(widget, **kwargs)
232 callback(widget, **kwargs)
216
233
217 kwargs from display are passed through without modification.
234 kwargs from display are passed through without modification.
218 remove: bool
235 remove: bool
219 True if the callback should be unregistered."""
236 True if the callback should be unregistered."""
220 self._display_callbacks.register_callback(callback, remove=remove)
237 self._display_callbacks.register_callback(callback, remove=remove)
221
238
222 #-------------------------------------------------------------------------
239 #-------------------------------------------------------------------------
223 # Support methods
240 # Support methods
224 #-------------------------------------------------------------------------
241 #-------------------------------------------------------------------------
225 @contextmanager
242 @contextmanager
226 def _lock_property(self, key, value):
243 def _lock_property(self, key, value):
227 """Lock a property-value pair.
244 """Lock a property-value pair.
228
245
229 NOTE: This, in addition to the single lock for all state changes, is
246 NOTE: This, in addition to the single lock for all state changes, is
230 flawed. In the future we may want to look into buffering state changes
247 flawed. In the future we may want to look into buffering state changes
231 back to the front-end."""
248 back to the front-end."""
232 self._property_lock = (key, value)
249 self._property_lock = (key, value)
233 try:
250 try:
234 yield
251 yield
235 finally:
252 finally:
236 self._property_lock = (None, None)
253 self._property_lock = (None, None)
237
254
238 def _should_send_property(self, key, value):
255 def _should_send_property(self, key, value):
239 """Check the property lock (property_lock)"""
256 """Check the property lock (property_lock)"""
240 return key != self._property_lock[0] or \
257 return key != self._property_lock[0] or \
241 value != self._property_lock[1]
258 value != self._property_lock[1]
242
259
243 # Event handlers
260 # Event handlers
261 @_show_traceback
244 def _handle_msg(self, msg):
262 def _handle_msg(self, msg):
245 """Called when a msg is received from the front-end"""
263 """Called when a msg is received from the front-end"""
246 data = msg['content']['data']
264 data = msg['content']['data']
247 method = data['method']
265 method = data['method']
248 if not method in ['backbone', 'custom']:
266 if not method in ['backbone', 'custom']:
249 self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
267 self.log.error('Unknown front-end to back-end widget msg with method "%s"' % method)
250
268
251 # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
269 # Handle backbone sync methods CREATE, PATCH, and UPDATE all in one.
252 if method == 'backbone' and 'sync_data' in data:
270 if method == 'backbone' and 'sync_data' in data:
253 sync_data = data['sync_data']
271 sync_data = data['sync_data']
254 self._handle_receive_state(sync_data) # handles all methods
272 self._handle_receive_state(sync_data) # handles all methods
255
273
256 # Handle a custom msg from the front-end
274 # Handle a custom msg from the front-end
257 elif method == 'custom':
275 elif method == 'custom':
258 if 'content' in data:
276 if 'content' in data:
259 self._handle_custom_msg(data['content'])
277 self._handle_custom_msg(data['content'])
260
278
261 def _handle_receive_state(self, sync_data):
279 def _handle_receive_state(self, sync_data):
262 """Called when a state is received from the front-end."""
280 """Called when a state is received from the front-end."""
263 for name in self.keys:
281 for name in self.keys:
264 if name in sync_data:
282 if name in sync_data:
265 value = self._unpack_widgets(sync_data[name])
283 value = self._unpack_widgets(sync_data[name])
266 with self._lock_property(name, value):
284 with self._lock_property(name, value):
267 setattr(self, name, value)
285 setattr(self, name, value)
268
286
269 def _handle_custom_msg(self, content):
287 def _handle_custom_msg(self, content):
270 """Called when a custom msg is received."""
288 """Called when a custom msg is received."""
271 self._msg_callbacks(self, content)
289 self._msg_callbacks(self, content)
272
290
273 def _handle_property_changed(self, name, old, new):
291 def _handle_property_changed(self, name, old, new):
274 """Called when a property has been changed."""
292 """Called when a property has been changed."""
275 # Make sure this isn't information that the front-end just sent us.
293 # Make sure this isn't information that the front-end just sent us.
276 if self._should_send_property(name, new):
294 if self._should_send_property(name, new):
277 # Send new state to front-end
295 # Send new state to front-end
278 self.send_state(key=name)
296 self.send_state(key=name)
279
297
280 def _handle_displayed(self, **kwargs):
298 def _handle_displayed(self, **kwargs):
281 """Called when a view has been displayed for this widget instance"""
299 """Called when a view has been displayed for this widget instance"""
282 self._display_callbacks(self, **kwargs)
300 self._display_callbacks(self, **kwargs)
283
301
284 def _pack_widgets(self, x):
302 def _pack_widgets(self, x):
285 """Recursively converts all widget instances to model id strings.
303 """Recursively converts all widget instances to model id strings.
286
304
287 Children widgets will be stored and transmitted to the front-end by
305 Children widgets will be stored and transmitted to the front-end by
288 their model ids. Return value must be JSON-able."""
306 their model ids. Return value must be JSON-able."""
289 if isinstance(x, dict):
307 if isinstance(x, dict):
290 return {k: self._pack_widgets(v) for k, v in x.items()}
308 return {k: self._pack_widgets(v) for k, v in x.items()}
291 elif isinstance(x, list):
309 elif isinstance(x, list):
292 return [self._pack_widgets(v) for v in x]
310 return [self._pack_widgets(v) for v in x]
293 elif isinstance(x, Widget):
311 elif isinstance(x, Widget):
294 return x.model_id
312 return x.model_id
295 else:
313 else:
296 return x # Value must be JSON-able
314 return x # Value must be JSON-able
297
315
298 def _unpack_widgets(self, x):
316 def _unpack_widgets(self, x):
299 """Recursively converts all model id strings to widget instances.
317 """Recursively converts all model id strings to widget instances.
300
318
301 Children widgets will be stored and transmitted to the front-end by
319 Children widgets will be stored and transmitted to the front-end by
302 their model ids."""
320 their model ids."""
303 if isinstance(x, dict):
321 if isinstance(x, dict):
304 return {k: self._unpack_widgets(v) for k, v in x.items()}
322 return {k: self._unpack_widgets(v) for k, v in x.items()}
305 elif isinstance(x, list):
323 elif isinstance(x, list):
306 return [self._unpack_widgets(v) for v in x]
324 return [self._unpack_widgets(v) for v in x]
307 elif isinstance(x, string_types):
325 elif isinstance(x, string_types):
308 return x if x not in Widget.widgets else Widget.widgets[x]
326 return x if x not in Widget.widgets else Widget.widgets[x]
309 else:
327 else:
310 return x
328 return x
311
329
312 def _ipython_display_(self, **kwargs):
330 def _ipython_display_(self, **kwargs):
313 """Called when `IPython.display.display` is called on the widget."""
331 """Called when `IPython.display.display` is called on the widget."""
314 # Show view. By sending a display message, the comm is opened and the
332 # Show view. By sending a display message, the comm is opened and the
315 # initial state is sent.
333 # initial state is sent.
316 self._send({"method": "display"})
334 self._send({"method": "display"})
317 self._handle_displayed(**kwargs)
335 self._handle_displayed(**kwargs)
318
336
319 def _send(self, msg):
337 def _send(self, msg):
320 """Sends a message to the model in the front-end."""
338 """Sends a message to the model in the front-end."""
321 self.comm.send(msg)
339 self.comm.send(msg)
322
340
323
341
324 class DOMWidget(Widget):
342 class DOMWidget(Widget):
325 visible = Bool(True, help="Whether the widget is visible.", sync=True)
343 visible = Bool(True, help="Whether the widget is visible.", sync=True)
326 _css = Dict(sync=True) # Internal CSS property dict
344 _css = Dict(sync=True) # Internal CSS property dict
327
345
328 def get_css(self, key, selector=""):
346 def get_css(self, key, selector=""):
329 """Get a CSS property of the widget.
347 """Get a CSS property of the widget.
330
348
331 Note: This function does not actually request the CSS from the
349 Note: This function does not actually request the CSS from the
332 front-end; Only properties that have been set with set_css can be read.
350 front-end; Only properties that have been set with set_css can be read.
333
351
334 Parameters
352 Parameters
335 ----------
353 ----------
336 key: unicode
354 key: unicode
337 CSS key
355 CSS key
338 selector: unicode (optional)
356 selector: unicode (optional)
339 JQuery selector used when the CSS key/value was set.
357 JQuery selector used when the CSS key/value was set.
340 """
358 """
341 if selector in self._css and key in self._css[selector]:
359 if selector in self._css and key in self._css[selector]:
342 return self._css[selector][key]
360 return self._css[selector][key]
343 else:
361 else:
344 return None
362 return None
345
363
346 def set_css(self, dict_or_key, value=None, selector=''):
364 def set_css(self, dict_or_key, value=None, selector=''):
347 """Set one or more CSS properties of the widget.
365 """Set one or more CSS properties of the widget.
348
366
349 This function has two signatures:
367 This function has two signatures:
350 - set_css(css_dict, selector='')
368 - set_css(css_dict, selector='')
351 - set_css(key, value, selector='')
369 - set_css(key, value, selector='')
352
370
353 Parameters
371 Parameters
354 ----------
372 ----------
355 css_dict : dict
373 css_dict : dict
356 CSS key/value pairs to apply
374 CSS key/value pairs to apply
357 key: unicode
375 key: unicode
358 CSS key
376 CSS key
359 value:
377 value:
360 CSS value
378 CSS value
361 selector: unicode (optional, kwarg only)
379 selector: unicode (optional, kwarg only)
362 JQuery selector to use to apply the CSS key/value. If no selector
380 JQuery selector to use to apply the CSS key/value. If no selector
363 is provided, an empty selector is used. An empty selector makes the
381 is provided, an empty selector is used. An empty selector makes the
364 front-end try to apply the css to a default element. The default
382 front-end try to apply the css to a default element. The default
365 element is an attribute unique to each view, which is a DOM element
383 element is an attribute unique to each view, which is a DOM element
366 of the view that should be styled with common CSS (see
384 of the view that should be styled with common CSS (see
367 `$el_to_style` in the Javascript code).
385 `$el_to_style` in the Javascript code).
368 """
386 """
369 if not selector in self._css:
387 if not selector in self._css:
370 self._css[selector] = {}
388 self._css[selector] = {}
371 my_css = self._css[selector]
389 my_css = self._css[selector]
372
390
373 if value is None:
391 if value is None:
374 css_dict = dict_or_key
392 css_dict = dict_or_key
375 else:
393 else:
376 css_dict = {dict_or_key: value}
394 css_dict = {dict_or_key: value}
377
395
378 for (key, value) in css_dict.items():
396 for (key, value) in css_dict.items():
379 if not (key in my_css and value == my_css[key]):
397 if not (key in my_css and value == my_css[key]):
380 my_css[key] = value
398 my_css[key] = value
381 self.send_state('_css')
399 self.send_state('_css')
382
400
383 def add_class(self, class_names, selector=""):
401 def add_class(self, class_names, selector=""):
384 """Add class[es] to a DOM element.
402 """Add class[es] to a DOM element.
385
403
386 Parameters
404 Parameters
387 ----------
405 ----------
388 class_names: unicode or list
406 class_names: unicode or list
389 Class name(s) to add to the DOM element(s).
407 Class name(s) to add to the DOM element(s).
390 selector: unicode (optional)
408 selector: unicode (optional)
391 JQuery selector to select the DOM element(s) that the class(es) will
409 JQuery selector to select the DOM element(s) that the class(es) will
392 be added to.
410 be added to.
393 """
411 """
394 class_list = class_names
412 class_list = class_names
395 if isinstance(class_list, list):
413 if isinstance(class_list, list):
396 class_list = ' '.join(class_list)
414 class_list = ' '.join(class_list)
397
415
398 self.send({
416 self.send({
399 "msg_type" : "add_class",
417 "msg_type" : "add_class",
400 "class_list" : class_list,
418 "class_list" : class_list,
401 "selector" : selector
419 "selector" : selector
402 })
420 })
403
421
404 def remove_class(self, class_names, selector=""):
422 def remove_class(self, class_names, selector=""):
405 """Remove class[es] from a DOM element.
423 """Remove class[es] from a DOM element.
406
424
407 Parameters
425 Parameters
408 ----------
426 ----------
409 class_names: unicode or list
427 class_names: unicode or list
410 Class name(s) to remove from the DOM element(s).
428 Class name(s) to remove from the DOM element(s).
411 selector: unicode (optional)
429 selector: unicode (optional)
412 JQuery selector to select the DOM element(s) that the class(es) will
430 JQuery selector to select the DOM element(s) that the class(es) will
413 be removed from.
431 be removed from.
414 """
432 """
415 class_list = class_names
433 class_list = class_names
416 if isinstance(class_list, list):
434 if isinstance(class_list, list):
417 class_list = ' '.join(class_list)
435 class_list = ' '.join(class_list)
418
436
419 self.send({
437 self.send({
420 "msg_type" : "remove_class",
438 "msg_type" : "remove_class",
421 "class_list" : class_list,
439 "class_list" : class_list,
422 "selector" : selector,
440 "selector" : selector,
423 })
441 })
@@ -1,108 +1,115 b''
1 """Configurable for configuring the IPython inline backend
1 """Configurable for configuring the IPython inline backend
2
2
3 This module does not import anything from matplotlib.
3 This module does not import anything from matplotlib.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2011 The IPython Development Team
6 # Copyright (C) 2011 The IPython Development Team
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.config.configurable import SingletonConfigurable
16 from IPython.config.configurable import SingletonConfigurable
17 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool, Int, TraitError
17 from IPython.utils.traitlets import (
18 Dict, Instance, CaselessStrEnum, Set, Bool, Int, TraitError, Unicode
19 )
18 from IPython.utils.warn import warn
20 from IPython.utils.warn import warn
19
21
20 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
21 # Configurable for inline backend options
23 # Configurable for inline backend options
22 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
23
25
24 def pil_available():
26 def pil_available():
25 """Test if PIL/Pillow is available"""
27 """Test if PIL/Pillow is available"""
26 out = False
28 out = False
27 try:
29 try:
28 from PIL import Image
30 from PIL import Image
29 out = True
31 out = True
30 except:
32 except:
31 pass
33 pass
32 return out
34 return out
33
35
34 # inherit from InlineBackendConfig for deprecation purposes
36 # inherit from InlineBackendConfig for deprecation purposes
35 class InlineBackendConfig(SingletonConfigurable):
37 class InlineBackendConfig(SingletonConfigurable):
36 pass
38 pass
37
39
38 class InlineBackend(InlineBackendConfig):
40 class InlineBackend(InlineBackendConfig):
39 """An object to store configuration of the inline backend."""
41 """An object to store configuration of the inline backend."""
40
42
41 def _config_changed(self, name, old, new):
43 def _config_changed(self, name, old, new):
42 # warn on change of renamed config section
44 # warn on change of renamed config section
43 if new.InlineBackendConfig != old.InlineBackendConfig:
45 if new.InlineBackendConfig != old.InlineBackendConfig:
44 warn("InlineBackendConfig has been renamed to InlineBackend")
46 warn("InlineBackendConfig has been renamed to InlineBackend")
45 super(InlineBackend, self)._config_changed(name, old, new)
47 super(InlineBackend, self)._config_changed(name, old, new)
46
48
47 # The typical default figure size is too large for inline use,
49 # The typical default figure size is too large for inline use,
48 # so we shrink the figure size to 6x4, and tweak fonts to
50 # so we shrink the figure size to 6x4, and tweak fonts to
49 # make that fit.
51 # make that fit.
50 rc = Dict({'figure.figsize': (6.0,4.0),
52 rc = Dict({'figure.figsize': (6.0,4.0),
51 # play nicely with white background in the Qt and notebook frontend
53 # play nicely with white background in the Qt and notebook frontend
52 'figure.facecolor': (1,1,1,0),
54 'figure.facecolor': (1,1,1,0),
53 'figure.edgecolor': (1,1,1,0),
55 'figure.edgecolor': (1,1,1,0),
54 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
56 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
55 'font.size': 10,
57 'font.size': 10,
56 # 72 dpi matches SVG/qtconsole
58 # 72 dpi matches SVG/qtconsole
57 # this only affects PNG export, as SVG has no dpi setting
59 # this only affects PNG export, as SVG has no dpi setting
58 'savefig.dpi': 72,
60 'savefig.dpi': 72,
59 # 10pt still needs a little more room on the xlabel:
61 # 10pt still needs a little more room on the xlabel:
60 'figure.subplot.bottom' : .125
62 'figure.subplot.bottom' : .125
61 }, config=True,
63 }, config=True,
62 help="""Subset of matplotlib rcParams that should be different for the
64 help="""Subset of matplotlib rcParams that should be different for the
63 inline backend."""
65 inline backend."""
64 )
66 )
65
67
68 figure_formats = Set({'png'}, config=True,
69 help="""A set of figure formats to enable: 'png',
70 'retina', 'jpeg', 'svg', 'pdf'.""")
66
71
67 figure_format = CaselessStrEnum(['svg', 'png', 'retina', 'jpg'],
72 def _figure_formats_changed(self, name, old, new):
68 default_value='png', config=True,
73 from IPython.core.pylabtools import select_figure_formats
69 help="""The image format for figures with the inline
74 if 'jpg' in new or 'jpeg' in new:
70 backend. JPEG requires the PIL/Pillow library.""")
71
72 def _figure_format_changed(self, name, old, new):
73 from IPython.core.pylabtools import select_figure_format
74 if new in {"jpg", "jpeg"}:
75 if not pil_available():
75 if not pil_available():
76 raise TraitError("Requires PIL/Pillow for JPG figures")
76 raise TraitError("Requires PIL/Pillow for JPG figures")
77 if self.shell is None:
77 if self.shell is None:
78 return
78 return
79 else:
79 else:
80 select_figure_format(self.shell, new)
80 select_figure_formats(self.shell, new)
81
82 figure_format = Unicode(config=True, help="""The figure format to enable (deprecated
83 use `figure_formats` instead)""")
84
85 def _figure_format_changed(self, name, old, new):
86 if new:
87 self.figure_formats = {new}
81
88
82 quality = Int(default_value=90, config=True,
89 quality = Int(default_value=90, config=True,
83 help="Quality of compression [10-100], currently for lossy JPEG only.")
90 help="Quality of compression [10-100], currently for lossy JPEG only.")
84
91
85 def _quality_changed(self, name, old, new):
92 def _quality_changed(self, name, old, new):
86 if new < 10 or new > 100:
93 if new < 10 or new > 100:
87 raise TraitError("figure JPEG quality must be in [10-100] range.")
94 raise TraitError("figure JPEG quality must be in [10-100] range.")
88
95
89 close_figures = Bool(True, config=True,
96 close_figures = Bool(True, config=True,
90 help="""Close all figures at the end of each cell.
97 help="""Close all figures at the end of each cell.
91
98
92 When True, ensures that each cell starts with no active figures, but it
99 When True, ensures that each cell starts with no active figures, but it
93 also means that one must keep track of references in order to edit or
100 also means that one must keep track of references in order to edit or
94 redraw figures in subsequent cells. This mode is ideal for the notebook,
101 redraw figures in subsequent cells. This mode is ideal for the notebook,
95 where residual plots from other cells might be surprising.
102 where residual plots from other cells might be surprising.
96
103
97 When False, one must call figure() to create new figures. This means
104 When False, one must call figure() to create new figures. This means
98 that gcf() and getfigs() can reference figures created in other cells,
105 that gcf() and getfigs() can reference figures created in other cells,
99 and the active figure can continue to be edited with pylab/pyplot
106 and the active figure can continue to be edited with pylab/pyplot
100 methods that reference the current active figure. This mode facilitates
107 methods that reference the current active figure. This mode facilitates
101 iterative editing of figures, and behaves most consistently with
108 iterative editing of figures, and behaves most consistently with
102 other matplotlib backends, but figure barriers between cells must
109 other matplotlib backends, but figure barriers between cells must
103 be explicit.
110 be explicit.
104 """)
111 """)
105
112
106 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
113 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
107
114
108
115
@@ -1,1455 +1,1463 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Facilities for launching IPython processes asynchronously.
3 Facilities for launching IPython processes asynchronously.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * MinRK
8 * MinRK
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import copy
22 import copy
23 import logging
23 import logging
24 import os
24 import os
25 import pipes
25 import pipes
26 import stat
26 import stat
27 import sys
27 import sys
28 import time
28 import time
29
29
30 # signal imports, handling various platforms, versions
30 # signal imports, handling various platforms, versions
31
31
32 from signal import SIGINT, SIGTERM
32 from signal import SIGINT, SIGTERM
33 try:
33 try:
34 from signal import SIGKILL
34 from signal import SIGKILL
35 except ImportError:
35 except ImportError:
36 # Windows
36 # Windows
37 SIGKILL=SIGTERM
37 SIGKILL=SIGTERM
38
38
39 try:
39 try:
40 # Windows >= 2.7, 3.2
40 # Windows >= 2.7, 3.2
41 from signal import CTRL_C_EVENT as SIGINT
41 from signal import CTRL_C_EVENT as SIGINT
42 except ImportError:
42 except ImportError:
43 pass
43 pass
44
44
45 from subprocess import Popen, PIPE, STDOUT
45 from subprocess import Popen, PIPE, STDOUT
46 try:
46 try:
47 from subprocess import check_output
47 from subprocess import check_output
48 except ImportError:
48 except ImportError:
49 # pre-2.7, define check_output with Popen
49 # pre-2.7, define check_output with Popen
50 def check_output(*args, **kwargs):
50 def check_output(*args, **kwargs):
51 kwargs.update(dict(stdout=PIPE))
51 kwargs.update(dict(stdout=PIPE))
52 p = Popen(*args, **kwargs)
52 p = Popen(*args, **kwargs)
53 out,err = p.communicate()
53 out,err = p.communicate()
54 return out
54 return out
55
55
56 from zmq.eventloop import ioloop
56 from zmq.eventloop import ioloop
57
57
58 from IPython.config.application import Application
58 from IPython.config.application import Application
59 from IPython.config.configurable import LoggingConfigurable
59 from IPython.config.configurable import LoggingConfigurable
60 from IPython.utils.text import EvalFormatter
60 from IPython.utils.text import EvalFormatter
61 from IPython.utils.traitlets import (
61 from IPython.utils.traitlets import (
62 Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, CRegExp
62 Any, Integer, CFloat, List, Unicode, Dict, Instance, HasTraits, CRegExp
63 )
63 )
64 from IPython.utils.encoding import DEFAULT_ENCODING
64 from IPython.utils.encoding import DEFAULT_ENCODING
65 from IPython.utils.path import get_home_dir
65 from IPython.utils.path import get_home_dir
66 from IPython.utils.process import find_cmd, FindCmdError
66 from IPython.utils.process import find_cmd, FindCmdError
67 from IPython.utils.py3compat import iteritems, itervalues
67 from IPython.utils.py3compat import iteritems, itervalues
68
68
69 from .win32support import forward_read_events
69 from .win32support import forward_read_events
70
70
71 from .winhpcjob import IPControllerTask, IPEngineTask, IPControllerJob, IPEngineSetJob
71 from .winhpcjob import IPControllerTask, IPEngineTask, IPControllerJob, IPEngineSetJob
72
72
73 WINDOWS = os.name == 'nt'
73 WINDOWS = os.name == 'nt'
74
74
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76 # Paths to the kernel apps
76 # Paths to the kernel apps
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78
78
79 ipcluster_cmd_argv = [sys.executable, "-m", "IPython.parallel.cluster"]
79 ipcluster_cmd_argv = [sys.executable, "-m", "IPython.parallel.cluster"]
80
80
81 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.engine"]
81 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.engine"]
82
82
83 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.controller"]
83 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.controller"]
84
84
85 if WINDOWS and sys.version_info < (3,):
85 if WINDOWS and sys.version_info < (3,):
86 # `python -m package` doesn't work on Windows Python 2,
86 # `python -m package` doesn't work on Windows Python 2,
87 # but `python -m module` does.
87 # but `python -m module` does.
88 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipengineapp"]
88 ipengine_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipengineapp"]
89 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipcontrollerapp"]
89 ipcontroller_cmd_argv = [sys.executable, "-m", "IPython.parallel.apps.ipcontrollerapp"]
90
90
91 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
92 # Base launchers and errors
92 # Base launchers and errors
93 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
94
94
95 class LauncherError(Exception):
95 class LauncherError(Exception):
96 pass
96 pass
97
97
98
98
99 class ProcessStateError(LauncherError):
99 class ProcessStateError(LauncherError):
100 pass
100 pass
101
101
102
102
103 class UnknownStatus(LauncherError):
103 class UnknownStatus(LauncherError):
104 pass
104 pass
105
105
106
106
107 class BaseLauncher(LoggingConfigurable):
107 class BaseLauncher(LoggingConfigurable):
108 """An asbtraction for starting, stopping and signaling a process."""
108 """An asbtraction for starting, stopping and signaling a process."""
109
109
110 # In all of the launchers, the work_dir is where child processes will be
110 # In all of the launchers, the work_dir is where child processes will be
111 # run. This will usually be the profile_dir, but may not be. any work_dir
111 # run. This will usually be the profile_dir, but may not be. any work_dir
112 # passed into the __init__ method will override the config value.
112 # passed into the __init__ method will override the config value.
113 # This should not be used to set the work_dir for the actual engine
113 # This should not be used to set the work_dir for the actual engine
114 # and controller. Instead, use their own config files or the
114 # and controller. Instead, use their own config files or the
115 # controller_args, engine_args attributes of the launchers to add
115 # controller_args, engine_args attributes of the launchers to add
116 # the work_dir option.
116 # the work_dir option.
117 work_dir = Unicode(u'.')
117 work_dir = Unicode(u'.')
118 loop = Instance('zmq.eventloop.ioloop.IOLoop')
118 loop = Instance('zmq.eventloop.ioloop.IOLoop')
119
119
120 start_data = Any()
120 start_data = Any()
121 stop_data = Any()
121 stop_data = Any()
122
122
123 def _loop_default(self):
123 def _loop_default(self):
124 return ioloop.IOLoop.instance()
124 return ioloop.IOLoop.instance()
125
125
126 def __init__(self, work_dir=u'.', config=None, **kwargs):
126 def __init__(self, work_dir=u'.', config=None, **kwargs):
127 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config, **kwargs)
127 super(BaseLauncher, self).__init__(work_dir=work_dir, config=config, **kwargs)
128 self.state = 'before' # can be before, running, after
128 self.state = 'before' # can be before, running, after
129 self.stop_callbacks = []
129 self.stop_callbacks = []
130 self.start_data = None
130 self.start_data = None
131 self.stop_data = None
131 self.stop_data = None
132
132
133 @property
133 @property
134 def args(self):
134 def args(self):
135 """A list of cmd and args that will be used to start the process.
135 """A list of cmd and args that will be used to start the process.
136
136
137 This is what is passed to :func:`spawnProcess` and the first element
137 This is what is passed to :func:`spawnProcess` and the first element
138 will be the process name.
138 will be the process name.
139 """
139 """
140 return self.find_args()
140 return self.find_args()
141
141
142 def find_args(self):
142 def find_args(self):
143 """The ``.args`` property calls this to find the args list.
143 """The ``.args`` property calls this to find the args list.
144
144
145 Subcommand should implement this to construct the cmd and args.
145 Subcommand should implement this to construct the cmd and args.
146 """
146 """
147 raise NotImplementedError('find_args must be implemented in a subclass')
147 raise NotImplementedError('find_args must be implemented in a subclass')
148
148
149 @property
149 @property
150 def arg_str(self):
150 def arg_str(self):
151 """The string form of the program arguments."""
151 """The string form of the program arguments."""
152 return ' '.join(self.args)
152 return ' '.join(self.args)
153
153
154 @property
154 @property
155 def running(self):
155 def running(self):
156 """Am I running."""
156 """Am I running."""
157 if self.state == 'running':
157 if self.state == 'running':
158 return True
158 return True
159 else:
159 else:
160 return False
160 return False
161
161
162 def start(self):
162 def start(self):
163 """Start the process."""
163 """Start the process."""
164 raise NotImplementedError('start must be implemented in a subclass')
164 raise NotImplementedError('start must be implemented in a subclass')
165
165
166 def stop(self):
166 def stop(self):
167 """Stop the process and notify observers of stopping.
167 """Stop the process and notify observers of stopping.
168
168
169 This method will return None immediately.
169 This method will return None immediately.
170 To observe the actual process stopping, see :meth:`on_stop`.
170 To observe the actual process stopping, see :meth:`on_stop`.
171 """
171 """
172 raise NotImplementedError('stop must be implemented in a subclass')
172 raise NotImplementedError('stop must be implemented in a subclass')
173
173
174 def on_stop(self, f):
174 def on_stop(self, f):
175 """Register a callback to be called with this Launcher's stop_data
175 """Register a callback to be called with this Launcher's stop_data
176 when the process actually finishes.
176 when the process actually finishes.
177 """
177 """
178 if self.state=='after':
178 if self.state=='after':
179 return f(self.stop_data)
179 return f(self.stop_data)
180 else:
180 else:
181 self.stop_callbacks.append(f)
181 self.stop_callbacks.append(f)
182
182
183 def notify_start(self, data):
183 def notify_start(self, data):
184 """Call this to trigger startup actions.
184 """Call this to trigger startup actions.
185
185
186 This logs the process startup and sets the state to 'running'. It is
186 This logs the process startup and sets the state to 'running'. It is
187 a pass-through so it can be used as a callback.
187 a pass-through so it can be used as a callback.
188 """
188 """
189
189
190 self.log.debug('Process %r started: %r', self.args[0], data)
190 self.log.debug('Process %r started: %r', self.args[0], data)
191 self.start_data = data
191 self.start_data = data
192 self.state = 'running'
192 self.state = 'running'
193 return data
193 return data
194
194
195 def notify_stop(self, data):
195 def notify_stop(self, data):
196 """Call this to trigger process stop actions.
196 """Call this to trigger process stop actions.
197
197
198 This logs the process stopping and sets the state to 'after'. Call
198 This logs the process stopping and sets the state to 'after'. Call
199 this to trigger callbacks registered via :meth:`on_stop`."""
199 this to trigger callbacks registered via :meth:`on_stop`."""
200
200
201 self.log.debug('Process %r stopped: %r', self.args[0], data)
201 self.log.debug('Process %r stopped: %r', self.args[0], data)
202 self.stop_data = data
202 self.stop_data = data
203 self.state = 'after'
203 self.state = 'after'
204 for i in range(len(self.stop_callbacks)):
204 for i in range(len(self.stop_callbacks)):
205 d = self.stop_callbacks.pop()
205 d = self.stop_callbacks.pop()
206 d(data)
206 d(data)
207 return data
207 return data
208
208
209 def signal(self, sig):
209 def signal(self, sig):
210 """Signal the process.
210 """Signal the process.
211
211
212 Parameters
212 Parameters
213 ----------
213 ----------
214 sig : str or int
214 sig : str or int
215 'KILL', 'INT', etc., or any signal number
215 'KILL', 'INT', etc., or any signal number
216 """
216 """
217 raise NotImplementedError('signal must be implemented in a subclass')
217 raise NotImplementedError('signal must be implemented in a subclass')
218
218
219 class ClusterAppMixin(HasTraits):
219 class ClusterAppMixin(HasTraits):
220 """MixIn for cluster args as traits"""
220 """MixIn for cluster args as traits"""
221 profile_dir=Unicode('')
221 profile_dir=Unicode('')
222 cluster_id=Unicode('')
222 cluster_id=Unicode('')
223
223
224 @property
224 @property
225 def cluster_args(self):
225 def cluster_args(self):
226 return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id]
226 return ['--profile-dir', self.profile_dir, '--cluster-id', self.cluster_id]
227
227
228 class ControllerMixin(ClusterAppMixin):
228 class ControllerMixin(ClusterAppMixin):
229 controller_cmd = List(ipcontroller_cmd_argv, config=True,
229 controller_cmd = List(ipcontroller_cmd_argv, config=True,
230 help="""Popen command to launch ipcontroller.""")
230 help="""Popen command to launch ipcontroller.""")
231 # Command line arguments to ipcontroller.
231 # Command line arguments to ipcontroller.
232 controller_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
232 controller_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
233 help="""command-line args to pass to ipcontroller""")
233 help="""command-line args to pass to ipcontroller""")
234
234
235 class EngineMixin(ClusterAppMixin):
235 class EngineMixin(ClusterAppMixin):
236 engine_cmd = List(ipengine_cmd_argv, config=True,
236 engine_cmd = List(ipengine_cmd_argv, config=True,
237 help="""command to launch the Engine.""")
237 help="""command to launch the Engine.""")
238 # Command line arguments for ipengine.
238 # Command line arguments for ipengine.
239 engine_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
239 engine_args = List(['--log-to-file','--log-level=%i' % logging.INFO], config=True,
240 help="command-line arguments to pass to ipengine"
240 help="command-line arguments to pass to ipengine"
241 )
241 )
242
242
243
243
244 #-----------------------------------------------------------------------------
244 #-----------------------------------------------------------------------------
245 # Local process launchers
245 # Local process launchers
246 #-----------------------------------------------------------------------------
246 #-----------------------------------------------------------------------------
247
247
248
248
249 class LocalProcessLauncher(BaseLauncher):
249 class LocalProcessLauncher(BaseLauncher):
250 """Start and stop an external process in an asynchronous manner.
250 """Start and stop an external process in an asynchronous manner.
251
251
252 This will launch the external process with a working directory of
252 This will launch the external process with a working directory of
253 ``self.work_dir``.
253 ``self.work_dir``.
254 """
254 """
255
255
256 # This is used to to construct self.args, which is passed to
256 # This is used to to construct self.args, which is passed to
257 # spawnProcess.
257 # spawnProcess.
258 cmd_and_args = List([])
258 cmd_and_args = List([])
259 poll_frequency = Integer(100) # in ms
259 poll_frequency = Integer(100) # in ms
260
260
261 def __init__(self, work_dir=u'.', config=None, **kwargs):
261 def __init__(self, work_dir=u'.', config=None, **kwargs):
262 super(LocalProcessLauncher, self).__init__(
262 super(LocalProcessLauncher, self).__init__(
263 work_dir=work_dir, config=config, **kwargs
263 work_dir=work_dir, config=config, **kwargs
264 )
264 )
265 self.process = None
265 self.process = None
266 self.poller = None
266 self.poller = None
267
267
268 def find_args(self):
268 def find_args(self):
269 return self.cmd_and_args
269 return self.cmd_and_args
270
270
271 def start(self):
271 def start(self):
272 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
272 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
273 if self.state == 'before':
273 if self.state == 'before':
274 self.process = Popen(self.args,
274 self.process = Popen(self.args,
275 stdout=PIPE,stderr=PIPE,stdin=PIPE,
275 stdout=PIPE,stderr=PIPE,stdin=PIPE,
276 env=os.environ,
276 env=os.environ,
277 cwd=self.work_dir
277 cwd=self.work_dir
278 )
278 )
279 if WINDOWS:
279 if WINDOWS:
280 self.stdout = forward_read_events(self.process.stdout)
280 self.stdout = forward_read_events(self.process.stdout)
281 self.stderr = forward_read_events(self.process.stderr)
281 self.stderr = forward_read_events(self.process.stderr)
282 else:
282 else:
283 self.stdout = self.process.stdout.fileno()
283 self.stdout = self.process.stdout.fileno()
284 self.stderr = self.process.stderr.fileno()
284 self.stderr = self.process.stderr.fileno()
285 self.loop.add_handler(self.stdout, self.handle_stdout, self.loop.READ)
285 self.loop.add_handler(self.stdout, self.handle_stdout, self.loop.READ)
286 self.loop.add_handler(self.stderr, self.handle_stderr, self.loop.READ)
286 self.loop.add_handler(self.stderr, self.handle_stderr, self.loop.READ)
287 self.poller = ioloop.PeriodicCallback(self.poll, self.poll_frequency, self.loop)
287 self.poller = ioloop.PeriodicCallback(self.poll, self.poll_frequency, self.loop)
288 self.poller.start()
288 self.poller.start()
289 self.notify_start(self.process.pid)
289 self.notify_start(self.process.pid)
290 else:
290 else:
291 s = 'The process was already started and has state: %r' % self.state
291 s = 'The process was already started and has state: %r' % self.state
292 raise ProcessStateError(s)
292 raise ProcessStateError(s)
293
293
294 def stop(self):
294 def stop(self):
295 return self.interrupt_then_kill()
295 return self.interrupt_then_kill()
296
296
297 def signal(self, sig):
297 def signal(self, sig):
298 if self.state == 'running':
298 if self.state == 'running':
299 if WINDOWS and sig != SIGINT:
299 if WINDOWS and sig != SIGINT:
300 # use Windows tree-kill for better child cleanup
300 # use Windows tree-kill for better child cleanup
301 check_output(['taskkill', '-pid', str(self.process.pid), '-t', '-f'])
301 check_output(['taskkill', '-pid', str(self.process.pid), '-t', '-f'])
302 else:
302 else:
303 self.process.send_signal(sig)
303 self.process.send_signal(sig)
304
304
305 def interrupt_then_kill(self, delay=2.0):
305 def interrupt_then_kill(self, delay=2.0):
306 """Send INT, wait a delay and then send KILL."""
306 """Send INT, wait a delay and then send KILL."""
307 try:
307 try:
308 self.signal(SIGINT)
308 self.signal(SIGINT)
309 except Exception:
309 except Exception:
310 self.log.debug("interrupt failed")
310 self.log.debug("interrupt failed")
311 pass
311 pass
312 self.killer = ioloop.DelayedCallback(lambda : self.signal(SIGKILL), delay*1000, self.loop)
312 self.killer = ioloop.DelayedCallback(lambda : self.signal(SIGKILL), delay*1000, self.loop)
313 self.killer.start()
313 self.killer.start()
314
314
315 # callbacks, etc:
315 # callbacks, etc:
316
316
317 def handle_stdout(self, fd, events):
317 def handle_stdout(self, fd, events):
318 if WINDOWS:
318 if WINDOWS:
319 line = self.stdout.recv()
319 line = self.stdout.recv()
320 else:
320 else:
321 line = self.process.stdout.readline()
321 line = self.process.stdout.readline()
322 # a stopped process will be readable but return empty strings
322 # a stopped process will be readable but return empty strings
323 if line:
323 if line:
324 self.log.debug(line[:-1])
324 self.log.debug(line[:-1])
325 else:
325 else:
326 self.poll()
326 self.poll()
327
327
328 def handle_stderr(self, fd, events):
328 def handle_stderr(self, fd, events):
329 if WINDOWS:
329 if WINDOWS:
330 line = self.stderr.recv()
330 line = self.stderr.recv()
331 else:
331 else:
332 line = self.process.stderr.readline()
332 line = self.process.stderr.readline()
333 # a stopped process will be readable but return empty strings
333 # a stopped process will be readable but return empty strings
334 if line:
334 if line:
335 self.log.debug(line[:-1])
335 self.log.debug(line[:-1])
336 else:
336 else:
337 self.poll()
337 self.poll()
338
338
339 def poll(self):
339 def poll(self):
340 status = self.process.poll()
340 status = self.process.poll()
341 if status is not None:
341 if status is not None:
342 self.poller.stop()
342 self.poller.stop()
343 self.loop.remove_handler(self.stdout)
343 self.loop.remove_handler(self.stdout)
344 self.loop.remove_handler(self.stderr)
344 self.loop.remove_handler(self.stderr)
345 self.notify_stop(dict(exit_code=status, pid=self.process.pid))
345 self.notify_stop(dict(exit_code=status, pid=self.process.pid))
346 return status
346 return status
347
347
348 class LocalControllerLauncher(LocalProcessLauncher, ControllerMixin):
348 class LocalControllerLauncher(LocalProcessLauncher, ControllerMixin):
349 """Launch a controller as a regular external process."""
349 """Launch a controller as a regular external process."""
350
350
351 def find_args(self):
351 def find_args(self):
352 return self.controller_cmd + self.cluster_args + self.controller_args
352 return self.controller_cmd + self.cluster_args + self.controller_args
353
353
354 def start(self):
354 def start(self):
355 """Start the controller by profile_dir."""
355 """Start the controller by profile_dir."""
356 return super(LocalControllerLauncher, self).start()
356 return super(LocalControllerLauncher, self).start()
357
357
358
358
359 class LocalEngineLauncher(LocalProcessLauncher, EngineMixin):
359 class LocalEngineLauncher(LocalProcessLauncher, EngineMixin):
360 """Launch a single engine as a regular externall process."""
360 """Launch a single engine as a regular externall process."""
361
361
362 def find_args(self):
362 def find_args(self):
363 return self.engine_cmd + self.cluster_args + self.engine_args
363 return self.engine_cmd + self.cluster_args + self.engine_args
364
364
365
365
366 class LocalEngineSetLauncher(LocalEngineLauncher):
366 class LocalEngineSetLauncher(LocalEngineLauncher):
367 """Launch a set of engines as regular external processes."""
367 """Launch a set of engines as regular external processes."""
368
368
369 delay = CFloat(0.1, config=True,
369 delay = CFloat(0.1, config=True,
370 help="""delay (in seconds) between starting each engine after the first.
370 help="""delay (in seconds) between starting each engine after the first.
371 This can help force the engines to get their ids in order, or limit
371 This can help force the engines to get their ids in order, or limit
372 process flood when starting many engines."""
372 process flood when starting many engines."""
373 )
373 )
374
374
375 # launcher class
375 # launcher class
376 launcher_class = LocalEngineLauncher
376 launcher_class = LocalEngineLauncher
377
377
378 launchers = Dict()
378 launchers = Dict()
379 stop_data = Dict()
379 stop_data = Dict()
380
380
381 def __init__(self, work_dir=u'.', config=None, **kwargs):
381 def __init__(self, work_dir=u'.', config=None, **kwargs):
382 super(LocalEngineSetLauncher, self).__init__(
382 super(LocalEngineSetLauncher, self).__init__(
383 work_dir=work_dir, config=config, **kwargs
383 work_dir=work_dir, config=config, **kwargs
384 )
384 )
385 self.stop_data = {}
385 self.stop_data = {}
386
386
387 def start(self, n):
387 def start(self, n):
388 """Start n engines by profile or profile_dir."""
388 """Start n engines by profile or profile_dir."""
389 dlist = []
389 dlist = []
390 for i in range(n):
390 for i in range(n):
391 if i > 0:
391 if i > 0:
392 time.sleep(self.delay)
392 time.sleep(self.delay)
393 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
393 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
394 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
394 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
395 )
395 )
396
396
397 # Copy the engine args over to each engine launcher.
397 # Copy the engine args over to each engine launcher.
398 el.engine_cmd = copy.deepcopy(self.engine_cmd)
398 el.engine_cmd = copy.deepcopy(self.engine_cmd)
399 el.engine_args = copy.deepcopy(self.engine_args)
399 el.engine_args = copy.deepcopy(self.engine_args)
400 el.on_stop(self._notice_engine_stopped)
400 el.on_stop(self._notice_engine_stopped)
401 d = el.start()
401 d = el.start()
402 self.launchers[i] = el
402 self.launchers[i] = el
403 dlist.append(d)
403 dlist.append(d)
404 self.notify_start(dlist)
404 self.notify_start(dlist)
405 return dlist
405 return dlist
406
406
407 def find_args(self):
407 def find_args(self):
408 return ['engine set']
408 return ['engine set']
409
409
410 def signal(self, sig):
410 def signal(self, sig):
411 dlist = []
411 dlist = []
412 for el in itervalues(self.launchers):
412 for el in itervalues(self.launchers):
413 d = el.signal(sig)
413 d = el.signal(sig)
414 dlist.append(d)
414 dlist.append(d)
415 return dlist
415 return dlist
416
416
417 def interrupt_then_kill(self, delay=1.0):
417 def interrupt_then_kill(self, delay=1.0):
418 dlist = []
418 dlist = []
419 for el in itervalues(self.launchers):
419 for el in itervalues(self.launchers):
420 d = el.interrupt_then_kill(delay)
420 d = el.interrupt_then_kill(delay)
421 dlist.append(d)
421 dlist.append(d)
422 return dlist
422 return dlist
423
423
424 def stop(self):
424 def stop(self):
425 return self.interrupt_then_kill()
425 return self.interrupt_then_kill()
426
426
427 def _notice_engine_stopped(self, data):
427 def _notice_engine_stopped(self, data):
428 pid = data['pid']
428 pid = data['pid']
429 for idx,el in iteritems(self.launchers):
429 for idx,el in iteritems(self.launchers):
430 if el.process.pid == pid:
430 if el.process.pid == pid:
431 break
431 break
432 self.launchers.pop(idx)
432 self.launchers.pop(idx)
433 self.stop_data[idx] = data
433 self.stop_data[idx] = data
434 if not self.launchers:
434 if not self.launchers:
435 self.notify_stop(self.stop_data)
435 self.notify_stop(self.stop_data)
436
436
437
437
438 #-----------------------------------------------------------------------------
438 #-----------------------------------------------------------------------------
439 # MPI launchers
439 # MPI launchers
440 #-----------------------------------------------------------------------------
440 #-----------------------------------------------------------------------------
441
441
442
442
443 class MPILauncher(LocalProcessLauncher):
443 class MPILauncher(LocalProcessLauncher):
444 """Launch an external process using mpiexec."""
444 """Launch an external process using mpiexec."""
445
445
446 mpi_cmd = List(['mpiexec'], config=True,
446 mpi_cmd = List(['mpiexec'], config=True,
447 help="The mpiexec command to use in starting the process."
447 help="The mpiexec command to use in starting the process."
448 )
448 )
449 mpi_args = List([], config=True,
449 mpi_args = List([], config=True,
450 help="The command line arguments to pass to mpiexec."
450 help="The command line arguments to pass to mpiexec."
451 )
451 )
452 program = List(['date'],
452 program = List(['date'],
453 help="The program to start via mpiexec.")
453 help="The program to start via mpiexec.")
454 program_args = List([],
454 program_args = List([],
455 help="The command line argument to the program."
455 help="The command line argument to the program."
456 )
456 )
457 n = Integer(1)
457 n = Integer(1)
458
458
459 def __init__(self, *args, **kwargs):
459 def __init__(self, *args, **kwargs):
460 # deprecation for old MPIExec names:
460 # deprecation for old MPIExec names:
461 config = kwargs.get('config', {})
461 config = kwargs.get('config', {})
462 for oldname in ('MPIExecLauncher', 'MPIExecControllerLauncher', 'MPIExecEngineSetLauncher'):
462 for oldname in ('MPIExecLauncher', 'MPIExecControllerLauncher', 'MPIExecEngineSetLauncher'):
463 deprecated = config.get(oldname)
463 deprecated = config.get(oldname)
464 if deprecated:
464 if deprecated:
465 newname = oldname.replace('MPIExec', 'MPI')
465 newname = oldname.replace('MPIExec', 'MPI')
466 config[newname].update(deprecated)
466 config[newname].update(deprecated)
467 self.log.warn("WARNING: %s name has been deprecated, use %s", oldname, newname)
467 self.log.warn("WARNING: %s name has been deprecated, use %s", oldname, newname)
468
468
469 super(MPILauncher, self).__init__(*args, **kwargs)
469 super(MPILauncher, self).__init__(*args, **kwargs)
470
470
471 def find_args(self):
471 def find_args(self):
472 """Build self.args using all the fields."""
472 """Build self.args using all the fields."""
473 return self.mpi_cmd + ['-n', str(self.n)] + self.mpi_args + \
473 return self.mpi_cmd + ['-n', str(self.n)] + self.mpi_args + \
474 self.program + self.program_args
474 self.program + self.program_args
475
475
476 def start(self, n):
476 def start(self, n):
477 """Start n instances of the program using mpiexec."""
477 """Start n instances of the program using mpiexec."""
478 self.n = n
478 self.n = n
479 return super(MPILauncher, self).start()
479 return super(MPILauncher, self).start()
480
480
481
481
482 class MPIControllerLauncher(MPILauncher, ControllerMixin):
482 class MPIControllerLauncher(MPILauncher, ControllerMixin):
483 """Launch a controller using mpiexec."""
483 """Launch a controller using mpiexec."""
484
484
485 # alias back to *non-configurable* program[_args] for use in find_args()
485 # alias back to *non-configurable* program[_args] for use in find_args()
486 # this way all Controller/EngineSetLaunchers have the same form, rather
486 # this way all Controller/EngineSetLaunchers have the same form, rather
487 # than *some* having `program_args` and others `controller_args`
487 # than *some* having `program_args` and others `controller_args`
488 @property
488 @property
489 def program(self):
489 def program(self):
490 return self.controller_cmd
490 return self.controller_cmd
491
491
492 @property
492 @property
493 def program_args(self):
493 def program_args(self):
494 return self.cluster_args + self.controller_args
494 return self.cluster_args + self.controller_args
495
495
496 def start(self):
496 def start(self):
497 """Start the controller by profile_dir."""
497 """Start the controller by profile_dir."""
498 return super(MPIControllerLauncher, self).start(1)
498 return super(MPIControllerLauncher, self).start(1)
499
499
500
500
501 class MPIEngineSetLauncher(MPILauncher, EngineMixin):
501 class MPIEngineSetLauncher(MPILauncher, EngineMixin):
502 """Launch engines using mpiexec"""
502 """Launch engines using mpiexec"""
503
503
504 # alias back to *non-configurable* program[_args] for use in find_args()
504 # alias back to *non-configurable* program[_args] for use in find_args()
505 # this way all Controller/EngineSetLaunchers have the same form, rather
505 # this way all Controller/EngineSetLaunchers have the same form, rather
506 # than *some* having `program_args` and others `controller_args`
506 # than *some* having `program_args` and others `controller_args`
507 @property
507 @property
508 def program(self):
508 def program(self):
509 return self.engine_cmd
509 return self.engine_cmd
510
510
511 @property
511 @property
512 def program_args(self):
512 def program_args(self):
513 return self.cluster_args + self.engine_args
513 return self.cluster_args + self.engine_args
514
514
515 def start(self, n):
515 def start(self, n):
516 """Start n engines by profile or profile_dir."""
516 """Start n engines by profile or profile_dir."""
517 self.n = n
517 self.n = n
518 return super(MPIEngineSetLauncher, self).start(n)
518 return super(MPIEngineSetLauncher, self).start(n)
519
519
520 # deprecated MPIExec names
520 # deprecated MPIExec names
521 class DeprecatedMPILauncher(object):
521 class DeprecatedMPILauncher(object):
522 def warn(self):
522 def warn(self):
523 oldname = self.__class__.__name__
523 oldname = self.__class__.__name__
524 newname = oldname.replace('MPIExec', 'MPI')
524 newname = oldname.replace('MPIExec', 'MPI')
525 self.log.warn("WARNING: %s name is deprecated, use %s", oldname, newname)
525 self.log.warn("WARNING: %s name is deprecated, use %s", oldname, newname)
526
526
527 class MPIExecLauncher(MPILauncher, DeprecatedMPILauncher):
527 class MPIExecLauncher(MPILauncher, DeprecatedMPILauncher):
528 """Deprecated, use MPILauncher"""
528 """Deprecated, use MPILauncher"""
529 def __init__(self, *args, **kwargs):
529 def __init__(self, *args, **kwargs):
530 super(MPIExecLauncher, self).__init__(*args, **kwargs)
530 super(MPIExecLauncher, self).__init__(*args, **kwargs)
531 self.warn()
531 self.warn()
532
532
533 class MPIExecControllerLauncher(MPIControllerLauncher, DeprecatedMPILauncher):
533 class MPIExecControllerLauncher(MPIControllerLauncher, DeprecatedMPILauncher):
534 """Deprecated, use MPIControllerLauncher"""
534 """Deprecated, use MPIControllerLauncher"""
535 def __init__(self, *args, **kwargs):
535 def __init__(self, *args, **kwargs):
536 super(MPIExecControllerLauncher, self).__init__(*args, **kwargs)
536 super(MPIExecControllerLauncher, self).__init__(*args, **kwargs)
537 self.warn()
537 self.warn()
538
538
539 class MPIExecEngineSetLauncher(MPIEngineSetLauncher, DeprecatedMPILauncher):
539 class MPIExecEngineSetLauncher(MPIEngineSetLauncher, DeprecatedMPILauncher):
540 """Deprecated, use MPIEngineSetLauncher"""
540 """Deprecated, use MPIEngineSetLauncher"""
541 def __init__(self, *args, **kwargs):
541 def __init__(self, *args, **kwargs):
542 super(MPIExecEngineSetLauncher, self).__init__(*args, **kwargs)
542 super(MPIExecEngineSetLauncher, self).__init__(*args, **kwargs)
543 self.warn()
543 self.warn()
544
544
545
545
546 #-----------------------------------------------------------------------------
546 #-----------------------------------------------------------------------------
547 # SSH launchers
547 # SSH launchers
548 #-----------------------------------------------------------------------------
548 #-----------------------------------------------------------------------------
549
549
550 # TODO: Get SSH Launcher back to level of sshx in 0.10.2
550 # TODO: Get SSH Launcher back to level of sshx in 0.10.2
551
551
552 class SSHLauncher(LocalProcessLauncher):
552 class SSHLauncher(LocalProcessLauncher):
553 """A minimal launcher for ssh.
553 """A minimal launcher for ssh.
554
554
555 To be useful this will probably have to be extended to use the ``sshx``
555 To be useful this will probably have to be extended to use the ``sshx``
556 idea for environment variables. There could be other things this needs
556 idea for environment variables. There could be other things this needs
557 as well.
557 as well.
558 """
558 """
559
559
560 ssh_cmd = List(['ssh'], config=True,
560 ssh_cmd = List(['ssh'], config=True,
561 help="command for starting ssh")
561 help="command for starting ssh")
562 ssh_args = List(['-tt'], config=True,
562 ssh_args = List(['-tt'], config=True,
563 help="args to pass to ssh")
563 help="args to pass to ssh")
564 scp_cmd = List(['scp'], config=True,
564 scp_cmd = List(['scp'], config=True,
565 help="command for sending files")
565 help="command for sending files")
566 program = List(['date'],
566 program = List(['date'],
567 help="Program to launch via ssh")
567 help="Program to launch via ssh")
568 program_args = List([],
568 program_args = List([],
569 help="args to pass to remote program")
569 help="args to pass to remote program")
570 hostname = Unicode('', config=True,
570 hostname = Unicode('', config=True,
571 help="hostname on which to launch the program")
571 help="hostname on which to launch the program")
572 user = Unicode('', config=True,
572 user = Unicode('', config=True,
573 help="username for ssh")
573 help="username for ssh")
574 location = Unicode('', config=True,
574 location = Unicode('', config=True,
575 help="user@hostname location for ssh in one setting")
575 help="user@hostname location for ssh in one setting")
576 to_fetch = List([], config=True,
576 to_fetch = List([], config=True,
577 help="List of (remote, local) files to fetch after starting")
577 help="List of (remote, local) files to fetch after starting")
578 to_send = List([], config=True,
578 to_send = List([], config=True,
579 help="List of (local, remote) files to send before starting")
579 help="List of (local, remote) files to send before starting")
580
580
581 def _hostname_changed(self, name, old, new):
581 def _hostname_changed(self, name, old, new):
582 if self.user:
582 if self.user:
583 self.location = u'%s@%s' % (self.user, new)
583 self.location = u'%s@%s' % (self.user, new)
584 else:
584 else:
585 self.location = new
585 self.location = new
586
586
587 def _user_changed(self, name, old, new):
587 def _user_changed(self, name, old, new):
588 self.location = u'%s@%s' % (new, self.hostname)
588 self.location = u'%s@%s' % (new, self.hostname)
589
589
590 def find_args(self):
590 def find_args(self):
591 return self.ssh_cmd + self.ssh_args + [self.location] + \
591 return self.ssh_cmd + self.ssh_args + [self.location] + \
592 list(map(pipes.quote, self.program + self.program_args))
592 list(map(pipes.quote, self.program + self.program_args))
593
593
594 def _send_file(self, local, remote):
594 def _send_file(self, local, remote):
595 """send a single file"""
595 """send a single file"""
596 remote = "%s:%s" % (self.location, remote)
596 remote = "%s:%s" % (self.location, remote)
597 for i in range(10):
597 for i in range(10):
598 if not os.path.exists(local):
598 if not os.path.exists(local):
599 self.log.debug("waiting for %s" % local)
599 self.log.debug("waiting for %s" % local)
600 time.sleep(1)
600 time.sleep(1)
601 else:
601 else:
602 break
602 break
603 remote_dir = os.path.dirname(remote)
604 self.log.info("ensuring remote %s:%s/ exists", self.location, remote_dir)
605 check_output(self.ssh_cmd + self.ssh_args + \
606 [self.location, 'mkdir', '-p', '--', remote_dir]
607 )
603 self.log.info("sending %s to %s", local, remote)
608 self.log.info("sending %s to %s", local, remote)
604 check_output(self.scp_cmd + [local, remote])
609 check_output(self.scp_cmd + [local, remote])
605
610
606 def send_files(self):
611 def send_files(self):
607 """send our files (called before start)"""
612 """send our files (called before start)"""
608 if not self.to_send:
613 if not self.to_send:
609 return
614 return
610 for local_file, remote_file in self.to_send:
615 for local_file, remote_file in self.to_send:
611 self._send_file(local_file, remote_file)
616 self._send_file(local_file, remote_file)
612
617
613 def _fetch_file(self, remote, local):
618 def _fetch_file(self, remote, local):
614 """fetch a single file"""
619 """fetch a single file"""
615 full_remote = "%s:%s" % (self.location, remote)
620 full_remote = "%s:%s" % (self.location, remote)
616 self.log.info("fetching %s from %s", local, full_remote)
621 self.log.info("fetching %s from %s", local, full_remote)
617 for i in range(10):
622 for i in range(10):
618 # wait up to 10s for remote file to exist
623 # wait up to 10s for remote file to exist
619 check = check_output(self.ssh_cmd + self.ssh_args + \
624 check = check_output(self.ssh_cmd + self.ssh_args + \
620 [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"])
625 [self.location, 'test -e', remote, "&& echo 'yes' || echo 'no'"])
621 check = check.decode(DEFAULT_ENCODING, 'replace').strip()
626 check = check.decode(DEFAULT_ENCODING, 'replace').strip()
622 if check == u'no':
627 if check == u'no':
623 time.sleep(1)
628 time.sleep(1)
624 elif check == u'yes':
629 elif check == u'yes':
625 break
630 break
631 local_dir = os.path.dirname(local)
632 if not os.path.exists(local_dir):
633 os.makedirs(local_dir, 775)
626 check_output(self.scp_cmd + [full_remote, local])
634 check_output(self.scp_cmd + [full_remote, local])
627
635
628 def fetch_files(self):
636 def fetch_files(self):
629 """fetch remote files (called after start)"""
637 """fetch remote files (called after start)"""
630 if not self.to_fetch:
638 if not self.to_fetch:
631 return
639 return
632 for remote_file, local_file in self.to_fetch:
640 for remote_file, local_file in self.to_fetch:
633 self._fetch_file(remote_file, local_file)
641 self._fetch_file(remote_file, local_file)
634
642
635 def start(self, hostname=None, user=None):
643 def start(self, hostname=None, user=None):
636 if hostname is not None:
644 if hostname is not None:
637 self.hostname = hostname
645 self.hostname = hostname
638 if user is not None:
646 if user is not None:
639 self.user = user
647 self.user = user
640
648
641 self.send_files()
649 self.send_files()
642 super(SSHLauncher, self).start()
650 super(SSHLauncher, self).start()
643 self.fetch_files()
651 self.fetch_files()
644
652
645 def signal(self, sig):
653 def signal(self, sig):
646 if self.state == 'running':
654 if self.state == 'running':
647 # send escaped ssh connection-closer
655 # send escaped ssh connection-closer
648 self.process.stdin.write('~.')
656 self.process.stdin.write('~.')
649 self.process.stdin.flush()
657 self.process.stdin.flush()
650
658
651 class SSHClusterLauncher(SSHLauncher, ClusterAppMixin):
659 class SSHClusterLauncher(SSHLauncher, ClusterAppMixin):
652
660
653 remote_profile_dir = Unicode('', config=True,
661 remote_profile_dir = Unicode('', config=True,
654 help="""The remote profile_dir to use.
662 help="""The remote profile_dir to use.
655
663
656 If not specified, use calling profile, stripping out possible leading homedir.
664 If not specified, use calling profile, stripping out possible leading homedir.
657 """)
665 """)
658
666
659 def _profile_dir_changed(self, name, old, new):
667 def _profile_dir_changed(self, name, old, new):
660 if not self.remote_profile_dir:
668 if not self.remote_profile_dir:
661 # trigger remote_profile_dir_default logic again,
669 # trigger remote_profile_dir_default logic again,
662 # in case it was already triggered before profile_dir was set
670 # in case it was already triggered before profile_dir was set
663 self.remote_profile_dir = self._strip_home(new)
671 self.remote_profile_dir = self._strip_home(new)
664
672
665 @staticmethod
673 @staticmethod
666 def _strip_home(path):
674 def _strip_home(path):
667 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
675 """turns /home/you/.ipython/profile_foo into .ipython/profile_foo"""
668 home = get_home_dir()
676 home = get_home_dir()
669 if not home.endswith('/'):
677 if not home.endswith('/'):
670 home = home+'/'
678 home = home+'/'
671
679
672 if path.startswith(home):
680 if path.startswith(home):
673 return path[len(home):]
681 return path[len(home):]
674 else:
682 else:
675 return path
683 return path
676
684
677 def _remote_profile_dir_default(self):
685 def _remote_profile_dir_default(self):
678 return self._strip_home(self.profile_dir)
686 return self._strip_home(self.profile_dir)
679
687
680 def _cluster_id_changed(self, name, old, new):
688 def _cluster_id_changed(self, name, old, new):
681 if new:
689 if new:
682 raise ValueError("cluster id not supported by SSH launchers")
690 raise ValueError("cluster id not supported by SSH launchers")
683
691
684 @property
692 @property
685 def cluster_args(self):
693 def cluster_args(self):
686 return ['--profile-dir', self.remote_profile_dir]
694 return ['--profile-dir', self.remote_profile_dir]
687
695
688 class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin):
696 class SSHControllerLauncher(SSHClusterLauncher, ControllerMixin):
689
697
690 # alias back to *non-configurable* program[_args] for use in find_args()
698 # alias back to *non-configurable* program[_args] for use in find_args()
691 # this way all Controller/EngineSetLaunchers have the same form, rather
699 # this way all Controller/EngineSetLaunchers have the same form, rather
692 # than *some* having `program_args` and others `controller_args`
700 # than *some* having `program_args` and others `controller_args`
693
701
694 def _controller_cmd_default(self):
702 def _controller_cmd_default(self):
695 return ['ipcontroller']
703 return ['ipcontroller']
696
704
697 @property
705 @property
698 def program(self):
706 def program(self):
699 return self.controller_cmd
707 return self.controller_cmd
700
708
701 @property
709 @property
702 def program_args(self):
710 def program_args(self):
703 return self.cluster_args + self.controller_args
711 return self.cluster_args + self.controller_args
704
712
705 def _to_fetch_default(self):
713 def _to_fetch_default(self):
706 return [
714 return [
707 (os.path.join(self.remote_profile_dir, 'security', cf),
715 (os.path.join(self.remote_profile_dir, 'security', cf),
708 os.path.join(self.profile_dir, 'security', cf),)
716 os.path.join(self.profile_dir, 'security', cf),)
709 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
717 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
710 ]
718 ]
711
719
712 class SSHEngineLauncher(SSHClusterLauncher, EngineMixin):
720 class SSHEngineLauncher(SSHClusterLauncher, EngineMixin):
713
721
714 # alias back to *non-configurable* program[_args] for use in find_args()
722 # alias back to *non-configurable* program[_args] for use in find_args()
715 # this way all Controller/EngineSetLaunchers have the same form, rather
723 # this way all Controller/EngineSetLaunchers have the same form, rather
716 # than *some* having `program_args` and others `controller_args`
724 # than *some* having `program_args` and others `controller_args`
717
725
718 def _engine_cmd_default(self):
726 def _engine_cmd_default(self):
719 return ['ipengine']
727 return ['ipengine']
720
728
721 @property
729 @property
722 def program(self):
730 def program(self):
723 return self.engine_cmd
731 return self.engine_cmd
724
732
725 @property
733 @property
726 def program_args(self):
734 def program_args(self):
727 return self.cluster_args + self.engine_args
735 return self.cluster_args + self.engine_args
728
736
729 def _to_send_default(self):
737 def _to_send_default(self):
730 return [
738 return [
731 (os.path.join(self.profile_dir, 'security', cf),
739 (os.path.join(self.profile_dir, 'security', cf),
732 os.path.join(self.remote_profile_dir, 'security', cf))
740 os.path.join(self.remote_profile_dir, 'security', cf))
733 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
741 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
734 ]
742 ]
735
743
736
744
737 class SSHEngineSetLauncher(LocalEngineSetLauncher):
745 class SSHEngineSetLauncher(LocalEngineSetLauncher):
738 launcher_class = SSHEngineLauncher
746 launcher_class = SSHEngineLauncher
739 engines = Dict(config=True,
747 engines = Dict(config=True,
740 help="""dict of engines to launch. This is a dict by hostname of ints,
748 help="""dict of engines to launch. This is a dict by hostname of ints,
741 corresponding to the number of engines to start on that host.""")
749 corresponding to the number of engines to start on that host.""")
742
750
743 def _engine_cmd_default(self):
751 def _engine_cmd_default(self):
744 return ['ipengine']
752 return ['ipengine']
745
753
746 @property
754 @property
747 def engine_count(self):
755 def engine_count(self):
748 """determine engine count from `engines` dict"""
756 """determine engine count from `engines` dict"""
749 count = 0
757 count = 0
750 for n in itervalues(self.engines):
758 for n in itervalues(self.engines):
751 if isinstance(n, (tuple,list)):
759 if isinstance(n, (tuple,list)):
752 n,args = n
760 n,args = n
753 count += n
761 count += n
754 return count
762 return count
755
763
756 def start(self, n):
764 def start(self, n):
757 """Start engines by profile or profile_dir.
765 """Start engines by profile or profile_dir.
758 `n` is ignored, and the `engines` config property is used instead.
766 `n` is ignored, and the `engines` config property is used instead.
759 """
767 """
760
768
761 dlist = []
769 dlist = []
762 for host, n in iteritems(self.engines):
770 for host, n in iteritems(self.engines):
763 if isinstance(n, (tuple, list)):
771 if isinstance(n, (tuple, list)):
764 n, args = n
772 n, args = n
765 else:
773 else:
766 args = copy.deepcopy(self.engine_args)
774 args = copy.deepcopy(self.engine_args)
767
775
768 if '@' in host:
776 if '@' in host:
769 user,host = host.split('@',1)
777 user,host = host.split('@',1)
770 else:
778 else:
771 user=None
779 user=None
772 for i in range(n):
780 for i in range(n):
773 if i > 0:
781 if i > 0:
774 time.sleep(self.delay)
782 time.sleep(self.delay)
775 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
783 el = self.launcher_class(work_dir=self.work_dir, parent=self, log=self.log,
776 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
784 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
777 )
785 )
778 if i > 0:
786 if i > 0:
779 # only send files for the first engine on each host
787 # only send files for the first engine on each host
780 el.to_send = []
788 el.to_send = []
781
789
782 # Copy the engine args over to each engine launcher.
790 # Copy the engine args over to each engine launcher.
783 el.engine_cmd = self.engine_cmd
791 el.engine_cmd = self.engine_cmd
784 el.engine_args = args
792 el.engine_args = args
785 el.on_stop(self._notice_engine_stopped)
793 el.on_stop(self._notice_engine_stopped)
786 d = el.start(user=user, hostname=host)
794 d = el.start(user=user, hostname=host)
787 self.launchers[ "%s/%i" % (host,i) ] = el
795 self.launchers[ "%s/%i" % (host,i) ] = el
788 dlist.append(d)
796 dlist.append(d)
789 self.notify_start(dlist)
797 self.notify_start(dlist)
790 return dlist
798 return dlist
791
799
792
800
793 class SSHProxyEngineSetLauncher(SSHClusterLauncher):
801 class SSHProxyEngineSetLauncher(SSHClusterLauncher):
794 """Launcher for calling
802 """Launcher for calling
795 `ipcluster engines` on a remote machine.
803 `ipcluster engines` on a remote machine.
796
804
797 Requires that remote profile is already configured.
805 Requires that remote profile is already configured.
798 """
806 """
799
807
800 n = Integer()
808 n = Integer()
801 ipcluster_cmd = List(['ipcluster'], config=True)
809 ipcluster_cmd = List(['ipcluster'], config=True)
802
810
803 @property
811 @property
804 def program(self):
812 def program(self):
805 return self.ipcluster_cmd + ['engines']
813 return self.ipcluster_cmd + ['engines']
806
814
807 @property
815 @property
808 def program_args(self):
816 def program_args(self):
809 return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir]
817 return ['-n', str(self.n), '--profile-dir', self.remote_profile_dir]
810
818
811 def _to_send_default(self):
819 def _to_send_default(self):
812 return [
820 return [
813 (os.path.join(self.profile_dir, 'security', cf),
821 (os.path.join(self.profile_dir, 'security', cf),
814 os.path.join(self.remote_profile_dir, 'security', cf))
822 os.path.join(self.remote_profile_dir, 'security', cf))
815 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
823 for cf in ('ipcontroller-client.json', 'ipcontroller-engine.json')
816 ]
824 ]
817
825
818 def start(self, n):
826 def start(self, n):
819 self.n = n
827 self.n = n
820 super(SSHProxyEngineSetLauncher, self).start()
828 super(SSHProxyEngineSetLauncher, self).start()
821
829
822
830
823 #-----------------------------------------------------------------------------
831 #-----------------------------------------------------------------------------
824 # Windows HPC Server 2008 scheduler launchers
832 # Windows HPC Server 2008 scheduler launchers
825 #-----------------------------------------------------------------------------
833 #-----------------------------------------------------------------------------
826
834
827
835
828 # This is only used on Windows.
836 # This is only used on Windows.
829 def find_job_cmd():
837 def find_job_cmd():
830 if WINDOWS:
838 if WINDOWS:
831 try:
839 try:
832 return find_cmd('job')
840 return find_cmd('job')
833 except (FindCmdError, ImportError):
841 except (FindCmdError, ImportError):
834 # ImportError will be raised if win32api is not installed
842 # ImportError will be raised if win32api is not installed
835 return 'job'
843 return 'job'
836 else:
844 else:
837 return 'job'
845 return 'job'
838
846
839
847
840 class WindowsHPCLauncher(BaseLauncher):
848 class WindowsHPCLauncher(BaseLauncher):
841
849
842 job_id_regexp = CRegExp(r'\d+', config=True,
850 job_id_regexp = CRegExp(r'\d+', config=True,
843 help="""A regular expression used to get the job id from the output of the
851 help="""A regular expression used to get the job id from the output of the
844 submit_command. """
852 submit_command. """
845 )
853 )
846 job_file_name = Unicode(u'ipython_job.xml', config=True,
854 job_file_name = Unicode(u'ipython_job.xml', config=True,
847 help="The filename of the instantiated job script.")
855 help="The filename of the instantiated job script.")
848 # The full path to the instantiated job script. This gets made dynamically
856 # The full path to the instantiated job script. This gets made dynamically
849 # by combining the work_dir with the job_file_name.
857 # by combining the work_dir with the job_file_name.
850 job_file = Unicode(u'')
858 job_file = Unicode(u'')
851 scheduler = Unicode('', config=True,
859 scheduler = Unicode('', config=True,
852 help="The hostname of the scheduler to submit the job to.")
860 help="The hostname of the scheduler to submit the job to.")
853 job_cmd = Unicode(find_job_cmd(), config=True,
861 job_cmd = Unicode(find_job_cmd(), config=True,
854 help="The command for submitting jobs.")
862 help="The command for submitting jobs.")
855
863
856 def __init__(self, work_dir=u'.', config=None, **kwargs):
864 def __init__(self, work_dir=u'.', config=None, **kwargs):
857 super(WindowsHPCLauncher, self).__init__(
865 super(WindowsHPCLauncher, self).__init__(
858 work_dir=work_dir, config=config, **kwargs
866 work_dir=work_dir, config=config, **kwargs
859 )
867 )
860
868
861 @property
869 @property
862 def job_file(self):
870 def job_file(self):
863 return os.path.join(self.work_dir, self.job_file_name)
871 return os.path.join(self.work_dir, self.job_file_name)
864
872
865 def write_job_file(self, n):
873 def write_job_file(self, n):
866 raise NotImplementedError("Implement write_job_file in a subclass.")
874 raise NotImplementedError("Implement write_job_file in a subclass.")
867
875
868 def find_args(self):
876 def find_args(self):
869 return [u'job.exe']
877 return [u'job.exe']
870
878
871 def parse_job_id(self, output):
879 def parse_job_id(self, output):
872 """Take the output of the submit command and return the job id."""
880 """Take the output of the submit command and return the job id."""
873 m = self.job_id_regexp.search(output)
881 m = self.job_id_regexp.search(output)
874 if m is not None:
882 if m is not None:
875 job_id = m.group()
883 job_id = m.group()
876 else:
884 else:
877 raise LauncherError("Job id couldn't be determined: %s" % output)
885 raise LauncherError("Job id couldn't be determined: %s" % output)
878 self.job_id = job_id
886 self.job_id = job_id
879 self.log.info('Job started with id: %r', job_id)
887 self.log.info('Job started with id: %r', job_id)
880 return job_id
888 return job_id
881
889
882 def start(self, n):
890 def start(self, n):
883 """Start n copies of the process using the Win HPC job scheduler."""
891 """Start n copies of the process using the Win HPC job scheduler."""
884 self.write_job_file(n)
892 self.write_job_file(n)
885 args = [
893 args = [
886 'submit',
894 'submit',
887 '/jobfile:%s' % self.job_file,
895 '/jobfile:%s' % self.job_file,
888 '/scheduler:%s' % self.scheduler
896 '/scheduler:%s' % self.scheduler
889 ]
897 ]
890 self.log.debug("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
898 self.log.debug("Starting Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
891
899
892 output = check_output([self.job_cmd]+args,
900 output = check_output([self.job_cmd]+args,
893 env=os.environ,
901 env=os.environ,
894 cwd=self.work_dir,
902 cwd=self.work_dir,
895 stderr=STDOUT
903 stderr=STDOUT
896 )
904 )
897 output = output.decode(DEFAULT_ENCODING, 'replace')
905 output = output.decode(DEFAULT_ENCODING, 'replace')
898 job_id = self.parse_job_id(output)
906 job_id = self.parse_job_id(output)
899 self.notify_start(job_id)
907 self.notify_start(job_id)
900 return job_id
908 return job_id
901
909
902 def stop(self):
910 def stop(self):
903 args = [
911 args = [
904 'cancel',
912 'cancel',
905 self.job_id,
913 self.job_id,
906 '/scheduler:%s' % self.scheduler
914 '/scheduler:%s' % self.scheduler
907 ]
915 ]
908 self.log.info("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
916 self.log.info("Stopping Win HPC Job: %s" % (self.job_cmd + ' ' + ' '.join(args),))
909 try:
917 try:
910 output = check_output([self.job_cmd]+args,
918 output = check_output([self.job_cmd]+args,
911 env=os.environ,
919 env=os.environ,
912 cwd=self.work_dir,
920 cwd=self.work_dir,
913 stderr=STDOUT
921 stderr=STDOUT
914 )
922 )
915 output = output.decode(DEFAULT_ENCODING, 'replace')
923 output = output.decode(DEFAULT_ENCODING, 'replace')
916 except:
924 except:
917 output = u'The job already appears to be stopped: %r' % self.job_id
925 output = u'The job already appears to be stopped: %r' % self.job_id
918 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
926 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
919 return output
927 return output
920
928
921
929
922 class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):
930 class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):
923
931
924 job_file_name = Unicode(u'ipcontroller_job.xml', config=True,
932 job_file_name = Unicode(u'ipcontroller_job.xml', config=True,
925 help="WinHPC xml job file.")
933 help="WinHPC xml job file.")
926 controller_args = List([], config=False,
934 controller_args = List([], config=False,
927 help="extra args to pass to ipcontroller")
935 help="extra args to pass to ipcontroller")
928
936
929 def write_job_file(self, n):
937 def write_job_file(self, n):
930 job = IPControllerJob(parent=self)
938 job = IPControllerJob(parent=self)
931
939
932 t = IPControllerTask(parent=self)
940 t = IPControllerTask(parent=self)
933 # The tasks work directory is *not* the actual work directory of
941 # The tasks work directory is *not* the actual work directory of
934 # the controller. It is used as the base path for the stdout/stderr
942 # the controller. It is used as the base path for the stdout/stderr
935 # files that the scheduler redirects to.
943 # files that the scheduler redirects to.
936 t.work_directory = self.profile_dir
944 t.work_directory = self.profile_dir
937 # Add the profile_dir and from self.start().
945 # Add the profile_dir and from self.start().
938 t.controller_args.extend(self.cluster_args)
946 t.controller_args.extend(self.cluster_args)
939 t.controller_args.extend(self.controller_args)
947 t.controller_args.extend(self.controller_args)
940 job.add_task(t)
948 job.add_task(t)
941
949
942 self.log.debug("Writing job description file: %s", self.job_file)
950 self.log.debug("Writing job description file: %s", self.job_file)
943 job.write(self.job_file)
951 job.write(self.job_file)
944
952
945 @property
953 @property
946 def job_file(self):
954 def job_file(self):
947 return os.path.join(self.profile_dir, self.job_file_name)
955 return os.path.join(self.profile_dir, self.job_file_name)
948
956
949 def start(self):
957 def start(self):
950 """Start the controller by profile_dir."""
958 """Start the controller by profile_dir."""
951 return super(WindowsHPCControllerLauncher, self).start(1)
959 return super(WindowsHPCControllerLauncher, self).start(1)
952
960
953
961
954 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):
962 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):
955
963
956 job_file_name = Unicode(u'ipengineset_job.xml', config=True,
964 job_file_name = Unicode(u'ipengineset_job.xml', config=True,
957 help="jobfile for ipengines job")
965 help="jobfile for ipengines job")
958 engine_args = List([], config=False,
966 engine_args = List([], config=False,
959 help="extra args to pas to ipengine")
967 help="extra args to pas to ipengine")
960
968
961 def write_job_file(self, n):
969 def write_job_file(self, n):
962 job = IPEngineSetJob(parent=self)
970 job = IPEngineSetJob(parent=self)
963
971
964 for i in range(n):
972 for i in range(n):
965 t = IPEngineTask(parent=self)
973 t = IPEngineTask(parent=self)
966 # The tasks work directory is *not* the actual work directory of
974 # The tasks work directory is *not* the actual work directory of
967 # the engine. It is used as the base path for the stdout/stderr
975 # the engine. It is used as the base path for the stdout/stderr
968 # files that the scheduler redirects to.
976 # files that the scheduler redirects to.
969 t.work_directory = self.profile_dir
977 t.work_directory = self.profile_dir
970 # Add the profile_dir and from self.start().
978 # Add the profile_dir and from self.start().
971 t.engine_args.extend(self.cluster_args)
979 t.engine_args.extend(self.cluster_args)
972 t.engine_args.extend(self.engine_args)
980 t.engine_args.extend(self.engine_args)
973 job.add_task(t)
981 job.add_task(t)
974
982
975 self.log.debug("Writing job description file: %s", self.job_file)
983 self.log.debug("Writing job description file: %s", self.job_file)
976 job.write(self.job_file)
984 job.write(self.job_file)
977
985
978 @property
986 @property
979 def job_file(self):
987 def job_file(self):
980 return os.path.join(self.profile_dir, self.job_file_name)
988 return os.path.join(self.profile_dir, self.job_file_name)
981
989
982 def start(self, n):
990 def start(self, n):
983 """Start the controller by profile_dir."""
991 """Start the controller by profile_dir."""
984 return super(WindowsHPCEngineSetLauncher, self).start(n)
992 return super(WindowsHPCEngineSetLauncher, self).start(n)
985
993
986
994
987 #-----------------------------------------------------------------------------
995 #-----------------------------------------------------------------------------
988 # Batch (PBS) system launchers
996 # Batch (PBS) system launchers
989 #-----------------------------------------------------------------------------
997 #-----------------------------------------------------------------------------
990
998
991 class BatchClusterAppMixin(ClusterAppMixin):
999 class BatchClusterAppMixin(ClusterAppMixin):
992 """ClusterApp mixin that updates the self.context dict, rather than cl-args."""
1000 """ClusterApp mixin that updates the self.context dict, rather than cl-args."""
993 def _profile_dir_changed(self, name, old, new):
1001 def _profile_dir_changed(self, name, old, new):
994 self.context[name] = new
1002 self.context[name] = new
995 _cluster_id_changed = _profile_dir_changed
1003 _cluster_id_changed = _profile_dir_changed
996
1004
997 def _profile_dir_default(self):
1005 def _profile_dir_default(self):
998 self.context['profile_dir'] = ''
1006 self.context['profile_dir'] = ''
999 return ''
1007 return ''
1000 def _cluster_id_default(self):
1008 def _cluster_id_default(self):
1001 self.context['cluster_id'] = ''
1009 self.context['cluster_id'] = ''
1002 return ''
1010 return ''
1003
1011
1004
1012
1005 class BatchSystemLauncher(BaseLauncher):
1013 class BatchSystemLauncher(BaseLauncher):
1006 """Launch an external process using a batch system.
1014 """Launch an external process using a batch system.
1007
1015
1008 This class is designed to work with UNIX batch systems like PBS, LSF,
1016 This class is designed to work with UNIX batch systems like PBS, LSF,
1009 GridEngine, etc. The overall model is that there are different commands
1017 GridEngine, etc. The overall model is that there are different commands
1010 like qsub, qdel, etc. that handle the starting and stopping of the process.
1018 like qsub, qdel, etc. that handle the starting and stopping of the process.
1011
1019
1012 This class also has the notion of a batch script. The ``batch_template``
1020 This class also has the notion of a batch script. The ``batch_template``
1013 attribute can be set to a string that is a template for the batch script.
1021 attribute can be set to a string that is a template for the batch script.
1014 This template is instantiated using string formatting. Thus the template can
1022 This template is instantiated using string formatting. Thus the template can
1015 use {n} fot the number of instances. Subclasses can add additional variables
1023 use {n} fot the number of instances. Subclasses can add additional variables
1016 to the template dict.
1024 to the template dict.
1017 """
1025 """
1018
1026
1019 # Subclasses must fill these in. See PBSEngineSet
1027 # Subclasses must fill these in. See PBSEngineSet
1020 submit_command = List([''], config=True,
1028 submit_command = List([''], config=True,
1021 help="The name of the command line program used to submit jobs.")
1029 help="The name of the command line program used to submit jobs.")
1022 delete_command = List([''], config=True,
1030 delete_command = List([''], config=True,
1023 help="The name of the command line program used to delete jobs.")
1031 help="The name of the command line program used to delete jobs.")
1024 job_id_regexp = CRegExp('', config=True,
1032 job_id_regexp = CRegExp('', config=True,
1025 help="""A regular expression used to get the job id from the output of the
1033 help="""A regular expression used to get the job id from the output of the
1026 submit_command.""")
1034 submit_command.""")
1027 job_id_regexp_group = Integer(0, config=True,
1035 job_id_regexp_group = Integer(0, config=True,
1028 help="""The group we wish to match in job_id_regexp (0 to match all)""")
1036 help="""The group we wish to match in job_id_regexp (0 to match all)""")
1029 batch_template = Unicode('', config=True,
1037 batch_template = Unicode('', config=True,
1030 help="The string that is the batch script template itself.")
1038 help="The string that is the batch script template itself.")
1031 batch_template_file = Unicode(u'', config=True,
1039 batch_template_file = Unicode(u'', config=True,
1032 help="The file that contains the batch template.")
1040 help="The file that contains the batch template.")
1033 batch_file_name = Unicode(u'batch_script', config=True,
1041 batch_file_name = Unicode(u'batch_script', config=True,
1034 help="The filename of the instantiated batch script.")
1042 help="The filename of the instantiated batch script.")
1035 queue = Unicode(u'', config=True,
1043 queue = Unicode(u'', config=True,
1036 help="The PBS Queue.")
1044 help="The PBS Queue.")
1037
1045
1038 def _queue_changed(self, name, old, new):
1046 def _queue_changed(self, name, old, new):
1039 self.context[name] = new
1047 self.context[name] = new
1040
1048
1041 n = Integer(1)
1049 n = Integer(1)
1042 _n_changed = _queue_changed
1050 _n_changed = _queue_changed
1043
1051
1044 # not configurable, override in subclasses
1052 # not configurable, override in subclasses
1045 # PBS Job Array regex
1053 # PBS Job Array regex
1046 job_array_regexp = CRegExp('')
1054 job_array_regexp = CRegExp('')
1047 job_array_template = Unicode('')
1055 job_array_template = Unicode('')
1048 # PBS Queue regex
1056 # PBS Queue regex
1049 queue_regexp = CRegExp('')
1057 queue_regexp = CRegExp('')
1050 queue_template = Unicode('')
1058 queue_template = Unicode('')
1051 # The default batch template, override in subclasses
1059 # The default batch template, override in subclasses
1052 default_template = Unicode('')
1060 default_template = Unicode('')
1053 # The full path to the instantiated batch script.
1061 # The full path to the instantiated batch script.
1054 batch_file = Unicode(u'')
1062 batch_file = Unicode(u'')
1055 # the format dict used with batch_template:
1063 # the format dict used with batch_template:
1056 context = Dict()
1064 context = Dict()
1057
1065
1058 def _context_default(self):
1066 def _context_default(self):
1059 """load the default context with the default values for the basic keys
1067 """load the default context with the default values for the basic keys
1060
1068
1061 because the _trait_changed methods only load the context if they
1069 because the _trait_changed methods only load the context if they
1062 are set to something other than the default value.
1070 are set to something other than the default value.
1063 """
1071 """
1064 return dict(n=1, queue=u'', profile_dir=u'', cluster_id=u'')
1072 return dict(n=1, queue=u'', profile_dir=u'', cluster_id=u'')
1065
1073
1066 # the Formatter instance for rendering the templates:
1074 # the Formatter instance for rendering the templates:
1067 formatter = Instance(EvalFormatter, (), {})
1075 formatter = Instance(EvalFormatter, (), {})
1068
1076
1069 def find_args(self):
1077 def find_args(self):
1070 return self.submit_command + [self.batch_file]
1078 return self.submit_command + [self.batch_file]
1071
1079
1072 def __init__(self, work_dir=u'.', config=None, **kwargs):
1080 def __init__(self, work_dir=u'.', config=None, **kwargs):
1073 super(BatchSystemLauncher, self).__init__(
1081 super(BatchSystemLauncher, self).__init__(
1074 work_dir=work_dir, config=config, **kwargs
1082 work_dir=work_dir, config=config, **kwargs
1075 )
1083 )
1076 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
1084 self.batch_file = os.path.join(self.work_dir, self.batch_file_name)
1077
1085
1078 def parse_job_id(self, output):
1086 def parse_job_id(self, output):
1079 """Take the output of the submit command and return the job id."""
1087 """Take the output of the submit command and return the job id."""
1080 m = self.job_id_regexp.search(output)
1088 m = self.job_id_regexp.search(output)
1081 if m is not None:
1089 if m is not None:
1082 job_id = m.group(self.job_id_regexp_group)
1090 job_id = m.group(self.job_id_regexp_group)
1083 else:
1091 else:
1084 raise LauncherError("Job id couldn't be determined: %s" % output)
1092 raise LauncherError("Job id couldn't be determined: %s" % output)
1085 self.job_id = job_id
1093 self.job_id = job_id
1086 self.log.info('Job submitted with job id: %r', job_id)
1094 self.log.info('Job submitted with job id: %r', job_id)
1087 return job_id
1095 return job_id
1088
1096
1089 def write_batch_script(self, n):
1097 def write_batch_script(self, n):
1090 """Instantiate and write the batch script to the work_dir."""
1098 """Instantiate and write the batch script to the work_dir."""
1091 self.n = n
1099 self.n = n
1092 # first priority is batch_template if set
1100 # first priority is batch_template if set
1093 if self.batch_template_file and not self.batch_template:
1101 if self.batch_template_file and not self.batch_template:
1094 # second priority is batch_template_file
1102 # second priority is batch_template_file
1095 with open(self.batch_template_file) as f:
1103 with open(self.batch_template_file) as f:
1096 self.batch_template = f.read()
1104 self.batch_template = f.read()
1097 if not self.batch_template:
1105 if not self.batch_template:
1098 # third (last) priority is default_template
1106 # third (last) priority is default_template
1099 self.batch_template = self.default_template
1107 self.batch_template = self.default_template
1100 # add jobarray or queue lines to user-specified template
1108 # add jobarray or queue lines to user-specified template
1101 # note that this is *only* when user did not specify a template.
1109 # note that this is *only* when user did not specify a template.
1102 self._insert_queue_in_script()
1110 self._insert_queue_in_script()
1103 self._insert_job_array_in_script()
1111 self._insert_job_array_in_script()
1104 script_as_string = self.formatter.format(self.batch_template, **self.context)
1112 script_as_string = self.formatter.format(self.batch_template, **self.context)
1105 self.log.debug('Writing batch script: %s', self.batch_file)
1113 self.log.debug('Writing batch script: %s', self.batch_file)
1106 with open(self.batch_file, 'w') as f:
1114 with open(self.batch_file, 'w') as f:
1107 f.write(script_as_string)
1115 f.write(script_as_string)
1108 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1116 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
1109
1117
1110 def _insert_queue_in_script(self):
1118 def _insert_queue_in_script(self):
1111 """Inserts a queue if required into the batch script.
1119 """Inserts a queue if required into the batch script.
1112 """
1120 """
1113 if self.queue and not self.queue_regexp.search(self.batch_template):
1121 if self.queue and not self.queue_regexp.search(self.batch_template):
1114 self.log.debug("adding PBS queue settings to batch script")
1122 self.log.debug("adding PBS queue settings to batch script")
1115 firstline, rest = self.batch_template.split('\n',1)
1123 firstline, rest = self.batch_template.split('\n',1)
1116 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
1124 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
1117
1125
1118 def _insert_job_array_in_script(self):
1126 def _insert_job_array_in_script(self):
1119 """Inserts a job array if required into the batch script.
1127 """Inserts a job array if required into the batch script.
1120 """
1128 """
1121 if not self.job_array_regexp.search(self.batch_template):
1129 if not self.job_array_regexp.search(self.batch_template):
1122 self.log.debug("adding job array settings to batch script")
1130 self.log.debug("adding job array settings to batch script")
1123 firstline, rest = self.batch_template.split('\n',1)
1131 firstline, rest = self.batch_template.split('\n',1)
1124 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
1132 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
1125
1133
1126 def start(self, n):
1134 def start(self, n):
1127 """Start n copies of the process using a batch system."""
1135 """Start n copies of the process using a batch system."""
1128 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
1136 self.log.debug("Starting %s: %r", self.__class__.__name__, self.args)
1129 # Here we save profile_dir in the context so they
1137 # Here we save profile_dir in the context so they
1130 # can be used in the batch script template as {profile_dir}
1138 # can be used in the batch script template as {profile_dir}
1131 self.write_batch_script(n)
1139 self.write_batch_script(n)
1132 output = check_output(self.args, env=os.environ)
1140 output = check_output(self.args, env=os.environ)
1133 output = output.decode(DEFAULT_ENCODING, 'replace')
1141 output = output.decode(DEFAULT_ENCODING, 'replace')
1134
1142
1135 job_id = self.parse_job_id(output)
1143 job_id = self.parse_job_id(output)
1136 self.notify_start(job_id)
1144 self.notify_start(job_id)
1137 return job_id
1145 return job_id
1138
1146
1139 def stop(self):
1147 def stop(self):
1140 try:
1148 try:
1141 p = Popen(self.delete_command+[self.job_id], env=os.environ,
1149 p = Popen(self.delete_command+[self.job_id], env=os.environ,
1142 stdout=PIPE, stderr=PIPE)
1150 stdout=PIPE, stderr=PIPE)
1143 out, err = p.communicate()
1151 out, err = p.communicate()
1144 output = out + err
1152 output = out + err
1145 except:
1153 except:
1146 self.log.exception("Problem stopping cluster with command: %s" %
1154 self.log.exception("Problem stopping cluster with command: %s" %
1147 (self.delete_command + [self.job_id]))
1155 (self.delete_command + [self.job_id]))
1148 output = ""
1156 output = ""
1149 output = output.decode(DEFAULT_ENCODING, 'replace')
1157 output = output.decode(DEFAULT_ENCODING, 'replace')
1150 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
1158 self.notify_stop(dict(job_id=self.job_id, output=output)) # Pass the output of the kill cmd
1151 return output
1159 return output
1152
1160
1153
1161
1154 class PBSLauncher(BatchSystemLauncher):
1162 class PBSLauncher(BatchSystemLauncher):
1155 """A BatchSystemLauncher subclass for PBS."""
1163 """A BatchSystemLauncher subclass for PBS."""
1156
1164
1157 submit_command = List(['qsub'], config=True,
1165 submit_command = List(['qsub'], config=True,
1158 help="The PBS submit command ['qsub']")
1166 help="The PBS submit command ['qsub']")
1159 delete_command = List(['qdel'], config=True,
1167 delete_command = List(['qdel'], config=True,
1160 help="The PBS delete command ['qsub']")
1168 help="The PBS delete command ['qsub']")
1161 job_id_regexp = CRegExp(r'\d+', config=True,
1169 job_id_regexp = CRegExp(r'\d+', config=True,
1162 help="Regular expresion for identifying the job ID [r'\d+']")
1170 help="Regular expresion for identifying the job ID [r'\d+']")
1163
1171
1164 batch_file = Unicode(u'')
1172 batch_file = Unicode(u'')
1165 job_array_regexp = CRegExp('#PBS\W+-t\W+[\w\d\-\$]+')
1173 job_array_regexp = CRegExp('#PBS\W+-t\W+[\w\d\-\$]+')
1166 job_array_template = Unicode('#PBS -t 1-{n}')
1174 job_array_template = Unicode('#PBS -t 1-{n}')
1167 queue_regexp = CRegExp('#PBS\W+-q\W+\$?\w+')
1175 queue_regexp = CRegExp('#PBS\W+-q\W+\$?\w+')
1168 queue_template = Unicode('#PBS -q {queue}')
1176 queue_template = Unicode('#PBS -q {queue}')
1169
1177
1170
1178
1171 class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):
1179 class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):
1172 """Launch a controller using PBS."""
1180 """Launch a controller using PBS."""
1173
1181
1174 batch_file_name = Unicode(u'pbs_controller', config=True,
1182 batch_file_name = Unicode(u'pbs_controller', config=True,
1175 help="batch file name for the controller job.")
1183 help="batch file name for the controller job.")
1176 default_template= Unicode("""#!/bin/sh
1184 default_template= Unicode("""#!/bin/sh
1177 #PBS -V
1185 #PBS -V
1178 #PBS -N ipcontroller
1186 #PBS -N ipcontroller
1179 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1187 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1180 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1188 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1181
1189
1182 def start(self):
1190 def start(self):
1183 """Start the controller by profile or profile_dir."""
1191 """Start the controller by profile or profile_dir."""
1184 return super(PBSControllerLauncher, self).start(1)
1192 return super(PBSControllerLauncher, self).start(1)
1185
1193
1186
1194
1187 class PBSEngineSetLauncher(PBSLauncher, BatchClusterAppMixin):
1195 class PBSEngineSetLauncher(PBSLauncher, BatchClusterAppMixin):
1188 """Launch Engines using PBS"""
1196 """Launch Engines using PBS"""
1189 batch_file_name = Unicode(u'pbs_engines', config=True,
1197 batch_file_name = Unicode(u'pbs_engines', config=True,
1190 help="batch file name for the engine(s) job.")
1198 help="batch file name for the engine(s) job.")
1191 default_template= Unicode(u"""#!/bin/sh
1199 default_template= Unicode(u"""#!/bin/sh
1192 #PBS -V
1200 #PBS -V
1193 #PBS -N ipengine
1201 #PBS -N ipengine
1194 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1202 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1195 """%(' '.join(map(pipes.quote,ipengine_cmd_argv))))
1203 """%(' '.join(map(pipes.quote,ipengine_cmd_argv))))
1196
1204
1197
1205
1198 #SGE is very similar to PBS
1206 #SGE is very similar to PBS
1199
1207
1200 class SGELauncher(PBSLauncher):
1208 class SGELauncher(PBSLauncher):
1201 """Sun GridEngine is a PBS clone with slightly different syntax"""
1209 """Sun GridEngine is a PBS clone with slightly different syntax"""
1202 job_array_regexp = CRegExp('#\$\W+\-t')
1210 job_array_regexp = CRegExp('#\$\W+\-t')
1203 job_array_template = Unicode('#$ -t 1-{n}')
1211 job_array_template = Unicode('#$ -t 1-{n}')
1204 queue_regexp = CRegExp('#\$\W+-q\W+\$?\w+')
1212 queue_regexp = CRegExp('#\$\W+-q\W+\$?\w+')
1205 queue_template = Unicode('#$ -q {queue}')
1213 queue_template = Unicode('#$ -q {queue}')
1206
1214
1207
1215
1208 class SGEControllerLauncher(SGELauncher, BatchClusterAppMixin):
1216 class SGEControllerLauncher(SGELauncher, BatchClusterAppMixin):
1209 """Launch a controller using SGE."""
1217 """Launch a controller using SGE."""
1210
1218
1211 batch_file_name = Unicode(u'sge_controller', config=True,
1219 batch_file_name = Unicode(u'sge_controller', config=True,
1212 help="batch file name for the ipontroller job.")
1220 help="batch file name for the ipontroller job.")
1213 default_template= Unicode(u"""#$ -V
1221 default_template= Unicode(u"""#$ -V
1214 #$ -S /bin/sh
1222 #$ -S /bin/sh
1215 #$ -N ipcontroller
1223 #$ -N ipcontroller
1216 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1224 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1217 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1225 """%(' '.join(map(pipes.quote, ipcontroller_cmd_argv))))
1218
1226
1219 def start(self):
1227 def start(self):
1220 """Start the controller by profile or profile_dir."""
1228 """Start the controller by profile or profile_dir."""
1221 return super(SGEControllerLauncher, self).start(1)
1229 return super(SGEControllerLauncher, self).start(1)
1222
1230
1223
1231
1224 class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):
1232 class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):
1225 """Launch Engines with SGE"""
1233 """Launch Engines with SGE"""
1226 batch_file_name = Unicode(u'sge_engines', config=True,
1234 batch_file_name = Unicode(u'sge_engines', config=True,
1227 help="batch file name for the engine(s) job.")
1235 help="batch file name for the engine(s) job.")
1228 default_template = Unicode("""#$ -V
1236 default_template = Unicode("""#$ -V
1229 #$ -S /bin/sh
1237 #$ -S /bin/sh
1230 #$ -N ipengine
1238 #$ -N ipengine
1231 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1239 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1232 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1240 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1233
1241
1234
1242
1235 # LSF launchers
1243 # LSF launchers
1236
1244
1237 class LSFLauncher(BatchSystemLauncher):
1245 class LSFLauncher(BatchSystemLauncher):
1238 """A BatchSystemLauncher subclass for LSF."""
1246 """A BatchSystemLauncher subclass for LSF."""
1239
1247
1240 submit_command = List(['bsub'], config=True,
1248 submit_command = List(['bsub'], config=True,
1241 help="The PBS submit command ['bsub']")
1249 help="The PBS submit command ['bsub']")
1242 delete_command = List(['bkill'], config=True,
1250 delete_command = List(['bkill'], config=True,
1243 help="The PBS delete command ['bkill']")
1251 help="The PBS delete command ['bkill']")
1244 job_id_regexp = CRegExp(r'\d+', config=True,
1252 job_id_regexp = CRegExp(r'\d+', config=True,
1245 help="Regular expresion for identifying the job ID [r'\d+']")
1253 help="Regular expresion for identifying the job ID [r'\d+']")
1246
1254
1247 batch_file = Unicode(u'')
1255 batch_file = Unicode(u'')
1248 job_array_regexp = CRegExp('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1256 job_array_regexp = CRegExp('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1249 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1257 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1250 queue_regexp = CRegExp('#BSUB[ \t]+-q[ \t]+\w+')
1258 queue_regexp = CRegExp('#BSUB[ \t]+-q[ \t]+\w+')
1251 queue_template = Unicode('#BSUB -q {queue}')
1259 queue_template = Unicode('#BSUB -q {queue}')
1252
1260
1253 def start(self, n):
1261 def start(self, n):
1254 """Start n copies of the process using LSF batch system.
1262 """Start n copies of the process using LSF batch system.
1255 This cant inherit from the base class because bsub expects
1263 This cant inherit from the base class because bsub expects
1256 to be piped a shell script in order to honor the #BSUB directives :
1264 to be piped a shell script in order to honor the #BSUB directives :
1257 bsub < script
1265 bsub < script
1258 """
1266 """
1259 # Here we save profile_dir in the context so they
1267 # Here we save profile_dir in the context so they
1260 # can be used in the batch script template as {profile_dir}
1268 # can be used in the batch script template as {profile_dir}
1261 self.write_batch_script(n)
1269 self.write_batch_script(n)
1262 piped_cmd = self.args[0]+'<\"'+self.args[1]+'\"'
1270 piped_cmd = self.args[0]+'<\"'+self.args[1]+'\"'
1263 self.log.debug("Starting %s: %s", self.__class__.__name__, piped_cmd)
1271 self.log.debug("Starting %s: %s", self.__class__.__name__, piped_cmd)
1264 p = Popen(piped_cmd, shell=True,env=os.environ,stdout=PIPE)
1272 p = Popen(piped_cmd, shell=True,env=os.environ,stdout=PIPE)
1265 output,err = p.communicate()
1273 output,err = p.communicate()
1266 output = output.decode(DEFAULT_ENCODING, 'replace')
1274 output = output.decode(DEFAULT_ENCODING, 'replace')
1267 job_id = self.parse_job_id(output)
1275 job_id = self.parse_job_id(output)
1268 self.notify_start(job_id)
1276 self.notify_start(job_id)
1269 return job_id
1277 return job_id
1270
1278
1271
1279
1272 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1280 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1273 """Launch a controller using LSF."""
1281 """Launch a controller using LSF."""
1274
1282
1275 batch_file_name = Unicode(u'lsf_controller', config=True,
1283 batch_file_name = Unicode(u'lsf_controller', config=True,
1276 help="batch file name for the controller job.")
1284 help="batch file name for the controller job.")
1277 default_template= Unicode("""#!/bin/sh
1285 default_template= Unicode("""#!/bin/sh
1278 #BSUB -J ipcontroller
1286 #BSUB -J ipcontroller
1279 #BSUB -oo ipcontroller.o.%%J
1287 #BSUB -oo ipcontroller.o.%%J
1280 #BSUB -eo ipcontroller.e.%%J
1288 #BSUB -eo ipcontroller.e.%%J
1281 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1289 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1282 """%(' '.join(map(pipes.quote,ipcontroller_cmd_argv))))
1290 """%(' '.join(map(pipes.quote,ipcontroller_cmd_argv))))
1283
1291
1284 def start(self):
1292 def start(self):
1285 """Start the controller by profile or profile_dir."""
1293 """Start the controller by profile or profile_dir."""
1286 return super(LSFControllerLauncher, self).start(1)
1294 return super(LSFControllerLauncher, self).start(1)
1287
1295
1288
1296
1289 class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):
1297 class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):
1290 """Launch Engines using LSF"""
1298 """Launch Engines using LSF"""
1291 batch_file_name = Unicode(u'lsf_engines', config=True,
1299 batch_file_name = Unicode(u'lsf_engines', config=True,
1292 help="batch file name for the engine(s) job.")
1300 help="batch file name for the engine(s) job.")
1293 default_template= Unicode(u"""#!/bin/sh
1301 default_template= Unicode(u"""#!/bin/sh
1294 #BSUB -oo ipengine.o.%%J
1302 #BSUB -oo ipengine.o.%%J
1295 #BSUB -eo ipengine.e.%%J
1303 #BSUB -eo ipengine.e.%%J
1296 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1304 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1297 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1305 """%(' '.join(map(pipes.quote, ipengine_cmd_argv))))
1298
1306
1299
1307
1300
1308
1301 class HTCondorLauncher(BatchSystemLauncher):
1309 class HTCondorLauncher(BatchSystemLauncher):
1302 """A BatchSystemLauncher subclass for HTCondor.
1310 """A BatchSystemLauncher subclass for HTCondor.
1303
1311
1304 HTCondor requires that we launch the ipengine/ipcontroller scripts rather
1312 HTCondor requires that we launch the ipengine/ipcontroller scripts rather
1305 that the python instance but otherwise is very similar to PBS. This is because
1313 that the python instance but otherwise is very similar to PBS. This is because
1306 HTCondor destroys sys.executable when launching remote processes - a launched
1314 HTCondor destroys sys.executable when launching remote processes - a launched
1307 python process depends on sys.executable to effectively evaluate its
1315 python process depends on sys.executable to effectively evaluate its
1308 module search paths. Without it, regardless of which python interpreter you launch
1316 module search paths. Without it, regardless of which python interpreter you launch
1309 you will get the to built in module search paths.
1317 you will get the to built in module search paths.
1310
1318
1311 We use the ip{cluster, engine, controller} scripts as our executable to circumvent
1319 We use the ip{cluster, engine, controller} scripts as our executable to circumvent
1312 this - the mechanism of shebanged scripts means that the python binary will be
1320 this - the mechanism of shebanged scripts means that the python binary will be
1313 launched with argv[0] set to the *location of the ip{cluster, engine, controller}
1321 launched with argv[0] set to the *location of the ip{cluster, engine, controller}
1314 scripts on the remote node*. This means you need to take care that:
1322 scripts on the remote node*. This means you need to take care that:
1315
1323
1316 a. Your remote nodes have their paths configured correctly, with the ipengine and ipcontroller
1324 a. Your remote nodes have their paths configured correctly, with the ipengine and ipcontroller
1317 of the python environment you wish to execute code in having top precedence.
1325 of the python environment you wish to execute code in having top precedence.
1318 b. This functionality is untested on Windows.
1326 b. This functionality is untested on Windows.
1319
1327
1320 If you need different behavior, consider making you own template.
1328 If you need different behavior, consider making you own template.
1321 """
1329 """
1322
1330
1323 submit_command = List(['condor_submit'], config=True,
1331 submit_command = List(['condor_submit'], config=True,
1324 help="The HTCondor submit command ['condor_submit']")
1332 help="The HTCondor submit command ['condor_submit']")
1325 delete_command = List(['condor_rm'], config=True,
1333 delete_command = List(['condor_rm'], config=True,
1326 help="The HTCondor delete command ['condor_rm']")
1334 help="The HTCondor delete command ['condor_rm']")
1327 job_id_regexp = CRegExp(r'(\d+)\.$', config=True,
1335 job_id_regexp = CRegExp(r'(\d+)\.$', config=True,
1328 help="Regular expression for identifying the job ID [r'(\d+)\.$']")
1336 help="Regular expression for identifying the job ID [r'(\d+)\.$']")
1329 job_id_regexp_group = Integer(1, config=True,
1337 job_id_regexp_group = Integer(1, config=True,
1330 help="""The group we wish to match in job_id_regexp [1]""")
1338 help="""The group we wish to match in job_id_regexp [1]""")
1331
1339
1332 job_array_regexp = CRegExp('queue\W+\$')
1340 job_array_regexp = CRegExp('queue\W+\$')
1333 job_array_template = Unicode('queue {n}')
1341 job_array_template = Unicode('queue {n}')
1334
1342
1335
1343
1336 def _insert_job_array_in_script(self):
1344 def _insert_job_array_in_script(self):
1337 """Inserts a job array if required into the batch script.
1345 """Inserts a job array if required into the batch script.
1338 """
1346 """
1339 if not self.job_array_regexp.search(self.batch_template):
1347 if not self.job_array_regexp.search(self.batch_template):
1340 self.log.debug("adding job array settings to batch script")
1348 self.log.debug("adding job array settings to batch script")
1341 #HTCondor requires that the job array goes at the bottom of the script
1349 #HTCondor requires that the job array goes at the bottom of the script
1342 self.batch_template = '\n'.join([self.batch_template,
1350 self.batch_template = '\n'.join([self.batch_template,
1343 self.job_array_template])
1351 self.job_array_template])
1344
1352
1345 def _insert_queue_in_script(self):
1353 def _insert_queue_in_script(self):
1346 """AFAIK, HTCondor doesn't have a concept of multiple queues that can be
1354 """AFAIK, HTCondor doesn't have a concept of multiple queues that can be
1347 specified in the script.
1355 specified in the script.
1348 """
1356 """
1349 pass
1357 pass
1350
1358
1351
1359
1352 class HTCondorControllerLauncher(HTCondorLauncher, BatchClusterAppMixin):
1360 class HTCondorControllerLauncher(HTCondorLauncher, BatchClusterAppMixin):
1353 """Launch a controller using HTCondor."""
1361 """Launch a controller using HTCondor."""
1354
1362
1355 batch_file_name = Unicode(u'htcondor_controller', config=True,
1363 batch_file_name = Unicode(u'htcondor_controller', config=True,
1356 help="batch file name for the controller job.")
1364 help="batch file name for the controller job.")
1357 default_template = Unicode(r"""
1365 default_template = Unicode(r"""
1358 universe = vanilla
1366 universe = vanilla
1359 executable = ipcontroller
1367 executable = ipcontroller
1360 # by default we expect a shared file system
1368 # by default we expect a shared file system
1361 transfer_executable = False
1369 transfer_executable = False
1362 arguments = --log-to-file '--profile-dir={profile_dir}' --cluster-id='{cluster_id}'
1370 arguments = --log-to-file '--profile-dir={profile_dir}' --cluster-id='{cluster_id}'
1363 """)
1371 """)
1364
1372
1365 def start(self):
1373 def start(self):
1366 """Start the controller by profile or profile_dir."""
1374 """Start the controller by profile or profile_dir."""
1367 return super(HTCondorControllerLauncher, self).start(1)
1375 return super(HTCondorControllerLauncher, self).start(1)
1368
1376
1369
1377
1370 class HTCondorEngineSetLauncher(HTCondorLauncher, BatchClusterAppMixin):
1378 class HTCondorEngineSetLauncher(HTCondorLauncher, BatchClusterAppMixin):
1371 """Launch Engines using HTCondor"""
1379 """Launch Engines using HTCondor"""
1372 batch_file_name = Unicode(u'htcondor_engines', config=True,
1380 batch_file_name = Unicode(u'htcondor_engines', config=True,
1373 help="batch file name for the engine(s) job.")
1381 help="batch file name for the engine(s) job.")
1374 default_template = Unicode("""
1382 default_template = Unicode("""
1375 universe = vanilla
1383 universe = vanilla
1376 executable = ipengine
1384 executable = ipengine
1377 # by default we expect a shared file system
1385 # by default we expect a shared file system
1378 transfer_executable = False
1386 transfer_executable = False
1379 arguments = "--log-to-file '--profile-dir={profile_dir}' '--cluster-id={cluster_id}'"
1387 arguments = "--log-to-file '--profile-dir={profile_dir}' '--cluster-id={cluster_id}'"
1380 """)
1388 """)
1381
1389
1382
1390
1383 #-----------------------------------------------------------------------------
1391 #-----------------------------------------------------------------------------
1384 # A launcher for ipcluster itself!
1392 # A launcher for ipcluster itself!
1385 #-----------------------------------------------------------------------------
1393 #-----------------------------------------------------------------------------
1386
1394
1387
1395
1388 class IPClusterLauncher(LocalProcessLauncher):
1396 class IPClusterLauncher(LocalProcessLauncher):
1389 """Launch the ipcluster program in an external process."""
1397 """Launch the ipcluster program in an external process."""
1390
1398
1391 ipcluster_cmd = List(ipcluster_cmd_argv, config=True,
1399 ipcluster_cmd = List(ipcluster_cmd_argv, config=True,
1392 help="Popen command for ipcluster")
1400 help="Popen command for ipcluster")
1393 ipcluster_args = List(
1401 ipcluster_args = List(
1394 ['--clean-logs=True', '--log-to-file', '--log-level=%i'%logging.INFO], config=True,
1402 ['--clean-logs=True', '--log-to-file', '--log-level=%i'%logging.INFO], config=True,
1395 help="Command line arguments to pass to ipcluster.")
1403 help="Command line arguments to pass to ipcluster.")
1396 ipcluster_subcommand = Unicode('start')
1404 ipcluster_subcommand = Unicode('start')
1397 profile = Unicode('default')
1405 profile = Unicode('default')
1398 n = Integer(2)
1406 n = Integer(2)
1399
1407
1400 def find_args(self):
1408 def find_args(self):
1401 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
1409 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
1402 ['--n=%i'%self.n, '--profile=%s'%self.profile] + \
1410 ['--n=%i'%self.n, '--profile=%s'%self.profile] + \
1403 self.ipcluster_args
1411 self.ipcluster_args
1404
1412
1405 def start(self):
1413 def start(self):
1406 return super(IPClusterLauncher, self).start()
1414 return super(IPClusterLauncher, self).start()
1407
1415
1408 #-----------------------------------------------------------------------------
1416 #-----------------------------------------------------------------------------
1409 # Collections of launchers
1417 # Collections of launchers
1410 #-----------------------------------------------------------------------------
1418 #-----------------------------------------------------------------------------
1411
1419
1412 local_launchers = [
1420 local_launchers = [
1413 LocalControllerLauncher,
1421 LocalControllerLauncher,
1414 LocalEngineLauncher,
1422 LocalEngineLauncher,
1415 LocalEngineSetLauncher,
1423 LocalEngineSetLauncher,
1416 ]
1424 ]
1417 mpi_launchers = [
1425 mpi_launchers = [
1418 MPILauncher,
1426 MPILauncher,
1419 MPIControllerLauncher,
1427 MPIControllerLauncher,
1420 MPIEngineSetLauncher,
1428 MPIEngineSetLauncher,
1421 ]
1429 ]
1422 ssh_launchers = [
1430 ssh_launchers = [
1423 SSHLauncher,
1431 SSHLauncher,
1424 SSHControllerLauncher,
1432 SSHControllerLauncher,
1425 SSHEngineLauncher,
1433 SSHEngineLauncher,
1426 SSHEngineSetLauncher,
1434 SSHEngineSetLauncher,
1427 SSHProxyEngineSetLauncher,
1435 SSHProxyEngineSetLauncher,
1428 ]
1436 ]
1429 winhpc_launchers = [
1437 winhpc_launchers = [
1430 WindowsHPCLauncher,
1438 WindowsHPCLauncher,
1431 WindowsHPCControllerLauncher,
1439 WindowsHPCControllerLauncher,
1432 WindowsHPCEngineSetLauncher,
1440 WindowsHPCEngineSetLauncher,
1433 ]
1441 ]
1434 pbs_launchers = [
1442 pbs_launchers = [
1435 PBSLauncher,
1443 PBSLauncher,
1436 PBSControllerLauncher,
1444 PBSControllerLauncher,
1437 PBSEngineSetLauncher,
1445 PBSEngineSetLauncher,
1438 ]
1446 ]
1439 sge_launchers = [
1447 sge_launchers = [
1440 SGELauncher,
1448 SGELauncher,
1441 SGEControllerLauncher,
1449 SGEControllerLauncher,
1442 SGEEngineSetLauncher,
1450 SGEEngineSetLauncher,
1443 ]
1451 ]
1444 lsf_launchers = [
1452 lsf_launchers = [
1445 LSFLauncher,
1453 LSFLauncher,
1446 LSFControllerLauncher,
1454 LSFControllerLauncher,
1447 LSFEngineSetLauncher,
1455 LSFEngineSetLauncher,
1448 ]
1456 ]
1449 htcondor_launchers = [
1457 htcondor_launchers = [
1450 HTCondorLauncher,
1458 HTCondorLauncher,
1451 HTCondorControllerLauncher,
1459 HTCondorControllerLauncher,
1452 HTCondorEngineSetLauncher,
1460 HTCondorEngineSetLauncher,
1453 ]
1461 ]
1454 all_launchers = local_launchers + mpi_launchers + ssh_launchers + winhpc_launchers\
1462 all_launchers = local_launchers + mpi_launchers + ssh_launchers + winhpc_launchers\
1455 + pbs_launchers + sge_launchers + lsf_launchers + htcondor_launchers
1463 + pbs_launchers + sge_launchers + lsf_launchers + htcondor_launchers
@@ -1,510 +1,520 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Process Controller
2 """IPython Test Process Controller
3
3
4 This module runs one or more subprocesses which will actually run the IPython
4 This module runs one or more subprocesses which will actually run the IPython
5 test suite.
5 test suite.
6
6
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2009-2011 The IPython Development Team
10 # Copyright (C) 2009-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 from __future__ import print_function
19 from __future__ import print_function
20
20
21 import argparse
21 import argparse
22 import multiprocessing.pool
22 import multiprocessing.pool
23 from multiprocessing import Process, Queue
23 from multiprocessing import Process, Queue
24 import os
24 import os
25 import shutil
25 import shutil
26 import signal
26 import signal
27 import sys
27 import sys
28 import subprocess
28 import subprocess
29 import time
29 import time
30
30
31 from .iptest import have, test_group_names as py_test_group_names, test_sections
31 from .iptest import have, test_group_names as py_test_group_names, test_sections
32 from IPython.utils.path import compress_user
32 from IPython.utils.path import compress_user
33 from IPython.utils.py3compat import bytes_to_str
33 from IPython.utils.py3compat import bytes_to_str
34 from IPython.utils.sysinfo import get_sys_info
34 from IPython.utils.sysinfo import get_sys_info
35 from IPython.utils.tempdir import TemporaryDirectory
35 from IPython.utils.tempdir import TemporaryDirectory
36
36
37
37
38 class TestController(object):
38 class TestController(object):
39 """Run tests in a subprocess
39 """Run tests in a subprocess
40 """
40 """
41 #: str, IPython test suite to be executed.
41 #: str, IPython test suite to be executed.
42 section = None
42 section = None
43 #: list, command line arguments to be executed
43 #: list, command line arguments to be executed
44 cmd = None
44 cmd = None
45 #: dict, extra environment variables to set for the subprocess
45 #: dict, extra environment variables to set for the subprocess
46 env = None
46 env = None
47 #: list, TemporaryDirectory instances to clear up when the process finishes
47 #: list, TemporaryDirectory instances to clear up when the process finishes
48 dirs = None
48 dirs = None
49 #: subprocess.Popen instance
49 #: subprocess.Popen instance
50 process = None
50 process = None
51 #: str, process stdout+stderr
51 #: str, process stdout+stderr
52 stdout = None
52 stdout = None
53 #: bool, whether to capture process stdout & stderr
53 #: bool, whether to capture process stdout & stderr
54 buffer_output = False
54 buffer_output = False
55
55
56 def __init__(self):
56 def __init__(self):
57 self.cmd = []
57 self.cmd = []
58 self.env = {}
58 self.env = {}
59 self.dirs = []
59 self.dirs = []
60
60
61 def launch(self):
61 def launch(self):
62 # print('*** ENV:', self.env) # dbg
62 # print('*** ENV:', self.env) # dbg
63 # print('*** CMD:', self.cmd) # dbg
63 # print('*** CMD:', self.cmd) # dbg
64 env = os.environ.copy()
64 env = os.environ.copy()
65 env.update(self.env)
65 env.update(self.env)
66 output = subprocess.PIPE if self.buffer_output else None
66 output = subprocess.PIPE if self.buffer_output else None
67 stdout = subprocess.STDOUT if self.buffer_output else None
67 stdout = subprocess.STDOUT if self.buffer_output else None
68 self.process = subprocess.Popen(self.cmd, stdout=output,
68 self.process = subprocess.Popen(self.cmd, stdout=output,
69 stderr=stdout, env=env)
69 stderr=stdout, env=env)
70
70
71 def wait(self):
71 def wait(self):
72 self.stdout, _ = self.process.communicate()
72 self.stdout, _ = self.process.communicate()
73 return self.process.returncode
73 return self.process.returncode
74
74
75 def cleanup_process(self):
75 def cleanup_process(self):
76 """Cleanup on exit by killing any leftover processes."""
76 """Cleanup on exit by killing any leftover processes."""
77 subp = self.process
77 subp = self.process
78 if subp is None or (subp.poll() is not None):
78 if subp is None or (subp.poll() is not None):
79 return # Process doesn't exist, or is already dead.
79 return # Process doesn't exist, or is already dead.
80
80
81 try:
81 try:
82 print('Cleaning up stale PID: %d' % subp.pid)
82 print('Cleaning up stale PID: %d' % subp.pid)
83 subp.kill()
83 subp.kill()
84 except: # (OSError, WindowsError) ?
84 except: # (OSError, WindowsError) ?
85 # This is just a best effort, if we fail or the process was
85 # This is just a best effort, if we fail or the process was
86 # really gone, ignore it.
86 # really gone, ignore it.
87 pass
87 pass
88 else:
88 else:
89 for i in range(10):
89 for i in range(10):
90 if subp.poll() is None:
90 if subp.poll() is None:
91 time.sleep(0.1)
91 time.sleep(0.1)
92 else:
92 else:
93 break
93 break
94
94
95 if subp.poll() is None:
95 if subp.poll() is None:
96 # The process did not die...
96 # The process did not die...
97 print('... failed. Manual cleanup may be required.')
97 print('... failed. Manual cleanup may be required.')
98
98
99 def cleanup(self):
99 def cleanup(self):
100 "Kill process if it's still alive, and clean up temporary directories"
100 "Kill process if it's still alive, and clean up temporary directories"
101 self.cleanup_process()
101 self.cleanup_process()
102 for td in self.dirs:
102 for td in self.dirs:
103 td.cleanup()
103 td.cleanup()
104
104
105 __del__ = cleanup
105 __del__ = cleanup
106
106
107 class PyTestController(TestController):
107 class PyTestController(TestController):
108 """Run Python tests using IPython.testing.iptest"""
108 """Run Python tests using IPython.testing.iptest"""
109 #: str, Python command to execute in subprocess
109 #: str, Python command to execute in subprocess
110 pycmd = None
110 pycmd = None
111
111
112 def __init__(self, section):
112 def __init__(self, section):
113 """Create new test runner."""
113 """Create new test runner."""
114 TestController.__init__(self)
114 TestController.__init__(self)
115 self.section = section
115 self.section = section
116 # pycmd is put into cmd[2] in PyTestController.launch()
116 # pycmd is put into cmd[2] in PyTestController.launch()
117 self.cmd = [sys.executable, '-c', None, section]
117 self.cmd = [sys.executable, '-c', None, section]
118 self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
118 self.pycmd = "from IPython.testing.iptest import run_iptest; run_iptest()"
119 ipydir = TemporaryDirectory()
119 ipydir = TemporaryDirectory()
120 self.dirs.append(ipydir)
120 self.dirs.append(ipydir)
121 self.env['IPYTHONDIR'] = ipydir.name
121 self.env['IPYTHONDIR'] = ipydir.name
122 self.workingdir = workingdir = TemporaryDirectory()
122 self.workingdir = workingdir = TemporaryDirectory()
123 self.dirs.append(workingdir)
123 self.dirs.append(workingdir)
124 self.env['IPTEST_WORKING_DIR'] = workingdir.name
124 self.env['IPTEST_WORKING_DIR'] = workingdir.name
125 # This means we won't get odd effects from our own matplotlib config
125 # This means we won't get odd effects from our own matplotlib config
126 self.env['MPLCONFIGDIR'] = workingdir.name
126 self.env['MPLCONFIGDIR'] = workingdir.name
127
127
128 @property
128 @property
129 def will_run(self):
129 def will_run(self):
130 try:
130 try:
131 return test_sections[self.section].will_run
131 return test_sections[self.section].will_run
132 except KeyError:
132 except KeyError:
133 return True
133 return True
134
134
135 def add_xunit(self):
135 def add_xunit(self):
136 xunit_file = os.path.abspath(self.section + '.xunit.xml')
136 xunit_file = os.path.abspath(self.section + '.xunit.xml')
137 self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
137 self.cmd.extend(['--with-xunit', '--xunit-file', xunit_file])
138
138
139 def add_coverage(self):
139 def add_coverage(self):
140 try:
140 try:
141 sources = test_sections[self.section].includes
141 sources = test_sections[self.section].includes
142 except KeyError:
142 except KeyError:
143 sources = ['IPython']
143 sources = ['IPython']
144
144
145 coverage_rc = ("[run]\n"
145 coverage_rc = ("[run]\n"
146 "data_file = {data_file}\n"
146 "data_file = {data_file}\n"
147 "source =\n"
147 "source =\n"
148 " {source}\n"
148 " {source}\n"
149 ).format(data_file=os.path.abspath('.coverage.'+self.section),
149 ).format(data_file=os.path.abspath('.coverage.'+self.section),
150 source="\n ".join(sources))
150 source="\n ".join(sources))
151 config_file = os.path.join(self.workingdir.name, '.coveragerc')
151 config_file = os.path.join(self.workingdir.name, '.coveragerc')
152 with open(config_file, 'w') as f:
152 with open(config_file, 'w') as f:
153 f.write(coverage_rc)
153 f.write(coverage_rc)
154
154
155 self.env['COVERAGE_PROCESS_START'] = config_file
155 self.env['COVERAGE_PROCESS_START'] = config_file
156 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
156 self.pycmd = "import coverage; coverage.process_startup(); " + self.pycmd
157
157
158 def launch(self):
158 def launch(self):
159 self.cmd[2] = self.pycmd
159 self.cmd[2] = self.pycmd
160 super(PyTestController, self).launch()
160 super(PyTestController, self).launch()
161
161
162 js_prefix = 'js/'
163
164 def get_js_test_dir():
165 import IPython.html.tests as t
166 return os.path.join(os.path.dirname(t.__file__), '')
167
168 def all_js_groups():
169 import glob
170 test_dir = get_js_test_dir()
171 all_subdirs = glob.glob(test_dir + '*/')
172 return [js_prefix+os.path.relpath(x, test_dir) for x in all_subdirs if os.path.relpath(x, test_dir) != '__pycache__']
173
162 class JSController(TestController):
174 class JSController(TestController):
163 """Run CasperJS tests """
175 """Run CasperJS tests """
164 def __init__(self, section):
176 def __init__(self, section):
165 """Create new test runner."""
177 """Create new test runner."""
166 TestController.__init__(self)
178 TestController.__init__(self)
167 self.section = section
179 self.section = section
168
180
169 self.ipydir = TemporaryDirectory()
181 self.ipydir = TemporaryDirectory()
170 self.nbdir = TemporaryDirectory()
182 self.nbdir = TemporaryDirectory()
171 print("Running notebook tests in directory: %r" % self.nbdir.name)
183 print("Running notebook tests in directory: %r" % self.nbdir.name)
172 os.makedirs(os.path.join(self.nbdir.name, os.path.join('subdir1', 'subdir1a')))
184 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub ∂ir1', u'sub ∂ir 1a')))
173 os.makedirs(os.path.join(self.nbdir.name, os.path.join('subdir2', 'subdir2a')))
185 os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub ∂ir2', u'sub ∂ir 1b')))
174 self.dirs.append(self.ipydir)
186 self.dirs.append(self.ipydir)
175 self.dirs.append(self.nbdir)
187 self.dirs.append(self.nbdir)
176
188
177 def launch(self):
189 def launch(self):
178 # start the ipython notebook, so we get the port number
190 # start the ipython notebook, so we get the port number
179 self._init_server()
191 self._init_server()
180
192 js_test_dir = get_js_test_dir()
181 import IPython.html.tests as t
193 includes = '--includes=' + os.path.join(js_test_dir,'util.js')
182 test_dir = os.path.join(os.path.dirname(t.__file__), 'casperjs')
194 test_cases = os.path.join(js_test_dir, self.section[len(js_prefix):])
183 includes = '--includes=' + os.path.join(test_dir,'util.js')
184 test_cases = os.path.join(test_dir, 'test_cases')
185 port = '--port=' + str(self.server_port)
195 port = '--port=' + str(self.server_port)
186 self.cmd = ['casperjs', 'test', port, includes, test_cases]
196 self.cmd = ['casperjs', 'test', port, includes, test_cases]
187
188 super(JSController, self).launch()
197 super(JSController, self).launch()
189
198
190 @property
199 @property
191 def will_run(self):
200 def will_run(self):
192 return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs'])
201 return all(have[a] for a in ['zmq', 'tornado', 'jinja2', 'casperjs'])
193
202
194 def _init_server(self):
203 def _init_server(self):
195 "Start the notebook server in a separate process"
204 "Start the notebook server in a separate process"
196 self.queue = q = Queue()
205 self.queue = q = Queue()
197 self.server = Process(target=run_webapp, args=(q, self.ipydir.name, self.nbdir.name))
206 self.server = Process(target=run_webapp, args=(q, self.ipydir.name, self.nbdir.name))
198 self.server.start()
207 self.server.start()
199 self.server_port = q.get()
208 self.server_port = q.get()
200
209
201 def cleanup(self):
210 def cleanup(self):
202 self.server.terminate()
211 self.server.terminate()
203 self.server.join()
212 self.server.join()
204 TestController.cleanup(self)
213 TestController.cleanup(self)
205
214
206 js_test_group_names = {'js'}
207
208 def run_webapp(q, ipydir, nbdir, loglevel=0):
215 def run_webapp(q, ipydir, nbdir, loglevel=0):
209 """start the IPython Notebook, and pass port back to the queue"""
216 """start the IPython Notebook, and pass port back to the queue"""
210 import os
217 import os
211 import IPython.html.notebookapp as nbapp
218 import IPython.html.notebookapp as nbapp
212 import sys
219 import sys
213 sys.stderr = open(os.devnull, 'w')
220 sys.stderr = open(os.devnull, 'w')
214 server = nbapp.NotebookApp()
221 server = nbapp.NotebookApp()
215 args = ['--no-browser']
222 args = ['--no-browser']
216 args.extend(['--ipython-dir', ipydir])
223 args.extend(['--ipython-dir', ipydir])
217 args.extend(['--notebook-dir', nbdir])
224 args.extend(['--notebook-dir', nbdir])
218 args.extend(['--log-level', str(loglevel)])
225 args.extend(['--log-level', str(loglevel)])
219 server.initialize(args)
226 server.initialize(args)
220 # communicate the port number to the parent process
227 # communicate the port number to the parent process
221 q.put(server.port)
228 q.put(server.port)
222 server.start()
229 server.start()
223
230
224 def prepare_controllers(options):
231 def prepare_controllers(options):
225 """Returns two lists of TestController instances, those to run, and those
232 """Returns two lists of TestController instances, those to run, and those
226 not to run."""
233 not to run."""
227 testgroups = options.testgroups
234 testgroups = options.testgroups
228
235
229 if testgroups:
236 if testgroups:
230 py_testgroups = [g for g in testgroups if (g in py_test_group_names) \
237 py_testgroups = [g for g in testgroups if (g in py_test_group_names) \
231 or g.startswith('IPython.')]
238 or g.startswith('IPython.')]
232 js_testgroups = [g for g in testgroups if g in js_test_group_names]
239 if 'js' in testgroups:
240 js_testgroups = all_js_groups()
241 else:
242 js_testgroups = [g for g in testgroups if g not in py_testgroups]
233 else:
243 else:
234 py_testgroups = py_test_group_names
244 py_testgroups = py_test_group_names
235 js_testgroups = js_test_group_names
245 js_testgroups = all_js_groups()
236 if not options.all:
246 if not options.all:
237 test_sections['parallel'].enabled = False
247 test_sections['parallel'].enabled = False
238
248
239 c_js = [JSController(name) for name in js_testgroups]
249 c_js = [JSController(name) for name in js_testgroups]
240 c_py = [PyTestController(name) for name in py_testgroups]
250 c_py = [PyTestController(name) for name in py_testgroups]
241
251
242 configure_py_controllers(c_py, xunit=options.xunit,
252 configure_py_controllers(c_py, xunit=options.xunit,
243 coverage=options.coverage, subproc_streams=options.subproc_streams,
253 coverage=options.coverage, subproc_streams=options.subproc_streams,
244 extra_args=options.extra_args)
254 extra_args=options.extra_args)
245
255
246 controllers = c_py + c_js
256 controllers = c_py + c_js
247 to_run = [c for c in controllers if c.will_run]
257 to_run = [c for c in controllers if c.will_run]
248 not_run = [c for c in controllers if not c.will_run]
258 not_run = [c for c in controllers if not c.will_run]
249 return to_run, not_run
259 return to_run, not_run
250
260
251 def configure_py_controllers(controllers, xunit=False, coverage=False,
261 def configure_py_controllers(controllers, xunit=False, coverage=False,
252 subproc_streams='capture', extra_args=()):
262 subproc_streams='capture', extra_args=()):
253 """Apply options for a collection of TestController objects."""
263 """Apply options for a collection of TestController objects."""
254 for controller in controllers:
264 for controller in controllers:
255 if xunit:
265 if xunit:
256 controller.add_xunit()
266 controller.add_xunit()
257 if coverage:
267 if coverage:
258 controller.add_coverage()
268 controller.add_coverage()
259 controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams
269 controller.env['IPTEST_SUBPROC_STREAMS'] = subproc_streams
260 controller.cmd.extend(extra_args)
270 controller.cmd.extend(extra_args)
261
271
262 def do_run(controller):
272 def do_run(controller):
263 try:
273 try:
264 try:
274 try:
265 controller.launch()
275 controller.launch()
266 except Exception:
276 except Exception:
267 import traceback
277 import traceback
268 traceback.print_exc()
278 traceback.print_exc()
269 return controller, 1 # signal failure
279 return controller, 1 # signal failure
270
280
271 exitcode = controller.wait()
281 exitcode = controller.wait()
272 return controller, exitcode
282 return controller, exitcode
273
283
274 except KeyboardInterrupt:
284 except KeyboardInterrupt:
275 return controller, -signal.SIGINT
285 return controller, -signal.SIGINT
276 finally:
286 finally:
277 controller.cleanup()
287 controller.cleanup()
278
288
279 def report():
289 def report():
280 """Return a string with a summary report of test-related variables."""
290 """Return a string with a summary report of test-related variables."""
281 inf = get_sys_info()
291 inf = get_sys_info()
282 out = []
292 out = []
283 def _add(name, value):
293 def _add(name, value):
284 out.append((name, value))
294 out.append((name, value))
285
295
286 _add('IPython version', inf['ipython_version'])
296 _add('IPython version', inf['ipython_version'])
287 _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
297 _add('IPython commit', "{} ({})".format(inf['commit_hash'], inf['commit_source']))
288 _add('IPython package', compress_user(inf['ipython_path']))
298 _add('IPython package', compress_user(inf['ipython_path']))
289 _add('Python version', inf['sys_version'].replace('\n',''))
299 _add('Python version', inf['sys_version'].replace('\n',''))
290 _add('sys.executable', compress_user(inf['sys_executable']))
300 _add('sys.executable', compress_user(inf['sys_executable']))
291 _add('Platform', inf['platform'])
301 _add('Platform', inf['platform'])
292
302
293 width = max(len(n) for (n,v) in out)
303 width = max(len(n) for (n,v) in out)
294 out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
304 out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out]
295
305
296 avail = []
306 avail = []
297 not_avail = []
307 not_avail = []
298
308
299 for k, is_avail in have.items():
309 for k, is_avail in have.items():
300 if is_avail:
310 if is_avail:
301 avail.append(k)
311 avail.append(k)
302 else:
312 else:
303 not_avail.append(k)
313 not_avail.append(k)
304
314
305 if avail:
315 if avail:
306 out.append('\nTools and libraries available at test time:\n')
316 out.append('\nTools and libraries available at test time:\n')
307 avail.sort()
317 avail.sort()
308 out.append(' ' + ' '.join(avail)+'\n')
318 out.append(' ' + ' '.join(avail)+'\n')
309
319
310 if not_avail:
320 if not_avail:
311 out.append('\nTools and libraries NOT available at test time:\n')
321 out.append('\nTools and libraries NOT available at test time:\n')
312 not_avail.sort()
322 not_avail.sort()
313 out.append(' ' + ' '.join(not_avail)+'\n')
323 out.append(' ' + ' '.join(not_avail)+'\n')
314
324
315 return ''.join(out)
325 return ''.join(out)
316
326
317 def run_iptestall(options):
327 def run_iptestall(options):
318 """Run the entire IPython test suite by calling nose and trial.
328 """Run the entire IPython test suite by calling nose and trial.
319
329
320 This function constructs :class:`IPTester` instances for all IPython
330 This function constructs :class:`IPTester` instances for all IPython
321 modules and package and then runs each of them. This causes the modules
331 modules and package and then runs each of them. This causes the modules
322 and packages of IPython to be tested each in their own subprocess using
332 and packages of IPython to be tested each in their own subprocess using
323 nose.
333 nose.
324
334
325 Parameters
335 Parameters
326 ----------
336 ----------
327
337
328 All parameters are passed as attributes of the options object.
338 All parameters are passed as attributes of the options object.
329
339
330 testgroups : list of str
340 testgroups : list of str
331 Run only these sections of the test suite. If empty, run all the available
341 Run only these sections of the test suite. If empty, run all the available
332 sections.
342 sections.
333
343
334 fast : int or None
344 fast : int or None
335 Run the test suite in parallel, using n simultaneous processes. If None
345 Run the test suite in parallel, using n simultaneous processes. If None
336 is passed, one process is used per CPU core. Default 1 (i.e. sequential)
346 is passed, one process is used per CPU core. Default 1 (i.e. sequential)
337
347
338 inc_slow : bool
348 inc_slow : bool
339 Include slow tests, like IPython.parallel. By default, these tests aren't
349 Include slow tests, like IPython.parallel. By default, these tests aren't
340 run.
350 run.
341
351
342 xunit : bool
352 xunit : bool
343 Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
353 Produce Xunit XML output. This is written to multiple foo.xunit.xml files.
344
354
345 coverage : bool or str
355 coverage : bool or str
346 Measure code coverage from tests. True will store the raw coverage data,
356 Measure code coverage from tests. True will store the raw coverage data,
347 or pass 'html' or 'xml' to get reports.
357 or pass 'html' or 'xml' to get reports.
348
358
349 extra_args : list
359 extra_args : list
350 Extra arguments to pass to the test subprocesses, e.g. '-v'
360 Extra arguments to pass to the test subprocesses, e.g. '-v'
351 """
361 """
352 if options.fast != 1:
362 if options.fast != 1:
353 # If running in parallel, capture output so it doesn't get interleaved
363 # If running in parallel, capture output so it doesn't get interleaved
354 TestController.buffer_output = True
364 TestController.buffer_output = True
355
365
356 to_run, not_run = prepare_controllers(options)
366 to_run, not_run = prepare_controllers(options)
357
367
358 def justify(ltext, rtext, width=70, fill='-'):
368 def justify(ltext, rtext, width=70, fill='-'):
359 ltext += ' '
369 ltext += ' '
360 rtext = (' ' + rtext).rjust(width - len(ltext), fill)
370 rtext = (' ' + rtext).rjust(width - len(ltext), fill)
361 return ltext + rtext
371 return ltext + rtext
362
372
363 # Run all test runners, tracking execution time
373 # Run all test runners, tracking execution time
364 failed = []
374 failed = []
365 t_start = time.time()
375 t_start = time.time()
366
376
367 print()
377 print()
368 if options.fast == 1:
378 if options.fast == 1:
369 # This actually means sequential, i.e. with 1 job
379 # This actually means sequential, i.e. with 1 job
370 for controller in to_run:
380 for controller in to_run:
371 print('IPython test group:', controller.section)
381 print('IPython test group:', controller.section)
372 sys.stdout.flush() # Show in correct order when output is piped
382 sys.stdout.flush() # Show in correct order when output is piped
373 controller, res = do_run(controller)
383 controller, res = do_run(controller)
374 if res:
384 if res:
375 failed.append(controller)
385 failed.append(controller)
376 if res == -signal.SIGINT:
386 if res == -signal.SIGINT:
377 print("Interrupted")
387 print("Interrupted")
378 break
388 break
379 print()
389 print()
380
390
381 else:
391 else:
382 # Run tests concurrently
392 # Run tests concurrently
383 try:
393 try:
384 pool = multiprocessing.pool.ThreadPool(options.fast)
394 pool = multiprocessing.pool.ThreadPool(options.fast)
385 for (controller, res) in pool.imap_unordered(do_run, to_run):
395 for (controller, res) in pool.imap_unordered(do_run, to_run):
386 res_string = 'OK' if res == 0 else 'FAILED'
396 res_string = 'OK' if res == 0 else 'FAILED'
387 print(justify('IPython test group: ' + controller.section, res_string))
397 print(justify('IPython test group: ' + controller.section, res_string))
388 if res:
398 if res:
389 print(bytes_to_str(controller.stdout))
399 print(bytes_to_str(controller.stdout))
390 failed.append(controller)
400 failed.append(controller)
391 if res == -signal.SIGINT:
401 if res == -signal.SIGINT:
392 print("Interrupted")
402 print("Interrupted")
393 break
403 break
394 except KeyboardInterrupt:
404 except KeyboardInterrupt:
395 return
405 return
396
406
397 for controller in not_run:
407 for controller in not_run:
398 print(justify('IPython test group: ' + controller.section, 'NOT RUN'))
408 print(justify('IPython test group: ' + controller.section, 'NOT RUN'))
399
409
400 t_end = time.time()
410 t_end = time.time()
401 t_tests = t_end - t_start
411 t_tests = t_end - t_start
402 nrunners = len(to_run)
412 nrunners = len(to_run)
403 nfail = len(failed)
413 nfail = len(failed)
404 # summarize results
414 # summarize results
405 print('_'*70)
415 print('_'*70)
406 print('Test suite completed for system with the following information:')
416 print('Test suite completed for system with the following information:')
407 print(report())
417 print(report())
408 took = "Took %.3fs." % t_tests
418 took = "Took %.3fs." % t_tests
409 print('Status: ', end='')
419 print('Status: ', end='')
410 if not failed:
420 if not failed:
411 print('OK (%d test groups).' % nrunners, took)
421 print('OK (%d test groups).' % nrunners, took)
412 else:
422 else:
413 # If anything went wrong, point out what command to rerun manually to
423 # If anything went wrong, point out what command to rerun manually to
414 # see the actual errors and individual summary
424 # see the actual errors and individual summary
415 failed_sections = [c.section for c in failed]
425 failed_sections = [c.section for c in failed]
416 print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
426 print('ERROR - {} out of {} test groups failed ({}).'.format(nfail,
417 nrunners, ', '.join(failed_sections)), took)
427 nrunners, ', '.join(failed_sections)), took)
418 print()
428 print()
419 print('You may wish to rerun these, with:')
429 print('You may wish to rerun these, with:')
420 print(' iptest', *failed_sections)
430 print(' iptest', *failed_sections)
421 print()
431 print()
422
432
423 if options.coverage:
433 if options.coverage:
424 from coverage import coverage
434 from coverage import coverage
425 cov = coverage(data_file='.coverage')
435 cov = coverage(data_file='.coverage')
426 cov.combine()
436 cov.combine()
427 cov.save()
437 cov.save()
428
438
429 # Coverage HTML report
439 # Coverage HTML report
430 if options.coverage == 'html':
440 if options.coverage == 'html':
431 html_dir = 'ipy_htmlcov'
441 html_dir = 'ipy_htmlcov'
432 shutil.rmtree(html_dir, ignore_errors=True)
442 shutil.rmtree(html_dir, ignore_errors=True)
433 print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
443 print("Writing HTML coverage report to %s/ ... " % html_dir, end="")
434 sys.stdout.flush()
444 sys.stdout.flush()
435
445
436 # Custom HTML reporter to clean up module names.
446 # Custom HTML reporter to clean up module names.
437 from coverage.html import HtmlReporter
447 from coverage.html import HtmlReporter
438 class CustomHtmlReporter(HtmlReporter):
448 class CustomHtmlReporter(HtmlReporter):
439 def find_code_units(self, morfs):
449 def find_code_units(self, morfs):
440 super(CustomHtmlReporter, self).find_code_units(morfs)
450 super(CustomHtmlReporter, self).find_code_units(morfs)
441 for cu in self.code_units:
451 for cu in self.code_units:
442 nameparts = cu.name.split(os.sep)
452 nameparts = cu.name.split(os.sep)
443 if 'IPython' not in nameparts:
453 if 'IPython' not in nameparts:
444 continue
454 continue
445 ix = nameparts.index('IPython')
455 ix = nameparts.index('IPython')
446 cu.name = '.'.join(nameparts[ix:])
456 cu.name = '.'.join(nameparts[ix:])
447
457
448 # Reimplement the html_report method with our custom reporter
458 # Reimplement the html_report method with our custom reporter
449 cov._harvest_data()
459 cov._harvest_data()
450 cov.config.from_args(omit='*%stests' % os.sep, html_dir=html_dir,
460 cov.config.from_args(omit='*%stests' % os.sep, html_dir=html_dir,
451 html_title='IPython test coverage',
461 html_title='IPython test coverage',
452 )
462 )
453 reporter = CustomHtmlReporter(cov, cov.config)
463 reporter = CustomHtmlReporter(cov, cov.config)
454 reporter.report(None)
464 reporter.report(None)
455 print('done.')
465 print('done.')
456
466
457 # Coverage XML report
467 # Coverage XML report
458 elif options.coverage == 'xml':
468 elif options.coverage == 'xml':
459 cov.xml_report(outfile='ipy_coverage.xml')
469 cov.xml_report(outfile='ipy_coverage.xml')
460
470
461 if failed:
471 if failed:
462 # Ensure that our exit code indicates failure
472 # Ensure that our exit code indicates failure
463 sys.exit(1)
473 sys.exit(1)
464
474
465 argparser = argparse.ArgumentParser(description='Run IPython test suite')
475 argparser = argparse.ArgumentParser(description='Run IPython test suite')
466 argparser.add_argument('testgroups', nargs='*',
476 argparser.add_argument('testgroups', nargs='*',
467 help='Run specified groups of tests. If omitted, run '
477 help='Run specified groups of tests. If omitted, run '
468 'all tests.')
478 'all tests.')
469 argparser.add_argument('--all', action='store_true',
479 argparser.add_argument('--all', action='store_true',
470 help='Include slow tests not run by default.')
480 help='Include slow tests not run by default.')
471 argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
481 argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int,
472 help='Run test sections in parallel.')
482 help='Run test sections in parallel.')
473 argparser.add_argument('--xunit', action='store_true',
483 argparser.add_argument('--xunit', action='store_true',
474 help='Produce Xunit XML results')
484 help='Produce Xunit XML results')
475 argparser.add_argument('--coverage', nargs='?', const=True, default=False,
485 argparser.add_argument('--coverage', nargs='?', const=True, default=False,
476 help="Measure test coverage. Specify 'html' or "
486 help="Measure test coverage. Specify 'html' or "
477 "'xml' to get reports.")
487 "'xml' to get reports.")
478 argparser.add_argument('--subproc-streams', default='capture',
488 argparser.add_argument('--subproc-streams', default='capture',
479 help="What to do with stdout/stderr from subprocesses. "
489 help="What to do with stdout/stderr from subprocesses. "
480 "'capture' (default), 'show' and 'discard' are the options.")
490 "'capture' (default), 'show' and 'discard' are the options.")
481
491
482 def default_options():
492 def default_options():
483 """Get an argparse Namespace object with the default arguments, to pass to
493 """Get an argparse Namespace object with the default arguments, to pass to
484 :func:`run_iptestall`.
494 :func:`run_iptestall`.
485 """
495 """
486 options = argparser.parse_args([])
496 options = argparser.parse_args([])
487 options.extra_args = []
497 options.extra_args = []
488 return options
498 return options
489
499
490 def main():
500 def main():
491 # Arguments after -- should be passed through to nose. Argparse treats
501 # Arguments after -- should be passed through to nose. Argparse treats
492 # everything after -- as regular positional arguments, so we separate them
502 # everything after -- as regular positional arguments, so we separate them
493 # first.
503 # first.
494 try:
504 try:
495 ix = sys.argv.index('--')
505 ix = sys.argv.index('--')
496 except ValueError:
506 except ValueError:
497 to_parse = sys.argv[1:]
507 to_parse = sys.argv[1:]
498 extra_args = []
508 extra_args = []
499 else:
509 else:
500 to_parse = sys.argv[1:ix]
510 to_parse = sys.argv[1:ix]
501 extra_args = sys.argv[ix+1:]
511 extra_args = sys.argv[ix+1:]
502
512
503 options = argparser.parse_args(to_parse)
513 options = argparser.parse_args(to_parse)
504 options.extra_args = extra_args
514 options.extra_args = extra_args
505
515
506 run_iptestall(options)
516 run_iptestall(options)
507
517
508
518
509 if __name__ == '__main__':
519 if __name__ == '__main__':
510 main()
520 main()
@@ -1,247 +1,256 b''
1 """Utilities to manipulate JSON objects.
1 """Utilities to manipulate JSON objects.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010-2011 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # stdlib
13 # stdlib
14 import math
14 import math
15 import re
15 import re
16 import types
16 import types
17 from datetime import datetime
17 from datetime import datetime
18
18
19 try:
19 try:
20 # base64.encodestring is deprecated in Python 3.x
20 # base64.encodestring is deprecated in Python 3.x
21 from base64 import encodebytes
21 from base64 import encodebytes
22 except ImportError:
22 except ImportError:
23 # Python 2.x
23 # Python 2.x
24 from base64 import encodestring as encodebytes
24 from base64 import encodestring as encodebytes
25
25
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27 from IPython.utils.py3compat import string_types, unicode_type, iteritems
27 from IPython.utils.py3compat import string_types, unicode_type, iteritems
28 from IPython.utils.encoding import DEFAULT_ENCODING
28 from IPython.utils.encoding import DEFAULT_ENCODING
29 next_attr_name = '__next__' if py3compat.PY3 else 'next'
29 next_attr_name = '__next__' if py3compat.PY3 else 'next'
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Globals and constants
32 # Globals and constants
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 # timestamp formats
35 # timestamp formats
36 ISO8601 = "%Y-%m-%dT%H:%M:%S.%f"
36 ISO8601 = "%Y-%m-%dT%H:%M:%S.%f"
37 ISO8601_PAT=re.compile(r"^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{1,6})Z?([\+\-]\d{2}:?\d{2})?$")
37 ISO8601_PAT=re.compile(r"^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{1,6})Z?([\+\-]\d{2}:?\d{2})?$")
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Classes and functions
40 # Classes and functions
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43 def rekey(dikt):
43 def rekey(dikt):
44 """Rekey a dict that has been forced to use str keys where there should be
44 """Rekey a dict that has been forced to use str keys where there should be
45 ints by json."""
45 ints by json."""
46 for k in dikt:
46 for k in dikt:
47 if isinstance(k, string_types):
47 if isinstance(k, string_types):
48 ik=fk=None
48 ik=fk=None
49 try:
49 try:
50 ik = int(k)
50 ik = int(k)
51 except ValueError:
51 except ValueError:
52 try:
52 try:
53 fk = float(k)
53 fk = float(k)
54 except ValueError:
54 except ValueError:
55 continue
55 continue
56 if ik is not None:
56 if ik is not None:
57 nk = ik
57 nk = ik
58 else:
58 else:
59 nk = fk
59 nk = fk
60 if nk in dikt:
60 if nk in dikt:
61 raise KeyError("already have key %r"%nk)
61 raise KeyError("already have key %r"%nk)
62 dikt[nk] = dikt.pop(k)
62 dikt[nk] = dikt.pop(k)
63 return dikt
63 return dikt
64
64
65 def parse_date(s):
65 def parse_date(s):
66 """parse an ISO8601 date string
66 """parse an ISO8601 date string
67
67
68 If it is None or not a valid ISO8601 timestamp,
68 If it is None or not a valid ISO8601 timestamp,
69 it will be returned unmodified.
69 it will be returned unmodified.
70 Otherwise, it will return a datetime object.
70 Otherwise, it will return a datetime object.
71 """
71 """
72 if s is None:
72 if s is None:
73 return s
73 return s
74 m = ISO8601_PAT.match(s)
74 m = ISO8601_PAT.match(s)
75 if m:
75 if m:
76 # FIXME: add actual timezone support
76 # FIXME: add actual timezone support
77 # this just drops the timezone info
77 # this just drops the timezone info
78 notz = m.groups()[0]
78 notz = m.groups()[0]
79 return datetime.strptime(notz, ISO8601)
79 return datetime.strptime(notz, ISO8601)
80 return s
80 return s
81
81
82 def extract_dates(obj):
82 def extract_dates(obj):
83 """extract ISO8601 dates from unpacked JSON"""
83 """extract ISO8601 dates from unpacked JSON"""
84 if isinstance(obj, dict):
84 if isinstance(obj, dict):
85 new_obj = {} # don't clobber
85 new_obj = {} # don't clobber
86 for k,v in iteritems(obj):
86 for k,v in iteritems(obj):
87 new_obj[k] = extract_dates(v)
87 new_obj[k] = extract_dates(v)
88 obj = new_obj
88 obj = new_obj
89 elif isinstance(obj, (list, tuple)):
89 elif isinstance(obj, (list, tuple)):
90 obj = [ extract_dates(o) for o in obj ]
90 obj = [ extract_dates(o) for o in obj ]
91 elif isinstance(obj, string_types):
91 elif isinstance(obj, string_types):
92 obj = parse_date(obj)
92 obj = parse_date(obj)
93 return obj
93 return obj
94
94
95 def squash_dates(obj):
95 def squash_dates(obj):
96 """squash datetime objects into ISO8601 strings"""
96 """squash datetime objects into ISO8601 strings"""
97 if isinstance(obj, dict):
97 if isinstance(obj, dict):
98 obj = dict(obj) # don't clobber
98 obj = dict(obj) # don't clobber
99 for k,v in iteritems(obj):
99 for k,v in iteritems(obj):
100 obj[k] = squash_dates(v)
100 obj[k] = squash_dates(v)
101 elif isinstance(obj, (list, tuple)):
101 elif isinstance(obj, (list, tuple)):
102 obj = [ squash_dates(o) for o in obj ]
102 obj = [ squash_dates(o) for o in obj ]
103 elif isinstance(obj, datetime):
103 elif isinstance(obj, datetime):
104 obj = obj.isoformat()
104 obj = obj.isoformat()
105 return obj
105 return obj
106
106
107 def date_default(obj):
107 def date_default(obj):
108 """default function for packing datetime objects in JSON."""
108 """default function for packing datetime objects in JSON."""
109 if isinstance(obj, datetime):
109 if isinstance(obj, datetime):
110 return obj.isoformat()
110 return obj.isoformat()
111 else:
111 else:
112 raise TypeError("%r is not JSON serializable"%obj)
112 raise TypeError("%r is not JSON serializable"%obj)
113
113
114
114
115 # constants for identifying png/jpeg data
115 # constants for identifying png/jpeg data
116 PNG = b'\x89PNG\r\n\x1a\n'
116 PNG = b'\x89PNG\r\n\x1a\n'
117 # front of PNG base64-encoded
117 # front of PNG base64-encoded
118 PNG64 = b'iVBORw0KG'
118 PNG64 = b'iVBORw0KG'
119 JPEG = b'\xff\xd8'
119 JPEG = b'\xff\xd8'
120 # front of JPEG base64-encoded
120 # front of JPEG base64-encoded
121 JPEG64 = b'/9'
121 JPEG64 = b'/9'
122 # front of PDF base64-encoded
123 PDF64 = b'JVBER'
122
124
123 def encode_images(format_dict):
125 def encode_images(format_dict):
124 """b64-encodes images in a displaypub format dict
126 """b64-encodes images in a displaypub format dict
125
127
126 Perhaps this should be handled in json_clean itself?
128 Perhaps this should be handled in json_clean itself?
127
129
128 Parameters
130 Parameters
129 ----------
131 ----------
130
132
131 format_dict : dict
133 format_dict : dict
132 A dictionary of display data keyed by mime-type
134 A dictionary of display data keyed by mime-type
133
135
134 Returns
136 Returns
135 -------
137 -------
136
138
137 format_dict : dict
139 format_dict : dict
138 A copy of the same dictionary,
140 A copy of the same dictionary,
139 but binary image data ('image/png' or 'image/jpeg')
141 but binary image data ('image/png', 'image/jpeg' or 'application/pdf')
140 is base64-encoded.
142 is base64-encoded.
141
143
142 """
144 """
143 encoded = format_dict.copy()
145 encoded = format_dict.copy()
144
146
145 pngdata = format_dict.get('image/png')
147 pngdata = format_dict.get('image/png')
146 if isinstance(pngdata, bytes):
148 if isinstance(pngdata, bytes):
147 # make sure we don't double-encode
149 # make sure we don't double-encode
148 if not pngdata.startswith(PNG64):
150 if not pngdata.startswith(PNG64):
149 pngdata = encodebytes(pngdata)
151 pngdata = encodebytes(pngdata)
150 encoded['image/png'] = pngdata.decode('ascii')
152 encoded['image/png'] = pngdata.decode('ascii')
151
153
152 jpegdata = format_dict.get('image/jpeg')
154 jpegdata = format_dict.get('image/jpeg')
153 if isinstance(jpegdata, bytes):
155 if isinstance(jpegdata, bytes):
154 # make sure we don't double-encode
156 # make sure we don't double-encode
155 if not jpegdata.startswith(JPEG64):
157 if not jpegdata.startswith(JPEG64):
156 jpegdata = encodebytes(jpegdata)
158 jpegdata = encodebytes(jpegdata)
157 encoded['image/jpeg'] = jpegdata.decode('ascii')
159 encoded['image/jpeg'] = jpegdata.decode('ascii')
158
160
161 pdfdata = format_dict.get('application/pdf')
162 if isinstance(pdfdata, bytes):
163 # make sure we don't double-encode
164 if not pdfdata.startswith(PDF64):
165 pdfdata = encodebytes(pdfdata)
166 encoded['application/pdf'] = pdfdata.decode('ascii')
167
159 return encoded
168 return encoded
160
169
161
170
162 def json_clean(obj):
171 def json_clean(obj):
163 """Clean an object to ensure it's safe to encode in JSON.
172 """Clean an object to ensure it's safe to encode in JSON.
164
173
165 Atomic, immutable objects are returned unmodified. Sets and tuples are
174 Atomic, immutable objects are returned unmodified. Sets and tuples are
166 converted to lists, lists are copied and dicts are also copied.
175 converted to lists, lists are copied and dicts are also copied.
167
176
168 Note: dicts whose keys could cause collisions upon encoding (such as a dict
177 Note: dicts whose keys could cause collisions upon encoding (such as a dict
169 with both the number 1 and the string '1' as keys) will cause a ValueError
178 with both the number 1 and the string '1' as keys) will cause a ValueError
170 to be raised.
179 to be raised.
171
180
172 Parameters
181 Parameters
173 ----------
182 ----------
174 obj : any python object
183 obj : any python object
175
184
176 Returns
185 Returns
177 -------
186 -------
178 out : object
187 out : object
179
188
180 A version of the input which will not cause an encoding error when
189 A version of the input which will not cause an encoding error when
181 encoded as JSON. Note that this function does not *encode* its inputs,
190 encoded as JSON. Note that this function does not *encode* its inputs,
182 it simply sanitizes it so that there will be no encoding errors later.
191 it simply sanitizes it so that there will be no encoding errors later.
183
192
184 Examples
193 Examples
185 --------
194 --------
186 >>> json_clean(4)
195 >>> json_clean(4)
187 4
196 4
188 >>> json_clean(list(range(10)))
197 >>> json_clean(list(range(10)))
189 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
198 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
190 >>> sorted(json_clean(dict(x=1, y=2)).items())
199 >>> sorted(json_clean(dict(x=1, y=2)).items())
191 [('x', 1), ('y', 2)]
200 [('x', 1), ('y', 2)]
192 >>> sorted(json_clean(dict(x=1, y=2, z=[1,2,3])).items())
201 >>> sorted(json_clean(dict(x=1, y=2, z=[1,2,3])).items())
193 [('x', 1), ('y', 2), ('z', [1, 2, 3])]
202 [('x', 1), ('y', 2), ('z', [1, 2, 3])]
194 >>> json_clean(True)
203 >>> json_clean(True)
195 True
204 True
196 """
205 """
197 # types that are 'atomic' and ok in json as-is.
206 # types that are 'atomic' and ok in json as-is.
198 atomic_ok = (unicode_type, type(None))
207 atomic_ok = (unicode_type, type(None))
199
208
200 # containers that we need to convert into lists
209 # containers that we need to convert into lists
201 container_to_list = (tuple, set, types.GeneratorType)
210 container_to_list = (tuple, set, types.GeneratorType)
202
211
203 if isinstance(obj, float):
212 if isinstance(obj, float):
204 # cast out-of-range floats to their reprs
213 # cast out-of-range floats to their reprs
205 if math.isnan(obj) or math.isinf(obj):
214 if math.isnan(obj) or math.isinf(obj):
206 return repr(obj)
215 return repr(obj)
207 return float(obj)
216 return float(obj)
208
217
209 if isinstance(obj, int):
218 if isinstance(obj, int):
210 # cast int to int, in case subclasses override __str__ (e.g. boost enum, #4598)
219 # cast int to int, in case subclasses override __str__ (e.g. boost enum, #4598)
211 if isinstance(obj, bool):
220 if isinstance(obj, bool):
212 # bools are ints, but we don't want to cast them to 0,1
221 # bools are ints, but we don't want to cast them to 0,1
213 return obj
222 return obj
214 return int(obj)
223 return int(obj)
215
224
216 if isinstance(obj, atomic_ok):
225 if isinstance(obj, atomic_ok):
217 return obj
226 return obj
218
227
219 if isinstance(obj, bytes):
228 if isinstance(obj, bytes):
220 return obj.decode(DEFAULT_ENCODING, 'replace')
229 return obj.decode(DEFAULT_ENCODING, 'replace')
221
230
222 if isinstance(obj, container_to_list) or (
231 if isinstance(obj, container_to_list) or (
223 hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
232 hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
224 obj = list(obj)
233 obj = list(obj)
225
234
226 if isinstance(obj, list):
235 if isinstance(obj, list):
227 return [json_clean(x) for x in obj]
236 return [json_clean(x) for x in obj]
228
237
229 if isinstance(obj, dict):
238 if isinstance(obj, dict):
230 # First, validate that the dict won't lose data in conversion due to
239 # First, validate that the dict won't lose data in conversion due to
231 # key collisions after stringification. This can happen with keys like
240 # key collisions after stringification. This can happen with keys like
232 # True and 'true' or 1 and '1', which collide in JSON.
241 # True and 'true' or 1 and '1', which collide in JSON.
233 nkeys = len(obj)
242 nkeys = len(obj)
234 nkeys_collapsed = len(set(map(str, obj)))
243 nkeys_collapsed = len(set(map(str, obj)))
235 if nkeys != nkeys_collapsed:
244 if nkeys != nkeys_collapsed:
236 raise ValueError('dict can not be safely converted to JSON: '
245 raise ValueError('dict can not be safely converted to JSON: '
237 'key collision would lead to dropped values')
246 'key collision would lead to dropped values')
238 # If all OK, proceed by making the new dict that will be json-safe
247 # If all OK, proceed by making the new dict that will be json-safe
239 out = {}
248 out = {}
240 for k,v in iteritems(obj):
249 for k,v in iteritems(obj):
241 out[str(k)] = json_clean(v)
250 out[str(k)] = json_clean(v)
242 return out
251 return out
243
252
244 # If we get here, we don't know how to handle the object, so we just get
253 # If we get here, we don't know how to handle the object, so we just get
245 # its repr and return that. This will catch lambdas, open sockets, class
254 # its repr and return that. This will catch lambdas, open sockets, class
246 # objects, and any other complicated contraption that json can't encode
255 # objects, and any other complicated contraption that json can't encode
247 return repr(obj)
256 return repr(obj)
@@ -1,147 +1,149 b''
1 """Test suite for our JSON utilities.
1 """Test suite for our JSON utilities.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010-2011 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING.txt, distributed as part of this software.
7 # the file COPYING.txt, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # stdlib
13 # stdlib
14 import datetime
14 import datetime
15 import json
15 import json
16 from base64 import decodestring
16 from base64 import decodestring
17
17
18 # third party
18 # third party
19 import nose.tools as nt
19 import nose.tools as nt
20
20
21 # our own
21 # our own
22 from IPython.utils import jsonutil, tz
22 from IPython.utils import jsonutil, tz
23 from ..jsonutil import json_clean, encode_images
23 from ..jsonutil import json_clean, encode_images
24 from ..py3compat import unicode_to_str, str_to_bytes, iteritems
24 from ..py3compat import unicode_to_str, str_to_bytes, iteritems
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Test functions
27 # Test functions
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 class Int(int):
29 class Int(int):
30 def __str__(self):
30 def __str__(self):
31 return 'Int(%i)' % self
31 return 'Int(%i)' % self
32
32
33 def test():
33 def test():
34 # list of input/expected output. Use None for the expected output if it
34 # list of input/expected output. Use None for the expected output if it
35 # can be the same as the input.
35 # can be the same as the input.
36 pairs = [(1, None), # start with scalars
36 pairs = [(1, None), # start with scalars
37 (1.0, None),
37 (1.0, None),
38 ('a', None),
38 ('a', None),
39 (True, None),
39 (True, None),
40 (False, None),
40 (False, None),
41 (None, None),
41 (None, None),
42 # complex numbers for now just go to strings, as otherwise they
42 # complex numbers for now just go to strings, as otherwise they
43 # are unserializable
43 # are unserializable
44 (1j, '1j'),
44 (1j, '1j'),
45 # Containers
45 # Containers
46 ([1, 2], None),
46 ([1, 2], None),
47 ((1, 2), [1, 2]),
47 ((1, 2), [1, 2]),
48 (set([1, 2]), [1, 2]),
48 (set([1, 2]), [1, 2]),
49 (dict(x=1), None),
49 (dict(x=1), None),
50 ({'x': 1, 'y':[1,2,3], '1':'int'}, None),
50 ({'x': 1, 'y':[1,2,3], '1':'int'}, None),
51 # More exotic objects
51 # More exotic objects
52 ((x for x in range(3)), [0, 1, 2]),
52 ((x for x in range(3)), [0, 1, 2]),
53 (iter([1, 2]), [1, 2]),
53 (iter([1, 2]), [1, 2]),
54 (Int(5), 5),
54 (Int(5), 5),
55 ]
55 ]
56
56
57 for val, jval in pairs:
57 for val, jval in pairs:
58 if jval is None:
58 if jval is None:
59 jval = val
59 jval = val
60 out = json_clean(val)
60 out = json_clean(val)
61 # validate our cleanup
61 # validate our cleanup
62 nt.assert_equal(out, jval)
62 nt.assert_equal(out, jval)
63 # and ensure that what we return, indeed encodes cleanly
63 # and ensure that what we return, indeed encodes cleanly
64 json.loads(json.dumps(out))
64 json.loads(json.dumps(out))
65
65
66
66
67
67
68 def test_encode_images():
68 def test_encode_images():
69 # invalid data, but the header and footer are from real files
69 # invalid data, but the header and footer are from real files
70 pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82'
70 pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82'
71 jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9'
71 jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9'
72 pdfdata = b'%PDF-1.\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>'
72
73
73 fmt = {
74 fmt = {
74 'image/png' : pngdata,
75 'image/png' : pngdata,
75 'image/jpeg' : jpegdata,
76 'image/jpeg' : jpegdata,
77 'application/pdf' : pdfdata
76 }
78 }
77 encoded = encode_images(fmt)
79 encoded = encode_images(fmt)
78 for key, value in iteritems(fmt):
80 for key, value in iteritems(fmt):
79 # encoded has unicode, want bytes
81 # encoded has unicode, want bytes
80 decoded = decodestring(encoded[key].encode('ascii'))
82 decoded = decodestring(encoded[key].encode('ascii'))
81 nt.assert_equal(decoded, value)
83 nt.assert_equal(decoded, value)
82 encoded2 = encode_images(encoded)
84 encoded2 = encode_images(encoded)
83 nt.assert_equal(encoded, encoded2)
85 nt.assert_equal(encoded, encoded2)
84
86
85 b64_str = {}
87 b64_str = {}
86 for key, encoded in iteritems(encoded):
88 for key, encoded in iteritems(encoded):
87 b64_str[key] = unicode_to_str(encoded)
89 b64_str[key] = unicode_to_str(encoded)
88 encoded3 = encode_images(b64_str)
90 encoded3 = encode_images(b64_str)
89 nt.assert_equal(encoded3, b64_str)
91 nt.assert_equal(encoded3, b64_str)
90 for key, value in iteritems(fmt):
92 for key, value in iteritems(fmt):
91 # encoded3 has str, want bytes
93 # encoded3 has str, want bytes
92 decoded = decodestring(str_to_bytes(encoded3[key]))
94 decoded = decodestring(str_to_bytes(encoded3[key]))
93 nt.assert_equal(decoded, value)
95 nt.assert_equal(decoded, value)
94
96
95 def test_lambda():
97 def test_lambda():
96 jc = json_clean(lambda : 1)
98 jc = json_clean(lambda : 1)
97 assert isinstance(jc, str)
99 assert isinstance(jc, str)
98 assert '<lambda>' in jc
100 assert '<lambda>' in jc
99 json.dumps(jc)
101 json.dumps(jc)
100
102
101 def test_extract_dates():
103 def test_extract_dates():
102 timestamps = [
104 timestamps = [
103 '2013-07-03T16:34:52.249482',
105 '2013-07-03T16:34:52.249482',
104 '2013-07-03T16:34:52.249482Z',
106 '2013-07-03T16:34:52.249482Z',
105 '2013-07-03T16:34:52.249482Z-0800',
107 '2013-07-03T16:34:52.249482Z-0800',
106 '2013-07-03T16:34:52.249482Z+0800',
108 '2013-07-03T16:34:52.249482Z+0800',
107 '2013-07-03T16:34:52.249482Z+08:00',
109 '2013-07-03T16:34:52.249482Z+08:00',
108 '2013-07-03T16:34:52.249482Z-08:00',
110 '2013-07-03T16:34:52.249482Z-08:00',
109 '2013-07-03T16:34:52.249482-0800',
111 '2013-07-03T16:34:52.249482-0800',
110 '2013-07-03T16:34:52.249482+0800',
112 '2013-07-03T16:34:52.249482+0800',
111 '2013-07-03T16:34:52.249482+08:00',
113 '2013-07-03T16:34:52.249482+08:00',
112 '2013-07-03T16:34:52.249482-08:00',
114 '2013-07-03T16:34:52.249482-08:00',
113 ]
115 ]
114 extracted = jsonutil.extract_dates(timestamps)
116 extracted = jsonutil.extract_dates(timestamps)
115 ref = extracted[0]
117 ref = extracted[0]
116 for dt in extracted:
118 for dt in extracted:
117 nt.assert_true(isinstance(dt, datetime.datetime))
119 nt.assert_true(isinstance(dt, datetime.datetime))
118 nt.assert_equal(dt, ref)
120 nt.assert_equal(dt, ref)
119
121
120 def test_parse_ms_precision():
122 def test_parse_ms_precision():
121 base = '2013-07-03T16:34:52.'
123 base = '2013-07-03T16:34:52.'
122 digits = '1234567890'
124 digits = '1234567890'
123
125
124 for i in range(len(digits)):
126 for i in range(len(digits)):
125 ts = base + digits[:i]
127 ts = base + digits[:i]
126 parsed = jsonutil.parse_date(ts)
128 parsed = jsonutil.parse_date(ts)
127 if i >= 1 and i <= 6:
129 if i >= 1 and i <= 6:
128 assert isinstance(parsed, datetime.datetime)
130 assert isinstance(parsed, datetime.datetime)
129 else:
131 else:
130 assert isinstance(parsed, str)
132 assert isinstance(parsed, str)
131
133
132 def test_date_default():
134 def test_date_default():
133 data = dict(today=datetime.datetime.now(), utcnow=tz.utcnow())
135 data = dict(today=datetime.datetime.now(), utcnow=tz.utcnow())
134 jsondata = json.dumps(data, default=jsonutil.date_default)
136 jsondata = json.dumps(data, default=jsonutil.date_default)
135 nt.assert_in("+00", jsondata)
137 nt.assert_in("+00", jsondata)
136 nt.assert_equal(jsondata.count("+00"), 1)
138 nt.assert_equal(jsondata.count("+00"), 1)
137 extracted = jsonutil.extract_dates(json.loads(jsondata))
139 extracted = jsonutil.extract_dates(json.loads(jsondata))
138 for dt in extracted.values():
140 for dt in extracted.values():
139 nt.assert_true(isinstance(dt, datetime.datetime))
141 nt.assert_true(isinstance(dt, datetime.datetime))
140
142
141 def test_exception():
143 def test_exception():
142 bad_dicts = [{1:'number', '1':'string'},
144 bad_dicts = [{1:'number', '1':'string'},
143 {True:'bool', 'True':'string'},
145 {True:'bool', 'True':'string'},
144 ]
146 ]
145 for d in bad_dicts:
147 for d in bad_dicts:
146 nt.assert_raises(ValueError, json_clean, d)
148 nt.assert_raises(ValueError, json_clean, d)
147
149
@@ -1,131 +1,131 b''
1 # load with: . ipython-completion.bash
1 # load with: . ipython-completion.bash
2
2
3 if [[ -n ${ZSH_VERSION-} ]]; then
3 if [[ -n ${ZSH_VERSION-} ]]; then
4 autoload -Uz bashcompinit && bashcompinit
4 autoload -Uz bashcompinit && bashcompinit
5 fi
5 fi
6
6
7 _ipython_get_flags()
7 _ipython_get_flags()
8 {
8 {
9 local url=$1
9 local url=$1
10 local var=$2
10 local var=$2
11 local dash=$3
11 local dash=$3
12 if [[ "$url $var" == $__ipython_complete_last ]]; then
12 if [[ "$url $var" == $__ipython_complete_last ]]; then
13 opts=$__ipython_complete_last_res
13 opts=$__ipython_complete_last_res
14 return
14 return
15 fi
15 fi
16 # pylab and profile don't need the = and the
16 # matplotlib and profile don't need the = and the
17 # version without simplifies the special cased completion
17 # version without simplifies the special cased completion
18 opts=$(ipython ${url} --help-all | grep -E "^-{1,2}[^-]" | sed -e "s/<.*//" -e "s/[^=]$/& /" -e "s/^--pylab=$//" -e "s/^--profile=$/--profile /")
18 opts=$(ipython ${url} --help-all | grep -E "^-{1,2}[^-]" | sed -e "s/<.*//" -e "s/[^=]$/& /" -e "s/^--matplotlib=$//" -e "s/^--profile=$/--profile /")
19 __ipython_complete_last="$url $var"
19 __ipython_complete_last="$url $var"
20 __ipython_complete_last_res="$opts"
20 __ipython_complete_last_res="$opts"
21 }
21 }
22
22
23 _ipython()
23 _ipython()
24 {
24 {
25 local cur=${COMP_WORDS[COMP_CWORD]}
25 local cur=${COMP_WORDS[COMP_CWORD]}
26 local prev=${COMP_WORDS[COMP_CWORD - 1]}
26 local prev=${COMP_WORDS[COMP_CWORD - 1]}
27 local subcommands="notebook qtconsole console kernel profile locate history nbconvert "
27 local subcommands="notebook qtconsole console kernel profile locate history nbconvert "
28 local opts=""
28 local opts=""
29 if [ -z "$__ipython_complete_baseopts" ]; then
29 if [ -z "$__ipython_complete_baseopts" ]; then
30 _ipython_get_flags baseopts
30 _ipython_get_flags baseopts
31 __ipython_complete_baseopts="${opts}"
31 __ipython_complete_baseopts="${opts}"
32 fi
32 fi
33 local baseopts="$__ipython_complete_baseopts"
33 local baseopts="$__ipython_complete_baseopts"
34 local mode=""
34 local mode=""
35 for i in "${COMP_WORDS[@]}"; do
35 for i in "${COMP_WORDS[@]}"; do
36 [ "$cur" = "$i" ] && break
36 [ "$cur" = "$i" ] && break
37 if [[ ${subcommands} == *${i}* ]]; then
37 if [[ ${subcommands} == *${i}* ]]; then
38 mode="$i"
38 mode="$i"
39 break
39 break
40 elif [[ ${i} == "--"* ]]; then
40 elif [[ ${i} == "--"* ]]; then
41 mode="nosubcommand"
41 mode="nosubcommand"
42 break
42 break
43 fi
43 fi
44 done
44 done
45
45
46
46
47 if [[ ${cur} == -* ]]; then
47 if [[ ${cur} == -* ]]; then
48 case $mode in
48 case $mode in
49 "notebook" | "qtconsole" | "console" | "kernel" | "nbconvert")
49 "notebook" | "qtconsole" | "console" | "kernel" | "nbconvert")
50 _ipython_get_flags $mode
50 _ipython_get_flags $mode
51 opts=$"${opts} ${baseopts}"
51 opts=$"${opts} ${baseopts}"
52 ;;
52 ;;
53 "locate" | "profile")
53 "locate" | "profile")
54 _ipython_get_flags $mode
54 _ipython_get_flags $mode
55 ;;
55 ;;
56 "history")
56 "history")
57 if [[ $COMP_CWORD -ge 3 ]]; then
57 if [[ $COMP_CWORD -ge 3 ]]; then
58 # 'history trim' and 'history clear' covered by next line
58 # 'history trim' and 'history clear' covered by next line
59 _ipython_get_flags history\ "${COMP_WORDS[2]}"
59 _ipython_get_flags history\ "${COMP_WORDS[2]}"
60 else
60 else
61 _ipython_get_flags $mode
61 _ipython_get_flags $mode
62
62
63 fi
63 fi
64 opts=$"${opts}"
64 opts=$"${opts}"
65 ;;
65 ;;
66 *)
66 *)
67 opts=$baseopts
67 opts=$baseopts
68 esac
68 esac
69 # don't drop the trailing space
69 # don't drop the trailing space
70 local IFS=$'\t\n'
70 local IFS=$'\t\n'
71 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
71 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
72 return 0
72 return 0
73 elif [[ $mode == "profile" ]]; then
73 elif [[ $mode == "profile" ]]; then
74 opts="list create locate "
74 opts="list create locate "
75 local IFS=$'\t\n'
75 local IFS=$'\t\n'
76 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
76 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
77 elif [[ $mode == "history" ]]; then
77 elif [[ $mode == "history" ]]; then
78 if [[ $COMP_CWORD -ge 3 ]]; then
78 if [[ $COMP_CWORD -ge 3 ]]; then
79 # drop into flags
79 # drop into flags
80 opts="--"
80 opts="--"
81 else
81 else
82 opts="trim clear "
82 opts="trim clear "
83 fi
83 fi
84 local IFS=$'\t\n'
84 local IFS=$'\t\n'
85 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
85 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
86 elif [[ $mode == "locate" ]]; then
86 elif [[ $mode == "locate" ]]; then
87 opts="profile"
87 opts="profile"
88 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
88 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
89 elif [[ ${prev} == "--pylab"* ]] || [[ ${prev} == "--gui"* ]]; then
89 elif [[ ${prev} == "--matplotlib"* ]] || [[ ${prev} == "--gui"* ]]; then
90 if [ -z "$__ipython_complete_pylab" ]; then
90 if [ -z "$__ipython_complete_matplotlib" ]; then
91 __ipython_complete_pylab=`cat <<EOF | python -
91 __ipython_complete_matplotlib=`cat <<EOF | python -
92 try:
92 try:
93 import IPython.core.shellapp as mod;
93 import IPython.core.shellapp as mod;
94 for k in mod.InteractiveShellApp.pylab.values:
94 for k in mod.InteractiveShellApp.matplotlib.values:
95 print "%s " % k
95 print "%s " % k
96 except:
96 except:
97 pass
97 pass
98 EOF
98 EOF
99 `
99 `
100 fi
100 fi
101 local IFS=$'\t\n'
101 local IFS=$'\t\n'
102 COMPREPLY=( $(compgen -W "${__ipython_complete_pylab}" -- ${cur}) )
102 COMPREPLY=( $(compgen -W "${__ipython_complete_matplotlib}" -- ${cur}) )
103 elif [[ ${prev} == "--profile"* ]]; then
103 elif [[ ${prev} == "--profile"* ]]; then
104 if [ -z "$__ipython_complete_profiles" ]; then
104 if [ -z "$__ipython_complete_profiles" ]; then
105 __ipython_complete_profiles=`cat <<EOF | python -
105 __ipython_complete_profiles=`cat <<EOF | python -
106 try:
106 try:
107 import IPython.core.profileapp
107 import IPython.core.profileapp
108 for k in IPython.core.profileapp.list_bundled_profiles():
108 for k in IPython.core.profileapp.list_bundled_profiles():
109 print "%s " % k
109 print "%s " % k
110 p = IPython.core.profileapp.ProfileList()
110 p = IPython.core.profileapp.ProfileList()
111 for k in IPython.core.profileapp.list_profiles_in(p.ipython_dir):
111 for k in IPython.core.profileapp.list_profiles_in(p.ipython_dir):
112 print "%s " % k
112 print "%s " % k
113 except:
113 except:
114 pass
114 pass
115 EOF
115 EOF
116 `
116 `
117 fi
117 fi
118 local IFS=$'\t\n'
118 local IFS=$'\t\n'
119 COMPREPLY=( $(compgen -W "${__ipython_complete_profiles}" -- ${cur}) )
119 COMPREPLY=( $(compgen -W "${__ipython_complete_profiles}" -- ${cur}) )
120 else
120 else
121 if [ "$COMP_CWORD" == 1 ]; then
121 if [ "$COMP_CWORD" == 1 ]; then
122 local IFS=$'\t\n'
122 local IFS=$'\t\n'
123 local sub=$(echo $subcommands | sed -e "s/ / \t/g")
123 local sub=$(echo $subcommands | sed -e "s/ / \t/g")
124 COMPREPLY=( $(compgen -W "${sub}" -- ${cur}) )
124 COMPREPLY=( $(compgen -W "${sub}" -- ${cur}) )
125 else
125 else
126 COMPREPLY=( $(compgen -f -- ${cur}) )
126 COMPREPLY=( $(compgen -f -- ${cur}) )
127 fi
127 fi
128 fi
128 fi
129
129
130 }
130 }
131 complete -o default -o nospace -F _ipython ipython
131 complete -o default -o nospace -F _ipython ipython
@@ -1,24 +1,24 b''
1 # If you want ipython to appear in a linux app launcher ("start menu"), install this by doing:
1 # If you want ipython to appear in a linux app launcher ("start menu"), install this by doing:
2 # sudo desktop-file-install ipython-qtconsole.desktop
2 # sudo desktop-file-install ipython-qtconsole.desktop
3
3
4 [Desktop Entry]
4 [Desktop Entry]
5 Comment=Enhanced interactive Python qtconsole
5 Comment=Enhanced interactive Python qtconsole
6 Exec=ipython qtconsole
6 Exec=ipython qtconsole
7 GenericName[en_US]=Python shell
7 GenericName[en_US]=Python shell
8 GenericName=Python shell
8 GenericName=Python shell
9 Icon=gnome-netstatus-idle
9 Icon=gnome-netstatus-idle
10 Name[en_US]=IPython Qt console
10 Name[en_US]=IPython Qt console
11 Name=IPython Qt console
11 Name=IPython Qt console
12 Categories=Development;Utility;
12 Categories=Development;Utility;
13 StartupNotify=false
13 StartupNotify=false
14 Terminal=false
14 Terminal=false
15 Type=Application
15 Type=Application
16 Actions=Pylab;Pylabinline;
16 Actions=Matplotlib;Matplotlibinline;
17
17
18 [Desktop Action Pylab]
18 [Desktop Action Matplotlib]
19 Name=Pylab
19 Name=Matplotlib
20 Exec=ipython qtconsole --pylab
20 Exec=ipython qtconsole --matplotlib
21
21
22 [Desktop Action Pylabinline]
22 [Desktop Action Matplotlibinline]
23 Name=Pylab (inline plots)
23 Name=Matplotlib (inline plots)
24 Exec=ipython qtconsole --pylab=inline
24 Exec=ipython qtconsole --matplotlib=inline
@@ -1,58 +1,55 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Imports
2 # Imports
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4
4
5 import sys
5 import sys
6
6
7 from IPython.lib.kernel import connect_qtconsole
7 from IPython.lib.kernel import connect_qtconsole
8 from IPython.kernel.zmq.kernelapp import IPKernelApp
8 from IPython.kernel.zmq.kernelapp import IPKernelApp
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Functions and classes
11 # Functions and classes
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 def pylab_kernel(gui):
13 def mpl_kernel(gui):
14 """Launch and return an IPython kernel with pylab support for the desired gui
14 """Launch and return an IPython kernel with matplotlib support for the desired gui
15 """
15 """
16 kernel = IPKernelApp.instance()
16 kernel = IPKernelApp.instance()
17 kernel.initialize(['python', '--pylab=%s' % gui,
17 kernel.initialize(['python', '--matplotlib=%s' % gui,
18 #'--log-level=10'
18 #'--log-level=10'
19 ])
19 ])
20 return kernel
20 return kernel
21
21
22
22
23 class InternalIPKernel(object):
23 class InternalIPKernel(object):
24
24
25 def init_ipkernel(self, backend):
25 def init_ipkernel(self, backend):
26 # Start IPython kernel with GUI event loop and pylab support
26 # Start IPython kernel with GUI event loop and mpl support
27 self.ipkernel = pylab_kernel(backend)
27 self.ipkernel = mpl_kernel(backend)
28 # To create and track active qt consoles
28 # To create and track active qt consoles
29 self.consoles = []
29 self.consoles = []
30
30
31 # This application will also act on the shell user namespace
31 # This application will also act on the shell user namespace
32 self.namespace = self.ipkernel.shell.user_ns
32 self.namespace = self.ipkernel.shell.user_ns
33 # Keys present at startup so we don't print the entire pylab/numpy
34 # namespace when the user clicks the 'namespace' button
35 self._init_keys = set(self.namespace.keys())
36
33
37 # Example: a variable that will be seen by the user in the shell, and
34 # Example: a variable that will be seen by the user in the shell, and
38 # that the GUI modifies (the 'Counter++' button increments it):
35 # that the GUI modifies (the 'Counter++' button increments it):
39 self.namespace['app_counter'] = 0
36 self.namespace['app_counter'] = 0
40 #self.namespace['ipkernel'] = self.ipkernel # dbg
37 #self.namespace['ipkernel'] = self.ipkernel # dbg
41
38
42 def print_namespace(self, evt=None):
39 def print_namespace(self, evt=None):
43 print("\n***Variables in User namespace***")
40 print("\n***Variables in User namespace***")
44 for k, v in self.namespace.items():
41 for k, v in self.namespace.items():
45 if k not in self._init_keys and not k.startswith('_'):
42 if not k.startswith('_'):
46 print('%s -> %r' % (k, v))
43 print('%s -> %r' % (k, v))
47 sys.stdout.flush()
44 sys.stdout.flush()
48
45
49 def new_qt_console(self, evt=None):
46 def new_qt_console(self, evt=None):
50 """start a new qtconsole connected to our kernel"""
47 """start a new qtconsole connected to our kernel"""
51 return connect_qtconsole(self.ipkernel.connection_file, profile=self.ipkernel.profile)
48 return connect_qtconsole(self.ipkernel.connection_file, profile=self.ipkernel.profile)
52
49
53 def count(self, evt=None):
50 def count(self, evt=None):
54 self.namespace['app_counter'] += 1
51 self.namespace['app_counter'] += 1
55
52
56 def cleanup_consoles(self, evt=None):
53 def cleanup_consoles(self, evt=None):
57 for c in self.consoles:
54 for c in self.consoles:
58 c.kill()
55 c.kill()
@@ -1,1443 +1,1443 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": ""
3 "name": ""
4 },
4 },
5 "nbformat": 3,
5 "nbformat": 3,
6 "nbformat_minor": 0,
6 "nbformat_minor": 0,
7 "worksheets": [
7 "worksheets": [
8 {
8 {
9 "cells": [
9 "cells": [
10 {
10 {
11 "cell_type": "heading",
11 "cell_type": "heading",
12 "level": 1,
12 "level": 1,
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "The cell magics in IPython"
15 "The cell magics in IPython"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "markdown",
19 "cell_type": "markdown",
20 "metadata": {},
20 "metadata": {},
21 "source": [
21 "source": [
22 "IPython has a system of commands we call 'magics' that provide effectively a mini command language that is orthogonal to the syntax of Python and is extensible by the user with new commands. Magics are meant to be typed interactively, so they use command-line conventions, such as using whitespace for separating arguments, dashes for options and other conventions typical of a command-line environment.\n",
22 "IPython has a system of commands we call 'magics' that provide effectively a mini command language that is orthogonal to the syntax of Python and is extensible by the user with new commands. Magics are meant to be typed interactively, so they use command-line conventions, such as using whitespace for separating arguments, dashes for options and other conventions typical of a command-line environment.\n",
23 "\n",
23 "\n",
24 "Magics come in two kinds:\n",
24 "Magics come in two kinds:\n",
25 "\n",
25 "\n",
26 "* Line magics: these are commands prepended by one `%` character and whose arguments only extend to the end of the current line.\n",
26 "* Line magics: these are commands prepended by one `%` character and whose arguments only extend to the end of the current line.\n",
27 "* Cell magics: these use *two* percent characters as a marker (`%%`), and they receive as argument *both* the current line where they are declared and the whole body of the cell. Note that cell magics can *only* be used as the first line in a cell, and as a general principle they can't be 'stacked' (i.e. you can only use one cell magic per cell). A few of them, because of how they operate, can be stacked, but that is something you will discover on a case by case basis.\n",
27 "* Cell magics: these use *two* percent characters as a marker (`%%`), and they receive as argument *both* the current line where they are declared and the whole body of the cell. Note that cell magics can *only* be used as the first line in a cell, and as a general principle they can't be 'stacked' (i.e. you can only use one cell magic per cell). A few of them, because of how they operate, can be stacked, but that is something you will discover on a case by case basis.\n",
28 "\n",
28 "\n",
29 "The `%lsmagic` magic is used to list all available magics, and it will show both line and cell magics currently defined:"
29 "The `%lsmagic` magic is used to list all available magics, and it will show both line and cell magics currently defined:"
30 ]
30 ]
31 },
31 },
32 {
32 {
33 "cell_type": "code",
33 "cell_type": "code",
34 "collapsed": false,
34 "collapsed": false,
35 "input": [
35 "input": [
36 "%lsmagic"
36 "%lsmagic"
37 ],
37 ],
38 "language": "python",
38 "language": "python",
39 "metadata": {},
39 "metadata": {},
40 "outputs": [
40 "outputs": [
41 {
41 {
42 "json": [
42 "json": [
43 "{\"cell\": {\"prun\": \"ExecutionMagics\", \"file\": \"Other\", \"!\": \"OSMagics\", \"capture\": \"ExecutionMagics\", \"timeit\": \"ExecutionMagics\", \"script\": \"ScriptMagics\", \"ruby\": \"Other\", \"system\": \"OSMagics\", \"perl\": \"Other\", \"HTML\": \"Other\", \"bash\": \"Other\", \"python\": \"Other\", \"SVG\": \"Other\", \"javascript\": \"DisplayMagics\", \"writefile\": \"OSMagics\", \"pypy\": \"Other\", \"python3\": \"Other\", \"latex\": \"DisplayMagics\", \"sx\": \"OSMagics\", \"svg\": \"DisplayMagics\", \"html\": \"DisplayMagics\", \"sh\": \"Other\", \"time\": \"ExecutionMagics\", \"debug\": \"ExecutionMagics\"}, \"line\": {\"psource\": \"NamespaceMagics\", \"logstart\": \"LoggingMagics\", \"popd\": \"OSMagics\", \"loadpy\": \"CodeMagics\", \"install_ext\": \"ExtensionMagics\", \"colors\": \"BasicMagics\", \"who_ls\": \"NamespaceMagics\", \"install_profiles\": \"DeprecatedMagics\", \"pprint\": \"BasicMagics\", \"save\": \"CodeMagics\", \"tb\": \"ExecutionMagics\", \"pylab\": \"PylabMagics\", \"killbgscripts\": \"ScriptMagics\", \"quickref\": \"BasicMagics\", \"magic\": \"BasicMagics\", \"dhist\": \"OSMagics\", \"edit\": \"KernelMagics\", \"logstop\": \"LoggingMagics\", \"gui\": \"BasicMagics\", \"alias_magic\": \"BasicMagics\", \"debug\": \"ExecutionMagics\", \"page\": \"BasicMagics\", \"logstate\": \"LoggingMagics\", \"ed\": \"Other\", \"pushd\": \"OSMagics\", \"timeit\": \"ExecutionMagics\", \"rehashx\": \"OSMagics\", \"hist\": \"Other\", \"qtconsole\": \"KernelMagics\", \"dirs\": \"OSMagics\", \"run\": \"ExecutionMagics\", \"reset_selective\": \"NamespaceMagics\", \"pinfo2\": \"NamespaceMagics\", \"matplotlib\": \"PylabMagics\", \"automagic\": \"AutoMagics\", \"doctest_mode\": \"KernelMagics\", \"logoff\": \"LoggingMagics\", \"reload_ext\": \"ExtensionMagics\", \"pdb\": \"ExecutionMagics\", \"load\": \"CodeMagics\", \"lsmagic\": \"BasicMagics\", \"autosave\": \"KernelMagics\", \"cd\": \"OSMagics\", \"pastebin\": \"CodeMagics\", \"prun\": \"ExecutionMagics\", \"autocall\": \"AutoMagics\", \"bookmark\": \"OSMagics\", \"connect_info\": \"KernelMagics\", \"system\": \"OSMagics\", \"whos\": \"NamespaceMagics\", \"toc\": \"TimerMagics\", \"unload_ext\": \"ExtensionMagics\", \"store\": \"StoreMagics\", \"more\": \"KernelMagics\", \"gist\": \"Other\", \"pdef\": \"NamespaceMagics\", \"precision\": \"BasicMagics\", \"pinfo\": \"NamespaceMagics\", \"pwd\": \"OSMagics\", \"psearch\": \"NamespaceMagics\", \"reset\": \"NamespaceMagics\", \"recall\": \"HistoryMagics\", \"xdel\": \"NamespaceMagics\", \"xmode\": \"BasicMagics\", \"rerun\": \"HistoryMagics\", \"logon\": \"LoggingMagics\", \"history\": \"HistoryMagics\", \"pycat\": \"OSMagics\", \"unalias\": \"OSMagics\", \"install_default_config\": \"DeprecatedMagics\", \"env\": \"OSMagics\", \"load_ext\": \"ExtensionMagics\", \"config\": \"ConfigMagics\", \"tic\": \"TimerMagics\", \"profile\": \"BasicMagics\", \"pfile\": \"NamespaceMagics\", \"less\": \"KernelMagics\", \"who\": \"NamespaceMagics\", \"notebook\": \"BasicMagics\", \"man\": \"KernelMagics\", \"sx\": \"OSMagics\", \"macro\": \"ExecutionMagics\", \"clear\": \"KernelMagics\", \"alias\": \"OSMagics\", \"time\": \"ExecutionMagics\", \"sc\": \"OSMagics\", \"rep\": \"Other\", \"pdoc\": \"NamespaceMagics\"}}"
43 "{\"cell\": {\"prun\": \"ExecutionMagics\", \"file\": \"Other\", \"!\": \"OSMagics\", \"capture\": \"ExecutionMagics\", \"timeit\": \"ExecutionMagics\", \"script\": \"ScriptMagics\", \"ruby\": \"Other\", \"system\": \"OSMagics\", \"perl\": \"Other\", \"HTML\": \"Other\", \"bash\": \"Other\", \"python\": \"Other\", \"SVG\": \"Other\", \"javascript\": \"DisplayMagics\", \"writefile\": \"OSMagics\", \"pypy\": \"Other\", \"python3\": \"Other\", \"latex\": \"DisplayMagics\", \"sx\": \"OSMagics\", \"svg\": \"DisplayMagics\", \"html\": \"DisplayMagics\", \"sh\": \"Other\", \"time\": \"ExecutionMagics\", \"debug\": \"ExecutionMagics\"}, \"line\": {\"psource\": \"NamespaceMagics\", \"logstart\": \"LoggingMagics\", \"popd\": \"OSMagics\", \"loadpy\": \"CodeMagics\", \"install_ext\": \"ExtensionMagics\", \"colors\": \"BasicMagics\", \"who_ls\": \"NamespaceMagics\", \"install_profiles\": \"DeprecatedMagics\", \"pprint\": \"BasicMagics\", \"save\": \"CodeMagics\", \"tb\": \"ExecutionMagics\", \"pylab\": \"PylabMagics\", \"killbgscripts\": \"ScriptMagics\", \"quickref\": \"BasicMagics\", \"magic\": \"BasicMagics\", \"dhist\": \"OSMagics\", \"edit\": \"KernelMagics\", \"logstop\": \"LoggingMagics\", \"gui\": \"BasicMagics\", \"alias_magic\": \"BasicMagics\", \"debug\": \"ExecutionMagics\", \"page\": \"BasicMagics\", \"logstate\": \"LoggingMagics\", \"ed\": \"Other\", \"pushd\": \"OSMagics\", \"timeit\": \"ExecutionMagics\", \"rehashx\": \"OSMagics\", \"hist\": \"Other\", \"qtconsole\": \"KernelMagics\", \"dirs\": \"OSMagics\", \"run\": \"ExecutionMagics\", \"reset_selective\": \"NamespaceMagics\", \"pinfo2\": \"NamespaceMagics\", \"matplotlib\": \"PylabMagics\", \"automagic\": \"AutoMagics\", \"doctest_mode\": \"KernelMagics\", \"logoff\": \"LoggingMagics\", \"reload_ext\": \"ExtensionMagics\", \"pdb\": \"ExecutionMagics\", \"load\": \"CodeMagics\", \"lsmagic\": \"BasicMagics\", \"autosave\": \"KernelMagics\", \"cd\": \"OSMagics\", \"pastebin\": \"CodeMagics\", \"prun\": \"ExecutionMagics\", \"autocall\": \"AutoMagics\", \"bookmark\": \"OSMagics\", \"connect_info\": \"KernelMagics\", \"system\": \"OSMagics\", \"whos\": \"NamespaceMagics\", \"toc\": \"TimerMagics\", \"unload_ext\": \"ExtensionMagics\", \"store\": \"StoreMagics\", \"more\": \"KernelMagics\", \"gist\": \"Other\", \"pdef\": \"NamespaceMagics\", \"precision\": \"BasicMagics\", \"pinfo\": \"NamespaceMagics\", \"pwd\": \"OSMagics\", \"psearch\": \"NamespaceMagics\", \"reset\": \"NamespaceMagics\", \"recall\": \"HistoryMagics\", \"xdel\": \"NamespaceMagics\", \"xmode\": \"BasicMagics\", \"rerun\": \"HistoryMagics\", \"logon\": \"LoggingMagics\", \"history\": \"HistoryMagics\", \"pycat\": \"OSMagics\", \"unalias\": \"OSMagics\", \"install_default_config\": \"DeprecatedMagics\", \"env\": \"OSMagics\", \"load_ext\": \"ExtensionMagics\", \"config\": \"ConfigMagics\", \"tic\": \"TimerMagics\", \"profile\": \"BasicMagics\", \"pfile\": \"NamespaceMagics\", \"less\": \"KernelMagics\", \"who\": \"NamespaceMagics\", \"notebook\": \"BasicMagics\", \"man\": \"KernelMagics\", \"sx\": \"OSMagics\", \"macro\": \"ExecutionMagics\", \"clear\": \"KernelMagics\", \"alias\": \"OSMagics\", \"time\": \"ExecutionMagics\", \"sc\": \"OSMagics\", \"rep\": \"Other\", \"pdoc\": \"NamespaceMagics\"}}"
44 ],
44 ],
45 "metadata": {},
45 "metadata": {},
46 "output_type": "pyout",
46 "output_type": "pyout",
47 "prompt_number": 1,
47 "prompt_number": 1,
48 "text": [
48 "text": [
49 "Available line magics:\n",
49 "Available line magics:\n",
50 "%alias %alias_magic %autocall %automagic %autosave %bookmark %cd %clear %colors %config %connect_info %debug %dhist %dirs %doctest_mode %ed %edit %env %gist %gui %hist %history %install_default_config %install_ext %install_profiles %killbgscripts %less %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %lsmagic %macro %magic %man %matplotlib %more %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %run %save %sc %store %sx %system %tb %tic %time %timeit %toc %unalias %unload_ext %who %who_ls %whos %xdel %xmode\n",
50 "%alias %alias_magic %autocall %automagic %autosave %bookmark %cd %clear %colors %config %connect_info %debug %dhist %dirs %doctest_mode %ed %edit %env %gist %gui %hist %history %install_default_config %install_ext %install_profiles %killbgscripts %less %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %lsmagic %macro %magic %man %matplotlib %more %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %run %save %sc %store %sx %system %tb %tic %time %timeit %toc %unalias %unload_ext %who %who_ls %whos %xdel %xmode\n",
51 "\n",
51 "\n",
52 "Available cell magics:\n",
52 "Available cell magics:\n",
53 "%%! %%HTML %%SVG %%bash %%capture %%debug %%file %%html %%javascript %%latex %%perl %%prun %%pypy %%python %%python3 %%ruby %%script %%sh %%svg %%sx %%system %%time %%timeit %%writefile\n",
53 "%%! %%HTML %%SVG %%bash %%capture %%debug %%file %%html %%javascript %%latex %%perl %%prun %%pypy %%python %%python3 %%ruby %%script %%sh %%svg %%sx %%system %%time %%timeit %%writefile\n",
54 "\n",
54 "\n",
55 "Automagic is ON, % prefix IS NOT needed for line magics."
55 "Automagic is ON, % prefix IS NOT needed for line magics."
56 ]
56 ]
57 }
57 }
58 ],
58 ],
59 "prompt_number": 1
59 "prompt_number": 1
60 },
60 },
61 {
61 {
62 "cell_type": "markdown",
62 "cell_type": "markdown",
63 "metadata": {},
63 "metadata": {},
64 "source": [
64 "source": [
65 "Since in the introductory section we already covered the most frequently used line magics, we will focus here on the cell magics, which offer a great amount of power.\n",
65 "Since in the introductory section we already covered the most frequently used line magics, we will focus here on the cell magics, which offer a great amount of power.\n",
66 "\n",
66 "\n",
67 "Let's load matplotlib and numpy so we can use numerics/plotting at will later on."
67 "Let's load matplotlib and numpy so we can use numerics/plotting at will later on."
68 ]
68 ]
69 },
69 },
70 {
70 {
71 "cell_type": "code",
71 "cell_type": "code",
72 "collapsed": false,
72 "collapsed": false,
73 "input": [
73 "input": [
74 "%matplotlib inline\n",
74 "%matplotlib inline\n",
75 "import numpy as np\n",
75 "import numpy as np\n",
76 "import matplotlib.pyplot as plt"
76 "import matplotlib.pyplot as plt"
77 ],
77 ],
78 "language": "python",
78 "language": "python",
79 "metadata": {},
79 "metadata": {},
80 "outputs": [],
80 "outputs": [],
81 "prompt_number": 2
81 "prompt_number": 2
82 },
82 },
83 {
83 {
84 "cell_type": "heading",
84 "cell_type": "heading",
85 "level": 2,
85 "level": 2,
86 "metadata": {},
86 "metadata": {},
87 "source": [
87 "source": [
88 "<!--====-->\n",
88 "<!--====-->\n",
89 "Some simple cell magics"
89 "Some simple cell magics"
90 ]
90 ]
91 },
91 },
92 {
92 {
93 "cell_type": "markdown",
93 "cell_type": "markdown",
94 "metadata": {},
94 "metadata": {},
95 "source": [
95 "source": [
96 "Timing the execution of code; the 'timeit' magic exists both in line and cell form:"
96 "Timing the execution of code; the 'timeit' magic exists both in line and cell form:"
97 ]
97 ]
98 },
98 },
99 {
99 {
100 "cell_type": "code",
100 "cell_type": "code",
101 "collapsed": false,
101 "collapsed": false,
102 "input": [
102 "input": [
103 "%timeit np.linalg.eigvals(np.random.rand(100,100))"
103 "%timeit np.linalg.eigvals(np.random.rand(100,100))"
104 ],
104 ],
105 "language": "python",
105 "language": "python",
106 "metadata": {},
106 "metadata": {},
107 "outputs": [
107 "outputs": [
108 {
108 {
109 "output_type": "stream",
109 "output_type": "stream",
110 "stream": "stdout",
110 "stream": "stdout",
111 "text": [
111 "text": [
112 "100 loops, best of 3: 6.05 ms per loop\n"
112 "100 loops, best of 3: 6.05 ms per loop\n"
113 ]
113 ]
114 }
114 }
115 ],
115 ],
116 "prompt_number": 3
116 "prompt_number": 3
117 },
117 },
118 {
118 {
119 "cell_type": "code",
119 "cell_type": "code",
120 "collapsed": false,
120 "collapsed": false,
121 "input": [
121 "input": [
122 "%%timeit a = np.random.rand(100, 100)\n",
122 "%%timeit a = np.random.rand(100, 100)\n",
123 "np.linalg.eigvals(a)"
123 "np.linalg.eigvals(a)"
124 ],
124 ],
125 "language": "python",
125 "language": "python",
126 "metadata": {},
126 "metadata": {},
127 "outputs": [
127 "outputs": [
128 {
128 {
129 "output_type": "stream",
129 "output_type": "stream",
130 "stream": "stdout",
130 "stream": "stdout",
131 "text": [
131 "text": [
132 "100 loops, best of 3: 6.07 ms per loop\n"
132 "100 loops, best of 3: 6.07 ms per loop\n"
133 ]
133 ]
134 }
134 }
135 ],
135 ],
136 "prompt_number": 4
136 "prompt_number": 4
137 },
137 },
138 {
138 {
139 "cell_type": "markdown",
139 "cell_type": "markdown",
140 "metadata": {},
140 "metadata": {},
141 "source": [
141 "source": [
142 "The `%%capture` magic can be used to capture the stdout/err of any block of python code, either to discard it (if it's noise to you) or to store it in a variable for later use:"
142 "The `%%capture` magic can be used to capture the stdout/err of any block of python code, either to discard it (if it's noise to you) or to store it in a variable for later use:"
143 ]
143 ]
144 },
144 },
145 {
145 {
146 "cell_type": "code",
146 "cell_type": "code",
147 "collapsed": false,
147 "collapsed": false,
148 "input": [
148 "input": [
149 "%%capture capt\n",
149 "%%capture capt\n",
150 "from __future__ import print_function\n",
150 "from __future__ import print_function\n",
151 "import sys\n",
151 "import sys\n",
152 "print('Hello stdout')\n",
152 "print('Hello stdout')\n",
153 "print('and stderr', file=sys.stderr)"
153 "print('and stderr', file=sys.stderr)"
154 ],
154 ],
155 "language": "python",
155 "language": "python",
156 "metadata": {},
156 "metadata": {},
157 "outputs": [],
157 "outputs": [],
158 "prompt_number": 5
158 "prompt_number": 5
159 },
159 },
160 {
160 {
161 "cell_type": "code",
161 "cell_type": "code",
162 "collapsed": false,
162 "collapsed": false,
163 "input": [
163 "input": [
164 "capt.stdout, capt.stderr"
164 "capt.stdout, capt.stderr"
165 ],
165 ],
166 "language": "python",
166 "language": "python",
167 "metadata": {},
167 "metadata": {},
168 "outputs": [
168 "outputs": [
169 {
169 {
170 "metadata": {},
170 "metadata": {},
171 "output_type": "pyout",
171 "output_type": "pyout",
172 "prompt_number": 6,
172 "prompt_number": 6,
173 "text": [
173 "text": [
174 "('Hello stdout\\n', 'and stderr\\n')"
174 "('Hello stdout\\n', 'and stderr\\n')"
175 ]
175 ]
176 }
176 }
177 ],
177 ],
178 "prompt_number": 6
178 "prompt_number": 6
179 },
179 },
180 {
180 {
181 "cell_type": "code",
181 "cell_type": "code",
182 "collapsed": false,
182 "collapsed": false,
183 "input": [
183 "input": [
184 "capt.show()"
184 "capt.show()"
185 ],
185 ],
186 "language": "python",
186 "language": "python",
187 "metadata": {},
187 "metadata": {},
188 "outputs": [
188 "outputs": [
189 {
189 {
190 "output_type": "stream",
190 "output_type": "stream",
191 "stream": "stdout",
191 "stream": "stdout",
192 "text": [
192 "text": [
193 "Hello stdout\n"
193 "Hello stdout\n"
194 ]
194 ]
195 },
195 },
196 {
196 {
197 "output_type": "stream",
197 "output_type": "stream",
198 "stream": "stderr",
198 "stream": "stderr",
199 "text": [
199 "text": [
200 "and stderr\n"
200 "and stderr\n"
201 ]
201 ]
202 }
202 }
203 ],
203 ],
204 "prompt_number": 7
204 "prompt_number": 7
205 },
205 },
206 {
206 {
207 "cell_type": "markdown",
207 "cell_type": "markdown",
208 "metadata": {},
208 "metadata": {},
209 "source": [
209 "source": [
210 "The `%%writefile` magic is a very useful tool that writes the cell contents as a named file:"
210 "The `%%writefile` magic is a very useful tool that writes the cell contents as a named file:"
211 ]
211 ]
212 },
212 },
213 {
213 {
214 "cell_type": "code",
214 "cell_type": "code",
215 "collapsed": false,
215 "collapsed": false,
216 "input": [
216 "input": [
217 "%%writefile foo.py\n",
217 "%%writefile foo.py\n",
218 "print('Hello world')"
218 "print('Hello world')"
219 ],
219 ],
220 "language": "python",
220 "language": "python",
221 "metadata": {},
221 "metadata": {},
222 "outputs": [
222 "outputs": [
223 {
223 {
224 "output_type": "stream",
224 "output_type": "stream",
225 "stream": "stdout",
225 "stream": "stdout",
226 "text": [
226 "text": [
227 "Writing foo.py\n"
227 "Writing foo.py\n"
228 ]
228 ]
229 }
229 }
230 ],
230 ],
231 "prompt_number": 8
231 "prompt_number": 8
232 },
232 },
233 {
233 {
234 "cell_type": "code",
234 "cell_type": "code",
235 "collapsed": false,
235 "collapsed": false,
236 "input": [
236 "input": [
237 "%run foo"
237 "%run foo"
238 ],
238 ],
239 "language": "python",
239 "language": "python",
240 "metadata": {},
240 "metadata": {},
241 "outputs": [
241 "outputs": [
242 {
242 {
243 "output_type": "stream",
243 "output_type": "stream",
244 "stream": "stdout",
244 "stream": "stdout",
245 "text": [
245 "text": [
246 "Hello world\n"
246 "Hello world\n"
247 ]
247 ]
248 }
248 }
249 ],
249 ],
250 "prompt_number": 9
250 "prompt_number": 9
251 },
251 },
252 {
252 {
253 "cell_type": "heading",
253 "cell_type": "heading",
254 "level": 2,
254 "level": 2,
255 "metadata": {},
255 "metadata": {},
256 "source": [
256 "source": [
257 "<!--====-->\n",
257 "<!--====-->\n",
258 "Magics for running code under other interpreters"
258 "Magics for running code under other interpreters"
259 ]
259 ]
260 },
260 },
261 {
261 {
262 "cell_type": "markdown",
262 "cell_type": "markdown",
263 "metadata": {},
263 "metadata": {},
264 "source": [
264 "source": [
265 "IPython has a `%%script` cell magic, which lets you run a cell in\n",
265 "IPython has a `%%script` cell magic, which lets you run a cell in\n",
266 "a subprocess of any interpreter on your system, such as: bash, ruby, perl, zsh, R, etc.\n",
266 "a subprocess of any interpreter on your system, such as: bash, ruby, perl, zsh, R, etc.\n",
267 "\n",
267 "\n",
268 "It can even be a script of your own, which expects input on stdin."
268 "It can even be a script of your own, which expects input on stdin."
269 ]
269 ]
270 },
270 },
271 {
271 {
272 "cell_type": "markdown",
272 "cell_type": "markdown",
273 "metadata": {},
273 "metadata": {},
274 "source": [
274 "source": [
275 "To use it, simply pass a path or shell command to the program you want to run on the `%%script` line,\n",
275 "To use it, simply pass a path or shell command to the program you want to run on the `%%script` line,\n",
276 "and the rest of the cell will be run by that script, and stdout/err from the subprocess are captured and displayed."
276 "and the rest of the cell will be run by that script, and stdout/err from the subprocess are captured and displayed."
277 ]
277 ]
278 },
278 },
279 {
279 {
280 "cell_type": "code",
280 "cell_type": "code",
281 "collapsed": false,
281 "collapsed": false,
282 "input": [
282 "input": [
283 "%%script python\n",
283 "%%script python\n",
284 "import sys\n",
284 "import sys\n",
285 "print 'hello from Python %s' % sys.version"
285 "print 'hello from Python %s' % sys.version"
286 ],
286 ],
287 "language": "python",
287 "language": "python",
288 "metadata": {},
288 "metadata": {},
289 "outputs": [
289 "outputs": [
290 {
290 {
291 "output_type": "stream",
291 "output_type": "stream",
292 "stream": "stdout",
292 "stream": "stdout",
293 "text": [
293 "text": [
294 "hello from Python 2.7.2 (default, Oct 11 2012, 20:14:37) \n",
294 "hello from Python 2.7.2 (default, Oct 11 2012, 20:14:37) \n",
295 "[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)]\n"
295 "[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)]\n"
296 ]
296 ]
297 }
297 }
298 ],
298 ],
299 "prompt_number": 10
299 "prompt_number": 10
300 },
300 },
301 {
301 {
302 "cell_type": "code",
302 "cell_type": "code",
303 "collapsed": false,
303 "collapsed": false,
304 "input": [
304 "input": [
305 "%%script python3\n",
305 "%%script python3\n",
306 "import sys\n",
306 "import sys\n",
307 "print('hello from Python: %s' % sys.version)"
307 "print('hello from Python: %s' % sys.version)"
308 ],
308 ],
309 "language": "python",
309 "language": "python",
310 "metadata": {},
310 "metadata": {},
311 "outputs": [
311 "outputs": [
312 {
312 {
313 "output_type": "stream",
313 "output_type": "stream",
314 "stream": "stdout",
314 "stream": "stdout",
315 "text": [
315 "text": [
316 "hello from Python: 3.3.1 (v3.3.1:d9893d13c628, Apr 6 2013, 11:07:11) \n",
316 "hello from Python: 3.3.1 (v3.3.1:d9893d13c628, Apr 6 2013, 11:07:11) \n",
317 "[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n"
317 "[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n"
318 ]
318 ]
319 }
319 }
320 ],
320 ],
321 "prompt_number": 11
321 "prompt_number": 11
322 },
322 },
323 {
323 {
324 "cell_type": "markdown",
324 "cell_type": "markdown",
325 "metadata": {},
325 "metadata": {},
326 "source": [
326 "source": [
327 "IPython also creates aliases for a few common interpreters, such as bash, ruby, perl, etc.\n",
327 "IPython also creates aliases for a few common interpreters, such as bash, ruby, perl, etc.\n",
328 "\n",
328 "\n",
329 "These are all equivalent to `%%script <name>`"
329 "These are all equivalent to `%%script <name>`"
330 ]
330 ]
331 },
331 },
332 {
332 {
333 "cell_type": "code",
333 "cell_type": "code",
334 "collapsed": false,
334 "collapsed": false,
335 "input": [
335 "input": [
336 "%%ruby\n",
336 "%%ruby\n",
337 "puts \"Hello from Ruby #{RUBY_VERSION}\""
337 "puts \"Hello from Ruby #{RUBY_VERSION}\""
338 ],
338 ],
339 "language": "python",
339 "language": "python",
340 "metadata": {},
340 "metadata": {},
341 "outputs": [
341 "outputs": [
342 {
342 {
343 "output_type": "stream",
343 "output_type": "stream",
344 "stream": "stdout",
344 "stream": "stdout",
345 "text": [
345 "text": [
346 "Hello from Ruby 1.9.3\n"
346 "Hello from Ruby 1.9.3\n"
347 ]
347 ]
348 }
348 }
349 ],
349 ],
350 "prompt_number": 12
350 "prompt_number": 12
351 },
351 },
352 {
352 {
353 "cell_type": "code",
353 "cell_type": "code",
354 "collapsed": false,
354 "collapsed": false,
355 "input": [
355 "input": [
356 "%%bash\n",
356 "%%bash\n",
357 "echo \"hello from $BASH\""
357 "echo \"hello from $BASH\""
358 ],
358 ],
359 "language": "python",
359 "language": "python",
360 "metadata": {},
360 "metadata": {},
361 "outputs": [
361 "outputs": [
362 {
362 {
363 "output_type": "stream",
363 "output_type": "stream",
364 "stream": "stdout",
364 "stream": "stdout",
365 "text": [
365 "text": [
366 "hello from /usr/local/bin/bash\n"
366 "hello from /usr/local/bin/bash\n"
367 ]
367 ]
368 }
368 }
369 ],
369 ],
370 "prompt_number": 13
370 "prompt_number": 13
371 },
371 },
372 {
372 {
373 "cell_type": "heading",
373 "cell_type": "heading",
374 "level": 2,
374 "level": 2,
375 "metadata": {},
375 "metadata": {},
376 "source": [
376 "source": [
377 "Exercise: write your own script that numbers input lines"
377 "Exercise: write your own script that numbers input lines"
378 ]
378 ]
379 },
379 },
380 {
380 {
381 "cell_type": "markdown",
381 "cell_type": "markdown",
382 "metadata": {},
382 "metadata": {},
383 "source": [
383 "source": [
384 "Write a file, called `lnum.py`, such that the following cell works as shown (hint: don't forget about the executable bit!): "
384 "Write a file, called `lnum.py`, such that the following cell works as shown (hint: don't forget about the executable bit!): "
385 ]
385 ]
386 },
386 },
387 {
387 {
388 "cell_type": "code",
388 "cell_type": "code",
389 "collapsed": false,
389 "collapsed": false,
390 "input": [
390 "input": [
391 "%%script ./lnum.py\n",
391 "%%script ./lnum.py\n",
392 "my first line\n",
392 "my first line\n",
393 "my second\n",
393 "my second\n",
394 "more"
394 "more"
395 ],
395 ],
396 "language": "python",
396 "language": "python",
397 "metadata": {},
397 "metadata": {},
398 "outputs": [
398 "outputs": [
399 {
399 {
400 "output_type": "stream",
400 "output_type": "stream",
401 "stream": "stdout",
401 "stream": "stdout",
402 "text": [
402 "text": [
403 "0: my first line\n",
403 "0: my first line\n",
404 "1: my second\n",
404 "1: my second\n",
405 "2: more\n",
405 "2: more\n",
406 "---- END ----\n"
406 "---- END ----\n"
407 ]
407 ]
408 }
408 }
409 ],
409 ],
410 "prompt_number": 29
410 "prompt_number": 29
411 },
411 },
412 {
412 {
413 "cell_type": "heading",
413 "cell_type": "heading",
414 "level": 2,
414 "level": 2,
415 "metadata": {},
415 "metadata": {},
416 "source": [
416 "source": [
417 "Capturing output"
417 "Capturing output"
418 ]
418 ]
419 },
419 },
420 {
420 {
421 "cell_type": "markdown",
421 "cell_type": "markdown",
422 "metadata": {},
422 "metadata": {},
423 "source": [
423 "source": [
424 "You can also capture stdout/err from these subprocesses into Python variables, instead of letting them go directly to stdout/err"
424 "You can also capture stdout/err from these subprocesses into Python variables, instead of letting them go directly to stdout/err"
425 ]
425 ]
426 },
426 },
427 {
427 {
428 "cell_type": "code",
428 "cell_type": "code",
429 "collapsed": false,
429 "collapsed": false,
430 "input": [
430 "input": [
431 "%%bash\n",
431 "%%bash\n",
432 "echo \"hi, stdout\"\n",
432 "echo \"hi, stdout\"\n",
433 "echo \"hello, stderr\" >&2\n"
433 "echo \"hello, stderr\" >&2\n"
434 ],
434 ],
435 "language": "python",
435 "language": "python",
436 "metadata": {},
436 "metadata": {},
437 "outputs": [
437 "outputs": [
438 {
438 {
439 "output_type": "stream",
439 "output_type": "stream",
440 "stream": "stdout",
440 "stream": "stdout",
441 "text": [
441 "text": [
442 "hi, stdout\n"
442 "hi, stdout\n"
443 ]
443 ]
444 },
444 },
445 {
445 {
446 "output_type": "stream",
446 "output_type": "stream",
447 "stream": "stderr",
447 "stream": "stderr",
448 "text": [
448 "text": [
449 "hello, stderr\n"
449 "hello, stderr\n"
450 ]
450 ]
451 }
451 }
452 ],
452 ],
453 "prompt_number": 30
453 "prompt_number": 30
454 },
454 },
455 {
455 {
456 "cell_type": "code",
456 "cell_type": "code",
457 "collapsed": false,
457 "collapsed": false,
458 "input": [
458 "input": [
459 "%%bash --out output --err error\n",
459 "%%bash --out output --err error\n",
460 "echo \"hi, stdout\"\n",
460 "echo \"hi, stdout\"\n",
461 "echo \"hello, stderr\" >&2"
461 "echo \"hello, stderr\" >&2"
462 ],
462 ],
463 "language": "python",
463 "language": "python",
464 "metadata": {},
464 "metadata": {},
465 "outputs": [],
465 "outputs": [],
466 "prompt_number": 31
466 "prompt_number": 31
467 },
467 },
468 {
468 {
469 "cell_type": "code",
469 "cell_type": "code",
470 "collapsed": false,
470 "collapsed": false,
471 "input": [
471 "input": [
472 "print(error)\n",
472 "print(error)\n",
473 "print(output)"
473 "print(output)"
474 ],
474 ],
475 "language": "python",
475 "language": "python",
476 "metadata": {},
476 "metadata": {},
477 "outputs": [
477 "outputs": [
478 {
478 {
479 "output_type": "stream",
479 "output_type": "stream",
480 "stream": "stdout",
480 "stream": "stdout",
481 "text": [
481 "text": [
482 "hello, stderr\n",
482 "hello, stderr\n",
483 "\n",
483 "\n",
484 "hi, stdout\n",
484 "hi, stdout\n",
485 "\n"
485 "\n"
486 ]
486 ]
487 }
487 }
488 ],
488 ],
489 "prompt_number": 32
489 "prompt_number": 32
490 },
490 },
491 {
491 {
492 "cell_type": "heading",
492 "cell_type": "heading",
493 "level": 2,
493 "level": 2,
494 "metadata": {},
494 "metadata": {},
495 "source": [
495 "source": [
496 "Background Scripts"
496 "Background Scripts"
497 ]
497 ]
498 },
498 },
499 {
499 {
500 "cell_type": "markdown",
500 "cell_type": "markdown",
501 "metadata": {},
501 "metadata": {},
502 "source": [
502 "source": [
503 "These scripts can be run in the background, by adding the `--bg` flag.\n",
503 "These scripts can be run in the background, by adding the `--bg` flag.\n",
504 "\n",
504 "\n",
505 "When you do this, output is discarded unless you use the `--out/err`\n",
505 "When you do this, output is discarded unless you use the `--out/err`\n",
506 "flags to store output as above."
506 "flags to store output as above."
507 ]
507 ]
508 },
508 },
509 {
509 {
510 "cell_type": "code",
510 "cell_type": "code",
511 "collapsed": false,
511 "collapsed": false,
512 "input": [
512 "input": [
513 "%%ruby --bg --out ruby_lines\n",
513 "%%ruby --bg --out ruby_lines\n",
514 "for n in 1...10\n",
514 "for n in 1...10\n",
515 " sleep 1\n",
515 " sleep 1\n",
516 " puts \"line #{n}\"\n",
516 " puts \"line #{n}\"\n",
517 " STDOUT.flush\n",
517 " STDOUT.flush\n",
518 "end"
518 "end"
519 ],
519 ],
520 "language": "python",
520 "language": "python",
521 "metadata": {},
521 "metadata": {},
522 "outputs": [
522 "outputs": [
523 {
523 {
524 "output_type": "stream",
524 "output_type": "stream",
525 "stream": "stdout",
525 "stream": "stdout",
526 "text": [
526 "text": [
527 "Starting job # 0 in a separate thread.\n"
527 "Starting job # 0 in a separate thread.\n"
528 ]
528 ]
529 }
529 }
530 ],
530 ],
531 "prompt_number": 33
531 "prompt_number": 33
532 },
532 },
533 {
533 {
534 "cell_type": "markdown",
534 "cell_type": "markdown",
535 "metadata": {},
535 "metadata": {},
536 "source": [
536 "source": [
537 "When you do store output of a background thread, these are the stdout/err *pipes*,\n",
537 "When you do store output of a background thread, these are the stdout/err *pipes*,\n",
538 "rather than the text of the output."
538 "rather than the text of the output."
539 ]
539 ]
540 },
540 },
541 {
541 {
542 "cell_type": "code",
542 "cell_type": "code",
543 "collapsed": false,
543 "collapsed": false,
544 "input": [
544 "input": [
545 "ruby_lines"
545 "ruby_lines"
546 ],
546 ],
547 "language": "python",
547 "language": "python",
548 "metadata": {},
548 "metadata": {},
549 "outputs": [
549 "outputs": [
550 {
550 {
551 "metadata": {},
551 "metadata": {},
552 "output_type": "pyout",
552 "output_type": "pyout",
553 "prompt_number": 34,
553 "prompt_number": 34,
554 "text": [
554 "text": [
555 "<open file '<fdopen>', mode 'rb' at 0x112cd55d0>"
555 "<open file '<fdopen>', mode 'rb' at 0x112cd55d0>"
556 ]
556 ]
557 }
557 }
558 ],
558 ],
559 "prompt_number": 34
559 "prompt_number": 34
560 },
560 },
561 {
561 {
562 "cell_type": "code",
562 "cell_type": "code",
563 "collapsed": false,
563 "collapsed": false,
564 "input": [
564 "input": [
565 "print(ruby_lines.read())"
565 "print(ruby_lines.read())"
566 ],
566 ],
567 "language": "python",
567 "language": "python",
568 "metadata": {},
568 "metadata": {},
569 "outputs": [
569 "outputs": [
570 {
570 {
571 "output_type": "stream",
571 "output_type": "stream",
572 "stream": "stdout",
572 "stream": "stdout",
573 "text": [
573 "text": [
574 "line 1\n",
574 "line 1\n",
575 "line 2\n",
575 "line 2\n",
576 "line 3\n",
576 "line 3\n",
577 "line 4\n",
577 "line 4\n",
578 "line 5\n",
578 "line 5\n",
579 "line 6\n",
579 "line 6\n",
580 "line 7\n",
580 "line 7\n",
581 "line 8\n",
581 "line 8\n",
582 "line 9\n",
582 "line 9\n",
583 "\n"
583 "\n"
584 ]
584 ]
585 }
585 }
586 ],
586 ],
587 "prompt_number": 35
587 "prompt_number": 35
588 },
588 },
589 {
589 {
590 "cell_type": "heading",
590 "cell_type": "heading",
591 "level": 1,
591 "level": 1,
592 "metadata": {},
592 "metadata": {},
593 "source": [
593 "source": [
594 "Cython Magic Functions Extension"
594 "Cython Magic Functions Extension"
595 ]
595 ]
596 },
596 },
597 {
597 {
598 "cell_type": "heading",
598 "cell_type": "heading",
599 "level": 2,
599 "level": 2,
600 "metadata": {},
600 "metadata": {},
601 "source": [
601 "source": [
602 "Loading the extension"
602 "Loading the extension"
603 ]
603 ]
604 },
604 },
605 {
605 {
606 "cell_type": "markdown",
606 "cell_type": "markdown",
607 "metadata": {},
607 "metadata": {},
608 "source": [
608 "source": [
609 "IPtyhon has a `cythonmagic` extension that contains a number of magic functions for working with Cython code. This extension can be loaded using the `%load_ext` magic as follows:"
609 "IPtyhon has a `cythonmagic` extension that contains a number of magic functions for working with Cython code. This extension can be loaded using the `%load_ext` magic as follows:"
610 ]
610 ]
611 },
611 },
612 {
612 {
613 "cell_type": "code",
613 "cell_type": "code",
614 "collapsed": false,
614 "collapsed": false,
615 "input": [
615 "input": [
616 "%load_ext cythonmagic"
616 "%load_ext cythonmagic"
617 ],
617 ],
618 "language": "python",
618 "language": "python",
619 "metadata": {},
619 "metadata": {},
620 "outputs": [],
620 "outputs": [],
621 "prompt_number": 1
621 "prompt_number": 1
622 },
622 },
623 {
623 {
624 "cell_type": "markdown",
624 "cell_type": "markdown",
625 "metadata": {},
625 "metadata": {},
626 "source": [
626 "source": [
627 "The `%%cython_pyximport` magic allows you to enter arbitrary Cython code into a cell. That Cython code is written as a `.pyx` file in the current working directory and then imported using `pyximport`. You have the specify the name of the module that the Code will appear in. All symbols from the module are imported automatically by the magic function."
627 "The `%%cython_pyximport` magic allows you to enter arbitrary Cython code into a cell. That Cython code is written as a `.pyx` file in the current working directory and then imported using `pyximport`. You have the specify the name of the module that the Code will appear in. All symbols from the module are imported automatically by the magic function."
628 ]
628 ]
629 },
629 },
630 {
630 {
631 "cell_type": "code",
631 "cell_type": "code",
632 "collapsed": false,
632 "collapsed": false,
633 "input": [
633 "input": [
634 "%%cython_pyximport foo\n",
634 "%%cython_pyximport foo\n",
635 "def f(x):\n",
635 "def f(x):\n",
636 " return 4.0*x"
636 " return 4.0*x"
637 ],
637 ],
638 "language": "python",
638 "language": "python",
639 "metadata": {},
639 "metadata": {},
640 "outputs": [],
640 "outputs": [],
641 "prompt_number": 4
641 "prompt_number": 4
642 },
642 },
643 {
643 {
644 "cell_type": "code",
644 "cell_type": "code",
645 "collapsed": false,
645 "collapsed": false,
646 "input": [
646 "input": [
647 "f(10)"
647 "f(10)"
648 ],
648 ],
649 "language": "python",
649 "language": "python",
650 "metadata": {},
650 "metadata": {},
651 "outputs": [
651 "outputs": [
652 {
652 {
653 "metadata": {},
653 "metadata": {},
654 "output_type": "pyout",
654 "output_type": "pyout",
655 "prompt_number": 6,
655 "prompt_number": 6,
656 "text": [
656 "text": [
657 "40.0"
657 "40.0"
658 ]
658 ]
659 }
659 }
660 ],
660 ],
661 "prompt_number": 6
661 "prompt_number": 6
662 },
662 },
663 {
663 {
664 "cell_type": "heading",
664 "cell_type": "heading",
665 "level": 2,
665 "level": 2,
666 "metadata": {},
666 "metadata": {},
667 "source": [
667 "source": [
668 "The %cython magic"
668 "The %cython magic"
669 ]
669 ]
670 },
670 },
671 {
671 {
672 "cell_type": "markdown",
672 "cell_type": "markdown",
673 "metadata": {},
673 "metadata": {},
674 "source": [
674 "source": [
675 "Probably the most important magic is the `%cython` magic. This is similar to the `%%cython_pyximport` magic, but doesn't require you to specify a module name. Instead, the `%%cython` magic manages everything using temporary files in the `~/.cython/magic` directory. All of the symbols in the Cython module are imported automatically by the magic.\n",
675 "Probably the most important magic is the `%cython` magic. This is similar to the `%%cython_pyximport` magic, but doesn't require you to specify a module name. Instead, the `%%cython` magic manages everything using temporary files in the `~/.cython/magic` directory. All of the symbols in the Cython module are imported automatically by the magic.\n",
676 "\n",
676 "\n",
677 "Here is a simple example of a Black-Scholes options pricing algorithm written in Cython:"
677 "Here is a simple example of a Black-Scholes options pricing algorithm written in Cython:"
678 ]
678 ]
679 },
679 },
680 {
680 {
681 "cell_type": "code",
681 "cell_type": "code",
682 "collapsed": false,
682 "collapsed": false,
683 "input": [
683 "input": [
684 "%%cython\n",
684 "%%cython\n",
685 "cimport cython\n",
685 "cimport cython\n",
686 "from libc.math cimport exp, sqrt, pow, log, erf\n",
686 "from libc.math cimport exp, sqrt, pow, log, erf\n",
687 "\n",
687 "\n",
688 "@cython.cdivision(True)\n",
688 "@cython.cdivision(True)\n",
689 "cdef double std_norm_cdf(double x) nogil:\n",
689 "cdef double std_norm_cdf(double x) nogil:\n",
690 " return 0.5*(1+erf(x/sqrt(2.0)))\n",
690 " return 0.5*(1+erf(x/sqrt(2.0)))\n",
691 "\n",
691 "\n",
692 "@cython.cdivision(True)\n",
692 "@cython.cdivision(True)\n",
693 "def black_scholes(double s, double k, double t, double v,\n",
693 "def black_scholes(double s, double k, double t, double v,\n",
694 " double rf, double div, double cp):\n",
694 " double rf, double div, double cp):\n",
695 " \"\"\"Price an option using the Black-Scholes model.\n",
695 " \"\"\"Price an option using the Black-Scholes model.\n",
696 " \n",
696 " \n",
697 " s : initial stock price\n",
697 " s : initial stock price\n",
698 " k : strike price\n",
698 " k : strike price\n",
699 " t : expiration time\n",
699 " t : expiration time\n",
700 " v : volatility\n",
700 " v : volatility\n",
701 " rf : risk-free rate\n",
701 " rf : risk-free rate\n",
702 " div : dividend\n",
702 " div : dividend\n",
703 " cp : +1/-1 for call/put\n",
703 " cp : +1/-1 for call/put\n",
704 " \"\"\"\n",
704 " \"\"\"\n",
705 " cdef double d1, d2, optprice\n",
705 " cdef double d1, d2, optprice\n",
706 " with nogil:\n",
706 " with nogil:\n",
707 " d1 = (log(s/k)+(rf-div+0.5*pow(v,2))*t)/(v*sqrt(t))\n",
707 " d1 = (log(s/k)+(rf-div+0.5*pow(v,2))*t)/(v*sqrt(t))\n",
708 " d2 = d1 - v*sqrt(t)\n",
708 " d2 = d1 - v*sqrt(t)\n",
709 " optprice = cp*s*exp(-div*t)*std_norm_cdf(cp*d1) - \\\n",
709 " optprice = cp*s*exp(-div*t)*std_norm_cdf(cp*d1) - \\\n",
710 " cp*k*exp(-rf*t)*std_norm_cdf(cp*d2)\n",
710 " cp*k*exp(-rf*t)*std_norm_cdf(cp*d2)\n",
711 " return optprice"
711 " return optprice"
712 ],
712 ],
713 "language": "python",
713 "language": "python",
714 "metadata": {},
714 "metadata": {},
715 "outputs": [],
715 "outputs": [],
716 "prompt_number": 7
716 "prompt_number": 7
717 },
717 },
718 {
718 {
719 "cell_type": "code",
719 "cell_type": "code",
720 "collapsed": false,
720 "collapsed": false,
721 "input": [
721 "input": [
722 "black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)"
722 "black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)"
723 ],
723 ],
724 "language": "python",
724 "language": "python",
725 "metadata": {},
725 "metadata": {},
726 "outputs": [
726 "outputs": [
727 {
727 {
728 "metadata": {},
728 "metadata": {},
729 "output_type": "pyout",
729 "output_type": "pyout",
730 "prompt_number": 8,
730 "prompt_number": 8,
731 "text": [
731 "text": [
732 "10.327861752731728"
732 "10.327861752731728"
733 ]
733 ]
734 }
734 }
735 ],
735 ],
736 "prompt_number": 8
736 "prompt_number": 8
737 },
737 },
738 {
738 {
739 "cell_type": "code",
739 "cell_type": "code",
740 "collapsed": false,
740 "collapsed": false,
741 "input": [
741 "input": [
742 "%timeit black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)"
742 "%timeit black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)"
743 ],
743 ],
744 "language": "python",
744 "language": "python",
745 "metadata": {},
745 "metadata": {},
746 "outputs": [
746 "outputs": [
747 {
747 {
748 "output_type": "stream",
748 "output_type": "stream",
749 "stream": "stdout",
749 "stream": "stdout",
750 "text": [
750 "text": [
751 "1000000 loops, best of 3: 366 ns per loop\n"
751 "1000000 loops, best of 3: 366 ns per loop\n"
752 ]
752 ]
753 }
753 }
754 ],
754 ],
755 "prompt_number": 9
755 "prompt_number": 9
756 },
756 },
757 {
757 {
758 "cell_type": "markdown",
758 "cell_type": "markdown",
759 "metadata": {},
759 "metadata": {},
760 "source": [
760 "source": [
761 "Cython allows you to specify additional libraries to be linked with your extension, you can do so with the `-l` flag (also spelled `--lib`). Note that this flag can be passed more than once to specify multiple libraries, such as `-lm -llib2 --lib lib3`. Here's a simple example of how to access the system math library:"
761 "Cython allows you to specify additional libraries to be linked with your extension, you can do so with the `-l` flag (also spelled `--lib`). Note that this flag can be passed more than once to specify multiple libraries, such as `-lm -llib2 --lib lib3`. Here's a simple example of how to access the system math library:"
762 ]
762 ]
763 },
763 },
764 {
764 {
765 "cell_type": "code",
765 "cell_type": "code",
766 "collapsed": false,
766 "collapsed": false,
767 "input": [
767 "input": [
768 "%%cython -lm\n",
768 "%%cython -lm\n",
769 "from libc.math cimport sin\n",
769 "from libc.math cimport sin\n",
770 "print 'sin(1)=', sin(1)"
770 "print 'sin(1)=', sin(1)"
771 ],
771 ],
772 "language": "python",
772 "language": "python",
773 "metadata": {},
773 "metadata": {},
774 "outputs": [
774 "outputs": [
775 {
775 {
776 "output_type": "stream",
776 "output_type": "stream",
777 "stream": "stdout",
777 "stream": "stdout",
778 "text": [
778 "text": [
779 "sin(1)= 0.841470984808\n"
779 "sin(1)= 0.841470984808\n"
780 ]
780 ]
781 }
781 }
782 ],
782 ],
783 "prompt_number": 10
783 "prompt_number": 10
784 },
784 },
785 {
785 {
786 "cell_type": "markdown",
786 "cell_type": "markdown",
787 "metadata": {},
787 "metadata": {},
788 "source": [
788 "source": [
789 "You can similarly use the `-I/--include` flag to add include directories to the search path, and `-c/--compile-args` to add extra flags that are passed to Cython via the `extra_compile_args` of the distutils `Extension` class. Please see [the Cython docs on C library usage](http://docs.cython.org/src/tutorial/clibraries.html) for more details on the use of these flags."
789 "You can similarly use the `-I/--include` flag to add include directories to the search path, and `-c/--compile-args` to add extra flags that are passed to Cython via the `extra_compile_args` of the distutils `Extension` class. Please see [the Cython docs on C library usage](http://docs.cython.org/src/tutorial/clibraries.html) for more details on the use of these flags."
790 ]
790 ]
791 },
791 },
792 {
792 {
793 "cell_type": "heading",
793 "cell_type": "heading",
794 "level": 1,
794 "level": 1,
795 "metadata": {},
795 "metadata": {},
796 "source": [
796 "source": [
797 "Rmagic Functions Extension"
797 "Rmagic Functions Extension"
798 ]
798 ]
799 },
799 },
800 {
800 {
801 "cell_type": "markdown",
801 "cell_type": "markdown",
802 "metadata": {},
802 "metadata": {},
803 "source": [
803 "source": [
804 "IPython has an `rmagic` extension that contains a some magic functions for working with R via rpy2. This extension can be loaded using the `%load_ext` magic as follows:"
804 "IPython has an `rmagic` extension that contains a some magic functions for working with R via rpy2. This extension can be loaded using the `%load_ext` magic as follows:"
805 ]
805 ]
806 },
806 },
807 {
807 {
808 "cell_type": "code",
808 "cell_type": "code",
809 "collapsed": true,
809 "collapsed": true,
810 "input": [
810 "input": [
811 "%load_ext rmagic"
811 "%load_ext rmagic"
812 ],
812 ],
813 "language": "python",
813 "language": "python",
814 "metadata": {},
814 "metadata": {},
815 "outputs": [],
815 "outputs": [],
816 "prompt_number": 1
816 "prompt_number": 1
817 },
817 },
818 {
818 {
819 "cell_type": "markdown",
819 "cell_type": "markdown",
820 "metadata": {},
820 "metadata": {},
821 "source": [
821 "source": [
822 "A typical use case one imagines is having some numpy arrays, wanting to compute some statistics of interest on these\n",
822 "A typical use case one imagines is having some numpy arrays, wanting to compute some statistics of interest on these\n",
823 " arrays and return the result back to python. Let's suppose we just want to fit a simple linear model to a scatterplot."
823 " arrays and return the result back to python. Let's suppose we just want to fit a simple linear model to a scatterplot."
824 ]
824 ]
825 },
825 },
826 {
826 {
827 "cell_type": "code",
827 "cell_type": "code",
828 "collapsed": false,
828 "collapsed": false,
829 "input": [
829 "input": [
830 "%matplotlib inline\n",
830 "%matplotlib inline\n",
831 "import numpy as np\n",
831 "import numpy as np\n",
832 "import matplotlib.pyplot as plt"
832 "import matplotlib.pyplot as plt"
833 ],
833 ],
834 "language": "python",
834 "language": "python",
835 "metadata": {},
835 "metadata": {},
836 "outputs": [],
836 "outputs": [],
837 "prompt_number": 2
837 "prompt_number": 2
838 },
838 },
839 {
839 {
840 "cell_type": "code",
840 "cell_type": "code",
841 "collapsed": false,
841 "collapsed": false,
842 "input": [
842 "input": [
843 "X = np.array([0,1,2,3,4])\n",
843 "X = np.array([0,1,2,3,4])\n",
844 "Y = np.array([3,5,4,6,7])\n",
844 "Y = np.array([3,5,4,6,7])\n",
845 "plt.scatter(X, Y)"
845 "plt.scatter(X, Y)"
846 ],
846 ],
847 "language": "python",
847 "language": "python",
848 "metadata": {},
848 "metadata": {},
849 "outputs": [
849 "outputs": [
850 {
850 {
851 "metadata": {},
851 "metadata": {},
852 "output_type": "pyout",
852 "output_type": "pyout",
853 "prompt_number": 3,
853 "prompt_number": 3,
854 "text": [
854 "text": [
855 "<matplotlib.collections.PathCollection at 0x112ab1f90>"
855 "<matplotlib.collections.PathCollection at 0x112ab1f90>"
856 ]
856 ]
857 },
857 },
858 {
858 {
859 "metadata": {},
859 "metadata": {},
860 "output_type": "display_data",
860 "output_type": "display_data",
861 "png": "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\nH7s1AAAAAElFTkSuQmCC\n",
861 "png": "iVBORw0KGgoAAAANSUhEUgAAAkoAAAF9CAYAAAD7tEcRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEYFJREFUeJzt3V1slQcdx/H/OX0JAqULuK3uLYspUAqSUWi3MLoEiWQ6\nXMLdkGwsMXMaMxIvNm+IFXGyZPECo9udGZHohReG93mxadyicbMvTqEyRzY6NidZprRYQUrrhdps\nuj+nKuc8Xfv53MDTPWy/PEvgy3OenlOamJiYCAAA/kO56AEAANOVUAIASAglAICEUAIASAglAICE\nUAIASAglAIBE/VRO2rt3b7zyyitRLpfj2muvjc997nNRXz+lXwoA8IFV8Y7S6OhovPzyy7Fr167Y\nuXNn/OUvf4kzZ87UYhsAQKEq3haaO3durF27Nh588MFoaGiINWvWxHXXXVeLbQAAhap4R+ntt9+O\nX/3qV7Fnz5741re+FcPDw3H8+PFabAMAKFTFO0q///3vY9WqVTFnzpyIiFi3bl0cO3Ys2tvb33Pe\nM888U52FAABVsGHDhornVAylG264IX7605/Gpk2bolwux69//etYtmzZ+57b0dHx36/kf3bw4MH4\n9Kc/XfSMWcU1rz3XvPZc89pzzWuvr69vSudVDKUbb7wxVq9eHV/5yleiVCrFsmXL4rbbbvu/BwIA\nTHdT+h7/jRs3xsaNG6u9BQBgWvGGkwAACaEEAJAQSh9gS5YsKXrCrOOa155rXnuuee255tOXUPoA\nW7p0adETZh3XvPZc89pzzWvPNZ++hBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAk\nhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIA\nQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIo\nAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAk\n6iudMDAwEPv37588Pn36dDz88MOxZMmSqg4DAChaxVC65ZZb4pZbbomIiAsXLsTXv/71WLx4cdWH\nAcBM97e/RfT21sVvf1sXK1ZcitWrL0VjY9GreLeKofRuhw8fjk984hNRKpWqtQcAZo3+/rrYtKkp\nJiZKUS5PxJEjI9HVdanoWbzLlJ9RGh0djd7e3uju7q7mHgCYNU6fLsfExD9uPoyPl+L0aY8OTzdT\n/j9y+PDhuPPOO91NAoArZPHi8Zg3byIiIubPn4jW1vGCF/HvpvTS27lz56K/vz8effTRau8BgFlj\n5cpL8fTTw/H66+W48cbxWL5cKE03UwqlgwcPxqc+9Sl3kwDgClu+XCBNZ1MKpS1btlR7BwDAtOOp\nMQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCA\nhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFAC\nAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgI\nJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAxJRC6cyZM/HN\nb34zxsfHq70HAGDaqK90wvj4eBw6dCi++MUvRrnsBhTATPb226X4059KsXDhRCxaNFH0HChcxfLZ\nv39/nDp1Kvbs2RM/+clParEJgAKcOlWObdvmxa23Nse2bfNiaKhU9CQo3GXvKJ05cyaGhoaip6cn\nIiK+/e1vx7XXXhvt7e01GQdA7fT318UvftEQERE//3lD9PfXx003XSx4FRTrsneU+vr6orOzM8rl\ncpTL5Vi3bl0cP368VtsAqKE5cyYuewyz0WVDqampKV566aXJ4/7+/rjpppuqPgqA2lu9+lI8/PBf\nY8mSS/HlL/81Vq++VPQkKNxlX3pbu3ZtnDx5Mnbs2BGlUilWrFgRXV1dtdoGQA1dffVEPPLI+fjC\nF85HU1NEXV3Ri6B4lw2lUqkU9913X622AFCwurqIq64qegVMH77fHwAgIZQAABJCCQAgIZQAABJC\nCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAg\nIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQA\nABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJC\nCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABL1Uzlp+/btsWjRosnjhx56KBYuXFi1\nUQAA08GUQmnevHnR09NT7S0wbZ0/H/HLX9bHiy/WR2fnWNx661jMmVP0KgCqbUqhdPHixdi1a1eM\njIzExz/+8bjzzjurvQumlb6+uti8eX5ElKJUmojDh0fittsuFT0LgCqbUijt3r07Ghoa4uLFi/HY\nY49FW1tb3HzzzVWeBtPHH/5QjohSRERMTJTizTfLESGUAGa6KT3M3dDQMPljZ2dnnDp1qqqjYLpZ\nuvRSLFgwHhERzc3jsXSpSAKYDSqG0unTp+PQoUMRETE2Nhb9/f3R2tpa9WEwnaxYMR5PPz0SP/zh\nSBw9OhLLl48XPQmAGqj40ltLS0u88cYbsWPHjiiXy7Fx48a4/vrra7ENppW2tvFoaxNIALNJxVCq\nr6+PBx98sBZbAACmFW84CQCQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoA\nAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmh\nBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQ\nEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoA\nAAmhBACQmFIoXbhwIXp6euJ73/tetfcAAEwbUwqlffv2xfr166u9BeA93nqrFMeOleOtt0pFTwFm\nqYqhdPTo0Vi1alVcc801tdgDEBERr75ajnvumR/d3c2xdev8eO01TwoAtXfZ33kGBwdjeHg4Ojo6\nYmJiolabAGJgoC5eeqk+IiL6++tjYKCu4EXAbFR/uX84MDAQQ0ND8fjjj8fIyEicPXs2mpub4+67\n767VPmCWmj9/4rLHALVw2VDasmXL5M+PHz8evb29IgmoidWrx+KrXx2N/fsbY/Pmv0VHx1jRk4BZ\n6LKh9O9KJQ9UArWxcGHE9u0X4oEHLsSHPlT0GmC2mnIotbe3R3t7ezW3APwHkQQUybeRAAAkhBIA\nQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIo\nAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAk\nhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIA\nQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQKJ+Kift3bs3Tpw4\nEQ0NDdHV1RV33XVXtXcBABSuYiidP38+li9fHtu2bYuIiJ07d0Z3d3csWLCg6uN4f6OjEc8/Xx8/\n+1l93HHHWKxbNxZz5xa9CgBmnoqhNGfOnFizZk1ERIyOjk5+jeL09dXFPffMj4hSPPHERBw8OBK3\n336p6FkAMONM6aW3iIinnnoqnnvuudi6dWs0NjZWcxMV/PGP5Ygo/fOo9M9joQQAV9qUH+a+//77\n48knn4ze3t547bXXqjiJSpYtuxSLFo1HRMSHPzwey5aJJACohop3lE6ePBnvvPNOdHZ2RmNjYzQ3\nN8fw8HAttpFobx+Po0dH4s03S3HddRPR2jpe9CQAmJEqhlJLS0scOHAgDh06FBERS5cujZUrV1Z9\nGJfX2joera1FrwCAma1iKM2bNy++9KUv1WILAMC04g0nAQASQgkAICGUAAASQgkAICGUAAASQgkA\nICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGU\nAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAAS\nQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkA\nICGUAAASQgkAICGUAAASQukD7MSJE0VPmHVc89pzzWvPNa8913z6EkofYC+//HLRE2Yd17z2XPPa\nc81rzzWfvuqnctKRI0fi+eefj/r6+vjIRz4SDzzwQNTXT+mXAgB8YFW8o3Tu3LkYGhqKRx99NL72\nta9FU1NTvPDCC7XYBgBQqIq3hebPnx+f//znJ48vXLgQV199dVVHAQBMB//VM0o/+tGPYu7cubF4\n8eJq7QEAmDZKExMTE5VOGh8fj+9+97vR0tISmzZtet9znnnmmSs+DgCgWjZs2FDxnIqhdP78+fjO\nd74T3d3d0dXVdcXGAQBMdxVD6ciRI3Hw4MFoaWmZ/Nr69evjjjvuqPo4AIAiTemlNwCA2cgbTgIA\nJIQSAEBCKAEAJIQSAECiKh/Y1t/fH0888UT09PTEDTfcUI3/xKx34MCBePHFFyMioqOjIzZv3lzw\noplvbGwsvv/978fg4GDs3r276Dmzgs+ZrL29e/fGiRMnoqGhIbq6uuKuu+4qetKscOHChfjGN74R\nra2tce+99xY9Z8bbvn17LFq0aPL4oYceioULF77vuVf8d5zf/e530dfXFytXrgzfUFcdg4OD8eqr\nr8auXbsiIuLJJ5+M3/zmN/Gxj32s4GUz2w9+8INYsWJFDA4OFj1lVnj350yWSqXYt29fvPDCC7F2\n7dqip81Y58+fj+XLl8e2bdsiImLnzp3R3d0dCxYsKHjZzLdv375Yv359vP7660VPmRXmzZsXPT09\nUzr3ir/01tbWFp/97Gejrq7uSv+r+af+/v73vJvohg0boq+vr8BFs8O9994bHR0dRc+YNf71OZOl\nUikifM5kLcyZMyfWrFkTERGjo6OTX6O6jh49GqtWrYprrrmm6CmzxsWLF2PXrl3xyCOPxNNPP33Z\nc/+nO0p//vOfY8+ePf/xdW9EWRsjIyPR1NQ0ebxgwYI4e/ZsgYugunzOZG099dRT8dxzz8XWrVuj\nsbGx6Dkz2uDgYAwPD8cnP/nJOHbsWNFzZo3du3dHQ0NDXLx4MR577LFoa2uLm2+++X3P/Z9C6aqr\nrpryLSuuvKamphgeHp48Hh4edmucGendnzPpObzauf/+++Mzn/lM7NmzJz760Y+mf4Dw/xsYGIih\noaF4/PHHY2RkJM6ePRvNzc1x9913Fz1tRmtoaJj8sbOzM06dOnVlQ4lidXR0xI9//OPJZ5KeffbZ\nuP322wteBVeWz5msvZMnT8Y777wTnZ2d0djYGM3Nze/5SxlX3pYtWyZ/fvz48ejt7RVJVXb69OkY\nGBiITZs2xdjYWPT398d9992Xnl/VUPrXswVcWW1tbXHixInYsWNHRPwjnDzIzUzz7LPPxiuvvBLn\nzp2Lo0ePRoSX96utpaUlDhw4EIcOHYqIiKVLl8bKlSsLXjW7+HOz+lpaWuKNN96IHTt2RLlcjo0b\nN8b111+fnu+z3gAAEt5wEgAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJ/B42SRiUf\nH7s1AAAAAElFTkSuQmCC\n",
862 "text": [
862 "text": [
863 "<matplotlib.figure.Figure at 0x112a87c50>"
863 "<matplotlib.figure.Figure at 0x112a87c50>"
864 ]
864 ]
865 }
865 }
866 ],
866 ],
867 "prompt_number": 3
867 "prompt_number": 3
868 },
868 },
869 {
869 {
870 "cell_type": "markdown",
870 "cell_type": "markdown",
871 "metadata": {},
871 "metadata": {},
872 "source": [
872 "source": [
873 "We can accomplish this by first pushing variables to R, fitting a model and returning the results. The line magic %Rpush copies its arguments to variables of the same name in rpy2. The %R line magic evaluates the string in rpy2 and returns the results. In this case, the coefficients of a linear model."
873 "We can accomplish this by first pushing variables to R, fitting a model and returning the results. The line magic %Rpush copies its arguments to variables of the same name in rpy2. The %R line magic evaluates the string in rpy2 and returns the results. In this case, the coefficients of a linear model."
874 ]
874 ]
875 },
875 },
876 {
876 {
877 "cell_type": "code",
877 "cell_type": "code",
878 "collapsed": false,
878 "collapsed": false,
879 "input": [
879 "input": [
880 "%Rpush X Y\n",
880 "%Rpush X Y\n",
881 "%R lm(Y~X)$coef"
881 "%R lm(Y~X)$coef"
882 ],
882 ],
883 "language": "python",
883 "language": "python",
884 "metadata": {},
884 "metadata": {},
885 "outputs": [
885 "outputs": [
886 {
886 {
887 "metadata": {},
887 "metadata": {},
888 "output_type": "pyout",
888 "output_type": "pyout",
889 "prompt_number": 4,
889 "prompt_number": 4,
890 "text": [
890 "text": [
891 "array([ 3.2, 0.9])"
891 "array([ 3.2, 0.9])"
892 ]
892 ]
893 }
893 }
894 ],
894 ],
895 "prompt_number": 4
895 "prompt_number": 4
896 },
896 },
897 {
897 {
898 "cell_type": "markdown",
898 "cell_type": "markdown",
899 "metadata": {},
899 "metadata": {},
900 "source": [
900 "source": [
901 "It is also possible to return more than one value with %R."
901 "It is also possible to return more than one value with %R."
902 ]
902 ]
903 },
903 },
904 {
904 {
905 "cell_type": "code",
905 "cell_type": "code",
906 "collapsed": false,
906 "collapsed": false,
907 "input": [
907 "input": [
908 "%R resid(lm(Y~X)); coef(lm(X~Y))"
908 "%R resid(lm(Y~X)); coef(lm(X~Y))"
909 ],
909 ],
910 "language": "python",
910 "language": "python",
911 "metadata": {},
911 "metadata": {},
912 "outputs": [
912 "outputs": [
913 {
913 {
914 "metadata": {},
914 "metadata": {},
915 "output_type": "pyout",
915 "output_type": "pyout",
916 "prompt_number": 5,
916 "prompt_number": 5,
917 "text": [
917 "text": [
918 "array([-2.5, 0.9])"
918 "array([-2.5, 0.9])"
919 ]
919 ]
920 }
920 }
921 ],
921 ],
922 "prompt_number": 5
922 "prompt_number": 5
923 },
923 },
924 {
924 {
925 "cell_type": "markdown",
925 "cell_type": "markdown",
926 "metadata": {},
926 "metadata": {},
927 "source": [
927 "source": [
928 "One can also easily capture the results of %R into python objects. Like R, the return value of this multiline expression (multiline in the sense that it is separated by ';') is the final value, which is \n",
928 "One can also easily capture the results of %R into python objects. Like R, the return value of this multiline expression (multiline in the sense that it is separated by ';') is the final value, which is \n",
929 "the *coef(lm(X~Y))*."
929 "the *coef(lm(X~Y))*."
930 ]
930 ]
931 },
931 },
932 {
932 {
933 "cell_type": "markdown",
933 "cell_type": "markdown",
934 "metadata": {},
934 "metadata": {},
935 "source": [
935 "source": [
936 "To pull other variables from R, there are two more line magics, %Rpull and %Rget. Both are useful after some R code has been executed and there are variables\n",
936 "To pull other variables from R, there are two more line magics, %Rpull and %Rget. Both are useful after some R code has been executed and there are variables\n",
937 "in the rpy2 namespace that one would like to retrieve. The main difference is that one\n",
937 "in the rpy2 namespace that one would like to retrieve. The main difference is that one\n",
938 " returns the value (%Rget), while the other pulls it to self.shell.user_ns (%Rpull). Imagine we've stored the results\n",
938 " returns the value (%Rget), while the other pulls it to self.shell.user_ns (%Rpull). Imagine we've stored the results\n",
939 "of some calculation in the variable \"a\" in rpy2's namespace. By using the %R magic, we can obtain these results and\n",
939 "of some calculation in the variable \"a\" in rpy2's namespace. By using the %R magic, we can obtain these results and\n",
940 "store them in b. We can also pull them directly to user_ns with %Rpull. They are both views on the same data."
940 "store them in b. We can also pull them directly to user_ns with %Rpull. They are both views on the same data."
941 ]
941 ]
942 },
942 },
943 {
943 {
944 "cell_type": "code",
944 "cell_type": "code",
945 "collapsed": false,
945 "collapsed": false,
946 "input": [
946 "input": [
947 "b = %R a=resid(lm(Y~X))\n",
947 "b = %R a=resid(lm(Y~X))\n",
948 "%Rpull a\n",
948 "%Rpull a\n",
949 "print(a)\n",
949 "print(a)\n",
950 "assert id(b.data) == id(a.data)\n",
950 "assert id(b.data) == id(a.data)\n",
951 "%R -o a"
951 "%R -o a"
952 ],
952 ],
953 "language": "python",
953 "language": "python",
954 "metadata": {},
954 "metadata": {},
955 "outputs": [
955 "outputs": [
956 {
956 {
957 "output_type": "stream",
957 "output_type": "stream",
958 "stream": "stdout",
958 "stream": "stdout",
959 "text": [
959 "text": [
960 "[-0.2 0.9 -1. 0.1 0.2]\n"
960 "[-0.2 0.9 -1. 0.1 0.2]\n"
961 ]
961 ]
962 }
962 }
963 ],
963 ],
964 "prompt_number": 6
964 "prompt_number": 6
965 },
965 },
966 {
966 {
967 "cell_type": "heading",
967 "cell_type": "heading",
968 "level": 2,
968 "level": 2,
969 "metadata": {},
969 "metadata": {},
970 "source": [
970 "source": [
971 "Plotting and capturing output"
971 "Plotting and capturing output"
972 ]
972 ]
973 },
973 },
974 {
974 {
975 "cell_type": "markdown",
975 "cell_type": "markdown",
976 "metadata": {},
976 "metadata": {},
977 "source": [
977 "source": [
978 "R's console (i.e. its stdout() connection) is captured by ipython, as are any plots which are published as PNG files like the notebook with arguments --pylab inline. As a call to %R may produce a return value (see above) we must ask what happens to a magic like the one below. The R code specifies that something is published to the notebook. If anything is published to the notebook, that call to %R returns None."
978 "R's console (i.e. its stdout() connection) is captured by ipython, as are any plots which are published as PNG files like `%matplotlib inline`. As a call to %R may produce a return value (see above) we must ask what happens to a magic like the one below. The R code specifies that something is published to the notebook. If anything is published to the notebook, that call to %R returns None."
979 ]
979 ]
980 },
980 },
981 {
981 {
982 "cell_type": "code",
982 "cell_type": "code",
983 "collapsed": false,
983 "collapsed": false,
984 "input": [
984 "input": [
985 "from __future__ import print_function\n",
985 "from __future__ import print_function\n",
986 "v1 = %R plot(X,Y); print(summary(lm(Y~X))); vv=mean(X)*mean(Y)\n",
986 "v1 = %R plot(X,Y); print(summary(lm(Y~X))); vv=mean(X)*mean(Y)\n",
987 "print('v1 is:', v1)\n",
987 "print('v1 is:', v1)\n",
988 "v2 = %R mean(X)*mean(Y)\n",
988 "v2 = %R mean(X)*mean(Y)\n",
989 "print('v2 is:', v2)"
989 "print('v2 is:', v2)"
990 ],
990 ],
991 "language": "python",
991 "language": "python",
992 "metadata": {},
992 "metadata": {},
993 "outputs": [
993 "outputs": [
994 {
994 {
995 "metadata": {},
995 "metadata": {},
996 "output_type": "display_data",
996 "output_type": "display_data",
997 "text": [
997 "text": [
998 "\n",
998 "\n",
999 "Call:\n",
999 "Call:\n",
1000 "lm(formula = Y ~ X)\n",
1000 "lm(formula = Y ~ X)\n",
1001 "\n",
1001 "\n",
1002 "Residuals:\n",
1002 "Residuals:\n",
1003 " 1 2 3 4 5 \n",
1003 " 1 2 3 4 5 \n",
1004 "-0.2 0.9 -1.0 0.1 0.2 \n",
1004 "-0.2 0.9 -1.0 0.1 0.2 \n",
1005 "\n",
1005 "\n",
1006 "Coefficients:\n",
1006 "Coefficients:\n",
1007 " Estimate Std. Error t value Pr(>|t|) \n",
1007 " Estimate Std. Error t value Pr(>|t|) \n",
1008 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
1008 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
1009 "X 0.9000 0.2517 3.576 0.0374 *\n",
1009 "X 0.9000 0.2517 3.576 0.0374 *\n",
1010 "---\n",
1010 "---\n",
1011 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1\n",
1011 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1\n",
1012 "\n",
1012 "\n",
1013 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
1013 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
1014 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
1014 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
1015 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739\n",
1015 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739\n",
1016 "\n"
1016 "\n"
1017 ]
1017 ]
1018 },
1018 },
1019 {
1019 {
1020 "metadata": {},
1020 "metadata": {},
1021 "output_type": "display_data",
1021 "output_type": "display_data",
1022 "png": "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\nISCAy1C3JgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gICOPtDAAABAgQIlCEggMtQtyYB\nAgQIZC8ggLM/BAAQIECAQBkCArgMdWsSIECAQPYCAjj7QwAAAQIECJQhIIDLULcmAQIECGQvIICz\nPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4+0MAAAECBAiUISCAy1C3JgECBAhkLyCAsz8EABAgQIBA\nGQICuAx1axIgQIBA9gICOPtDAAABAgQIlCEggMtQtyYBAgQIZC8ggLM/BAAQIECAQBkCArgMdWsS\nIECAQPYCAjj7QwAAAQIECJQhIIDLULcmAQIECGQvIICzPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4\n+0MAAAECBAiUISCAy1C3JgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gICOPtDAAABAgQI\nlCEggMtQtyYBAgQIZC8ggLM/BAAQIECAQBkCArgMdWsSIECAQPYCAjj7QwAAAQIECJQhIIDLULcm\nAQIECGQvIICzPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4+0MAAAECBAiUISCAy1C3JgECBAhkLyCA\nsz8EABAgQIBAGQICuAx1axIgQIBA9gICOPtDAAABAgQIlCEggMtQtyYBAgQIZC8ggLM/BAAQIECA\nQBkCArgMdWsSIECAQPYCAjj7QwAAAQIECJQhIIDLULcmAQIECGQvIICzPwQAECBAgEAZAgK4DHVr\nEiBAgED2AgI4+0MAAAECBAiUISCAy1C3JgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gIC\nOPtDAAABAgQIlCEggMtQtyYBAgQIZC8ggLM/BAAQIECAQBkCArgMdWsSIECAQPYCAjj7QwAAAQIE\nCJQhIIDLULcmAQIECGQvIICzPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4+0MAAAECBAiUISCAy1C3\nJgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gIdshdYD8DDDz8cr732WmyzzTbRv3//9dzb\nzQQIECBAoHkCyb4CXrlyZSxevLh5XbTSvU455ZS46667omPHjnHllVfG8ccfH6tWrWql1eyWAAEC\nBHISSCKAly9fHldccUUMGTIknn322bjtttuiR48escUWW8Rxxx0X7777bpvPZNKkSfHiiy/GTTfd\nFIMHD45f/epXsfnmm8fPf/7zNq/FggQIECDQeAJJnII+//zz46WXXop99tknTjzxxOjQoUNMnjw5\nevXqFSNHjowpU6bUtq+Pf+LEiXH33XfXvdvzzz9f21/dG+tsfO655+Kaa65pcsvw4cPj9ttvb7LN\nFQIECBAgsCECSQTwQw89FDNmzKi9wuzcuXP8+9//jsMOO6zWz5gxY+Liiy9uVgAXp4i/8pWv1HW4\n8847Y8mSJXVvq7exeLU7e/bsOOSQQ9bc/Mc//rFW45oNviFAgAABAhsokEQA77zzzjFr1qzYf//9\n49RTT41//OMfa9qZOXNm9O7de831dX3TqVOnKL7qXYpALd5Xbu5l2LBhMXDgwOjZs2etrmnTpsXp\np58eCxcubO4u3I8AAQIECKxVIIkAHjVqVBx99NHxk5/8pPbfbbfdtlbwRRddFLfccks8+uija22g\ntW7o3r177dR3cXp8woQJUVyfN29edO3atbWWtF8CBAgQyEggiQA+8sgja6d7P3iKuDidXJx+3mST\nTUoZyVZbbRU333xzKWtblAABAgQaWyCJAC6Ii1PExdf7LwcddND7r/qeAAECBAg0jEASv4bUMJoa\nIUCAAAECzRQQwM2EcjcCBAgQINCSAgK4JTXtiwABAgQINFNAADcTyt0IECBAgEBLCgjgltS0LwIE\nCBAg0EwBAdxMKHcjQIAAAQItKSCAW1LTvggQIECAQDMF2r33v0sz71vpuxV/XGHAgAGx9957f+Q+\nHn/88bX+E5cfeWcesFaBZcuWRbt27Wp//nGtd3JDiwgU/+jNpptu2iL7spO1CyxdurR2PLdv337t\nd3LLRgusjrGDDz74I+9r7ty5MXXq1Nhuu+0+8mM39gHZBPDGQPXt2zeeeOKJjdmFxzZDYOzYsbU/\nQ1n8G9wurSvgmG5d39V7v/DCC2v/vO6BBx64epP/toJA8Qd8RowYUbm/VucUdCscDHZJgAABAgTW\nJyCA1yfkdgIECBAg0AoCArgVUO2SAAECBAisT0AAr0/I7QQIECBAoBUEBHAroNolAQIECBBYn4AA\nXp+Q2wkQIECAQCsI+DWkZqD+61//im222aYZ93SXjRFYvHhxFL8v6fdTN0axeY91TDfPaWPv9eab\nb9aO50984hMbuyuPX4fAqlWr4o033oju3buv417p3SSA05uJiggQIEAgAwGnoDMYshYJECBAID0B\nAZzeTFREgAABAhkICOAMhqxFAgQIEEhPQACnNxMVESBAgEAGAgI4gyFrkQABAgTSExDA6c1ERQQI\nECCQgYAAzmDIWiRAgACB9AQEcHozybqi5cuXZ92/5gkQyEdAAK9j1k888UQccsghsdNOO8Wxxx4b\nb7311jru7aaNFZg0aVIcdNBBG7sbj1+HQGF8+OGHR58+fWLw4MHx0ksvrePebtpQgTlz5tR+Zuy5\n556x//77xzPPPLOhu/K4ZgqcdtppMXz48GbeO427CeC1zKH4Z81OOumkuP7666P4P1MRwueee+5a\n7m3zxggUT2zOOuusOPvss+O9997bmF157DoE5s+fHyNHjowihP/0pz/FEUccEeecc846HuGmDRUY\nOnRoHH/88TFz5swYM2ZMDBw4cEN35XHNEHjwwQdj8uTJzbhnWncRwGuZx4wZM2KPPfaIvfbaKzp2\n7BgjRoyIu+++ey33tnljBB577LHYZJNN4mc/+9nG7MZj1yNQ/Hu5d9xxR/To0aN2z+JV8NNPP72e\nR7l5QwSmTJkSgwYNqj10xYoVUXy5tI7AggULak9yip/RVbsI4LVMbN68eU3+AEPxQ2vRokXx7rvv\nruURNm+oQPHq4Morr4zOnTtv6C48rhkC2267bRx66KFr7nnjjTfGgAED1lz3TcsJbL311tGuXbva\nGYbi1Oh1113Xcju3pyYCZ5xxRlx66aXRpUuXJturcEUAr2VKxbOq9/9VntXh8J///Gctj7CZQHUE\nxo0bF/fff39cddVV1Sm6YpUWT9aLv87Tq1evuO2222LZsmUV6yD9cn/xi1/Unrj369cv/WLrVCiA\n66AUm7p16xbFn8dbfXn77bejU6dOseWWW67e5L8EKilwww03xMUXXxyPPvpoLRwq2UQFii7+BOFF\nF10UTz31VDz++OO1/1ag7MqUWLxIKj7DUHyo8IEHHqh9oPDVV1+N6dOnV6YHAbyWURXPWl955ZU1\ntxbfb7/99muu+4ZAFQWK99mL03VF+BafcXBpeYGlS5fGBRdcsObtqg4dOsRuu+0Wf/nLX1p+sYz3\nuHDhwujdu3cUTygvv/zyKD5L8txzz8XEiRMroyKA1zKq4lnV3Llza0MtTiVdffXV8dWvfnUt97aZ\nQPoCf/vb3+LMM8+snQ4t3g8u/lh88eXSsgLFmbI//OEPMX78+NqOiw90/v73v4/Pf/7zLbtQ5nvb\nZZddah8iLD5IWHwVv0lx9NFH135zpSo0HapSaFvXWZw+Kj44ccwxx0TXrl1rz2DHjh3b1mVYj0CL\nCRS/UrdkyZLo27dvk30W24pPobu0nMAVV1wRo0aNimuuuab282PChAnx6U9/uuUWsKeGEGj3v9+7\n9IuX6xhl8esDxfu/3vtdB5KbCBCoK1D85kTxBN6FQD0BAVxPxTYCBAgQINDKAt4DbmVguydAgAAB\nAvUEBHA9FdsIECBAgEArCwjgVga2ewIECBAgUE9AANdTsY0AAQIECLSygABuZWC7J0CAAAEC9QQE\ncD0V2wgQIECAQCsLCOBWBrZ7AgQIECBQT0AA11OxjQABAgQItLKAAG5lYLsnQIAAAQL1BARwPRXb\nCBAgQIBAKwsI4FYGtnsCBAgQIFBPQADXU7GNAAECBAi0soAAbmVguydAgAABAvUEBHA9FdsIECBA\ngEArCwjgVga2ewIECBAgUE9AANdTsY0AAQIECLSygABuZWC7J0CAAAEC9QQEcD0V2wgQIECAQCsL\nCOBWBrZ7AikILF26ND772c/GRRdd1KScb37zm3HSSSc12eYKAQJtI9ChbZaxCgECZQp06tQpJk2a\nFAcccEDst99+ceyxx8b3v//9mD59esyYMaPM0qxNIFsBAZzt6DWem8Cee+5ZC91hw4ZFx44dY/To\n0fH000/HZpttlhuFfgkkIdDuvf9dkqhEEQQItInAUUcdFY888khcf/31cdppp7XJmhYhQODDAt4D\n/rCJLQQaWqB3796xcuXK6NatW0P3qTkCqQsI4NQnpD4CLSjwxBNPxIQJE+Kyyy6LM888M956660W\n3LtdESDwUQScgv4oWu5LoMIC77zzThTvA1944YVRvA/ct2/f2GmnneKnP/1phbtSOoHqCgjg6s5O\n5QQ+ksDw4cPj5ZdfjqlTp0a7du1izpw50adPn7jnnnuif//+H2lf7kyAwMYLCOCNN7QHAskLPPzw\nwzFw4MCYOXNm7LjjjmvqLX4V6cc//nG88MILPg29RsU3BNpGQAC3jbNVCBAgQIBAEwEfwmrC4QoB\nAgQIEGgbAQHcNs5WIUCAAAECTQQEcBMOVwgQIECAQNsICOC2cbYKAQIECBBoIiCAm3C4QoAAAQIE\n2kZAALeNs1UIECBAgEATAQHchMMVAgQIECDQNgICuG2crUKAAAECBJoICOAmHK4QIECAAIG2ERDA\nbeNsFQIECBAg0ERAADfhcIUAAQIECLSNgABuG2erECBAgACBJgICuAmHKwQIECBAoG0EBHDbOFuF\nAAECBAg0ERDATThcIUCAAAECbSMggNvG2SoECBAgQKCJgABuwuEKAQIECBBoG4H/A7mZRipqNAOP\nAAAAAElFTkSuQmCC\n"
1022 "png": "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\nISCAy1C3JgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gICOPtDAAABAgQIlCEggMtQtyYB\nAgQIZC8ggLM/BAAQIECAQBkCArgMdWsSIECAQPYCAjj7QwAAAQIECJQhIIDLULcmAQIECGQvIICz\nPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4+0MAAAECBAiUISCAy1C3JgECBAhkLyCAsz8EABAgQIBA\nGQICuAx1axIgQIBA9gICOPtDAAABAgQIlCEggMtQtyYBAgQIZC8ggLM/BAAQIECAQBkCArgMdWsS\nIECAQPYCAjj7QwAAAQIECJQhIIDLULcmAQIECGQvIICzPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4\n+0MAAAECBAiUISCAy1C3JgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gICOPtDAAABAgQI\nlCEggMtQtyYBAgQIZC8ggLM/BAAQIECAQBkCArgMdWsSIECAQPYCAjj7QwAAAQIECJQhIIDLULcm\nAQIECGQvIICzPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4+0MAAAECBAiUISCAy1C3JgECBAhkLyCA\nsz8EABAgQIBAGQICuAx1axIgQIBA9gICOPtDAAABAgQIlCEggMtQtyYBAgQIZC8ggLM/BAAQIECA\nQBkCArgMdWsSIECAQPYCAjj7QwAAAQIECJQhIIDLULcmAQIECGQvIICzPwQAECBAgEAZAgK4DHVr\nEiBAgED2AgI4+0MAAAECBAiUISCAy1C3JgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gIC\nOPtDAAABAgQIlCEggMtQtyYBAgQIZC8ggLM/BAAQIECAQBkCArgMdWsSIECAQPYCAjj7QwAAAQIE\nCJQhIIDLULcmAQIECGQvIICzPwQAECBAgEAZAgK4DHVrEiBAgED2AgI4+0MAAAECBAiUISCAy1C3\nJgECBAhkLyCAsz8EABAgQIBAGQICuAx1axIgQIBA9gIdshdYD8DDDz8cr732WmyzzTbRv3//9dzb\nzQQIECBAoHkCyb4CXrlyZSxevLh5XbTSvU455ZS46667omPHjnHllVfG8ccfH6tWrWql1eyWAAEC\nBHISSCKAly9fHldccUUMGTIknn322bjtttuiR48escUWW8Rxxx0X7777bpvPZNKkSfHiiy/GTTfd\nFIMHD45f/epXsfnmm8fPf/7zNq/FggQIECDQeAJJnII+//zz46WXXop99tknTjzxxOjQoUNMnjw5\nevXqFSNHjowpU6bUtq+Pf+LEiXH33XfXvdvzzz9f21/dG+tsfO655+Kaa65pcsvw4cPj9ttvb7LN\nFQIECBAgsCECSQTwQw89FDNmzKi9wuzcuXP8+9//jsMOO6zWz5gxY+Liiy9uVgAXp4i/8pWv1HW4\n8847Y8mSJXVvq7exeLU7e/bsOOSQQ9bc/Mc//rFW45oNviFAgAABAhsokEQA77zzzjFr1qzYf//9\n49RTT41//OMfa9qZOXNm9O7de831dX3TqVOnKL7qXYpALd5Xbu5l2LBhMXDgwOjZs2etrmnTpsXp\np58eCxcubO4u3I8AAQIECKxVIIkAHjVqVBx99NHxk5/8pPbfbbfdtlbwRRddFLfccks8+uija22g\ntW7o3r177dR3cXp8woQJUVyfN29edO3atbWWtF8CBAgQyEggiQA+8sgja6d7P3iKuDidXJx+3mST\nTUoZyVZbbRU333xzKWtblAABAgQaWyCJAC6Ii1PExdf7LwcddND7r/qeAAECBAg0jEASv4bUMJoa\nIUCAAAECzRQQwM2EcjcCBAgQINCSAgK4JTXtiwABAgQINFNAADcTyt0IECBAgEBLCgjgltS0LwIE\nCBAg0EwBAdxMKHcjQIAAAQItKSCAW1LTvggQIECAQDMF2r33v0sz71vpuxV/XGHAgAGx9957f+Q+\nHn/88bX+E5cfeWcesFaBZcuWRbt27Wp//nGtd3JDiwgU/+jNpptu2iL7spO1CyxdurR2PLdv337t\nd3LLRgusjrGDDz74I+9r7ty5MXXq1Nhuu+0+8mM39gHZBPDGQPXt2zeeeOKJjdmFxzZDYOzYsbU/\nQ1n8G9wurSvgmG5d39V7v/DCC2v/vO6BBx64epP/toJA8Qd8RowYUbm/VucUdCscDHZJgAABAgTW\nJyCA1yfkdgIECBAg0AoCArgVUO2SAAECBAisT0AAr0/I7QQIECBAoBUEBHAroNolAQIECBBYn4AA\nXp+Q2wkQIECAQCsI+DWkZqD+61//im222aYZ93SXjRFYvHhxFL8v6fdTN0axeY91TDfPaWPv9eab\nb9aO50984hMbuyuPX4fAqlWr4o033oju3buv417p3SSA05uJiggQIEAgAwGnoDMYshYJECBAID0B\nAZzeTFREgAABAhkICOAMhqxFAgQIEEhPQACnNxMVESBAgEAGAgI4gyFrkQABAgTSExDA6c1ERQQI\nECCQgYAAzmDIWiRAgACB9AQEcHozybqi5cuXZ92/5gkQyEdAAK9j1k888UQccsghsdNOO8Wxxx4b\nb7311jru7aaNFZg0aVIcdNBBG7sbj1+HQGF8+OGHR58+fWLw4MHx0ksvrePebtpQgTlz5tR+Zuy5\n556x//77xzPPPLOhu/K4ZgqcdtppMXz48GbeO427CeC1zKH4Z81OOumkuP7666P4P1MRwueee+5a\n7m3zxggUT2zOOuusOPvss+O9997bmF157DoE5s+fHyNHjowihP/0pz/FEUccEeecc846HuGmDRUY\nOnRoHH/88TFz5swYM2ZMDBw4cEN35XHNEHjwwQdj8uTJzbhnWncRwGuZx4wZM2KPPfaIvfbaKzp2\n7BgjRoyIu+++ey33tnljBB577LHYZJNN4mc/+9nG7MZj1yNQ/Hu5d9xxR/To0aN2z+JV8NNPP72e\nR7l5QwSmTJkSgwYNqj10xYoVUXy5tI7AggULak9yip/RVbsI4LVMbN68eU3+AEPxQ2vRokXx7rvv\nruURNm+oQPHq4Morr4zOnTtv6C48rhkC2267bRx66KFr7nnjjTfGgAED1lz3TcsJbL311tGuXbva\nGYbi1Oh1113Xcju3pyYCZ5xxRlx66aXRpUuXJturcEUAr2VKxbOq9/9VntXh8J///Gctj7CZQHUE\nxo0bF/fff39cddVV1Sm6YpUWT9aLv87Tq1evuO2222LZsmUV6yD9cn/xi1/Unrj369cv/WLrVCiA\n66AUm7p16xbFn8dbfXn77bejU6dOseWWW67e5L8EKilwww03xMUXXxyPPvpoLRwq2UQFii7+BOFF\nF10UTz31VDz++OO1/1ag7MqUWLxIKj7DUHyo8IEHHqh9oPDVV1+N6dOnV6YHAbyWURXPWl955ZU1\ntxbfb7/99muu+4ZAFQWK99mL03VF+BafcXBpeYGlS5fGBRdcsObtqg4dOsRuu+0Wf/nLX1p+sYz3\nuHDhwujdu3cUTygvv/zyKD5L8txzz8XEiRMroyKA1zKq4lnV3Llza0MtTiVdffXV8dWvfnUt97aZ\nQPoCf/vb3+LMM8+snQ4t3g8u/lh88eXSsgLFmbI//OEPMX78+NqOiw90/v73v4/Pf/7zLbtQ5nvb\nZZddah8iLD5IWHwVv0lx9NFH135zpSo0HapSaFvXWZw+Kj44ccwxx0TXrl1rz2DHjh3b1mVYj0CL\nCRS/UrdkyZLo27dvk30W24pPobu0nMAVV1wRo0aNimuuuab282PChAnx6U9/uuUWsKeGEGj3v9+7\n9IuX6xhl8esDxfu/3vtdB5KbCBCoK1D85kTxBN6FQD0BAVxPxTYCBAgQINDKAt4DbmVguydAgAAB\nAvUEBHA9FdsIECBAgEArCwjgVga2ewIECBAgUE9AANdTsY0AAQIECLSygABuZWC7J0CAAAEC9QQE\ncD0V2wgQIECAQCsLCOBWBrZ7AgQIECBQT0AA11OxjQABAgQItLKAAG5lYLsnQIAAAQL1BARwPRXb\nCBAgQIBAKwsI4FYGtnsCBAgQIFBPQADXU7GNAAECBAi0soAAbmVguydAgAABAvUEBHA9FdsIECBA\ngEArCwjgVga2ewIECBAgUE9AANdTsY0AAQIECLSygABuZWC7J0CAAAEC9QQEcD0V2wgQIECAQCsL\nCOBWBrZ7AikILF26ND772c/GRRdd1KScb37zm3HSSSc12eYKAQJtI9ChbZaxCgECZQp06tQpJk2a\nFAcccEDst99+ceyxx8b3v//9mD59esyYMaPM0qxNIFsBAZzt6DWem8Cee+5ZC91hw4ZFx44dY/To\n0fH000/HZpttlhuFfgkkIdDuvf9dkqhEEQQItInAUUcdFY888khcf/31cdppp7XJmhYhQODDAt4D\n/rCJLQQaWqB3796xcuXK6NatW0P3qTkCqQsI4NQnpD4CLSjwxBNPxIQJE+Kyyy6LM888M956660W\n3LtdESDwUQScgv4oWu5LoMIC77zzThTvA1944YVRvA/ct2/f2GmnneKnP/1phbtSOoHqCgjg6s5O\n5QQ+ksDw4cPj5ZdfjqlTp0a7du1izpw50adPn7jnnnuif//+H2lf7kyAwMYLCOCNN7QHAskLPPzw\nwzFw4MCYOXNm7LjjjmvqLX4V6cc//nG88MILPg29RsU3BNpGQAC3jbNVCBAgQIBAEwEfwmrC4QoB\nAgQIEGgbAQHcNs5WIUCAAAECTQQEcBMOVwgQIECAQNsICOC2cbYKAQIECBBoIiCAm3C4QoAAAQIE\n2kZAALeNs1UIECBAgEATAQHchMMVAgQIECDQNgICuG2crUKAAAECBJoICOAmHK4QIECAAIG2ERDA\nbeNsFQIECBAg0ERAADfhcIUAAQIECLSNgABuG2erECBAgACBJgICuAmHKwQIECBAoG0EBHDbOFuF\nAAECBAg0ERDATThcIUCAAAECbSMggNvG2SoECBAgQKCJgABuwuEKAQIECBBoG4H/A7mZRipqNAOP\nAAAAAElFTkSuQmCC\n"
1023 },
1023 },
1024 {
1024 {
1025 "output_type": "stream",
1025 "output_type": "stream",
1026 "stream": "stdout",
1026 "stream": "stdout",
1027 "text": [
1027 "text": [
1028 "v1 is: [ 10.]\n",
1028 "v1 is: [ 10.]\n",
1029 "v2 is: [ 10.]\n"
1029 "v2 is: [ 10.]\n"
1030 ]
1030 ]
1031 }
1031 }
1032 ],
1032 ],
1033 "prompt_number": 7
1033 "prompt_number": 7
1034 },
1034 },
1035 {
1035 {
1036 "cell_type": "heading",
1036 "cell_type": "heading",
1037 "level": 2,
1037 "level": 2,
1038 "metadata": {},
1038 "metadata": {},
1039 "source": [
1039 "source": [
1040 "Cell level magic"
1040 "Cell level magic"
1041 ]
1041 ]
1042 },
1042 },
1043 {
1043 {
1044 "cell_type": "markdown",
1044 "cell_type": "markdown",
1045 "metadata": {},
1045 "metadata": {},
1046 "source": [
1046 "source": [
1047 "Often, we will want to do more than a simple linear regression model. There may be several lines of R code that we want to \n",
1047 "Often, we will want to do more than a simple linear regression model. There may be several lines of R code that we want to \n",
1048 "use before returning to python. This is the cell-level magic.\n",
1048 "use before returning to python. This is the cell-level magic.\n",
1049 "\n",
1049 "\n",
1050 "\n",
1050 "\n",
1051 "For the cell level magic, inputs can be passed via the -i or --inputs argument in the line. These variables are copied \n",
1051 "For the cell level magic, inputs can be passed via the -i or --inputs argument in the line. These variables are copied \n",
1052 "from the shell namespace to R's namespace using rpy2.robjects.r.assign. It would be nice not to have to copy these into R: rnumpy ( http://bitbucket.org/njs/rnumpy/wiki/API ) has done some work to limit or at least make transparent the number of copies of an array. This seems like a natural thing to try to build on. Arrays can be output from R via the -o or --outputs argument in the line. All other arguments are sent to R's png function, which is the graphics device used to create the plots.\n",
1052 "from the shell namespace to R's namespace using rpy2.robjects.r.assign. It would be nice not to have to copy these into R: rnumpy ( http://bitbucket.org/njs/rnumpy/wiki/API ) has done some work to limit or at least make transparent the number of copies of an array. This seems like a natural thing to try to build on. Arrays can be output from R via the -o or --outputs argument in the line. All other arguments are sent to R's png function, which is the graphics device used to create the plots.\n",
1053 "\n",
1053 "\n",
1054 "We can redo the above calculations in one ipython cell. We might also want to add some output such as a summary\n",
1054 "We can redo the above calculations in one ipython cell. We might also want to add some output such as a summary\n",
1055 " from R or perhaps the standard plotting diagnostics of the lm."
1055 " from R or perhaps the standard plotting diagnostics of the lm."
1056 ]
1056 ]
1057 },
1057 },
1058 {
1058 {
1059 "cell_type": "code",
1059 "cell_type": "code",
1060 "collapsed": false,
1060 "collapsed": false,
1061 "input": [
1061 "input": [
1062 "%%R -i X,Y -o XYcoef\n",
1062 "%%R -i X,Y -o XYcoef\n",
1063 "XYlm = lm(Y~X)\n",
1063 "XYlm = lm(Y~X)\n",
1064 "XYcoef = coef(XYlm)\n",
1064 "XYcoef = coef(XYlm)\n",
1065 "print(summary(XYlm))\n",
1065 "print(summary(XYlm))\n",
1066 "par(mfrow=c(2,2))\n",
1066 "par(mfrow=c(2,2))\n",
1067 "plot(XYlm)"
1067 "plot(XYlm)"
1068 ],
1068 ],
1069 "language": "python",
1069 "language": "python",
1070 "metadata": {},
1070 "metadata": {},
1071 "outputs": [
1071 "outputs": [
1072 {
1072 {
1073 "metadata": {},
1073 "metadata": {},
1074 "output_type": "display_data",
1074 "output_type": "display_data",
1075 "text": [
1075 "text": [
1076 "\n",
1076 "\n",
1077 "Call:\n",
1077 "Call:\n",
1078 "lm(formula = Y ~ X)\n",
1078 "lm(formula = Y ~ X)\n",
1079 "\n",
1079 "\n",
1080 "Residuals:\n",
1080 "Residuals:\n",
1081 " 1 2 3 4 5 \n",
1081 " 1 2 3 4 5 \n",
1082 "-0.2 0.9 -1.0 0.1 0.2 \n",
1082 "-0.2 0.9 -1.0 0.1 0.2 \n",
1083 "\n",
1083 "\n",
1084 "Coefficients:\n",
1084 "Coefficients:\n",
1085 " Estimate Std. Error t value Pr(>|t|) \n",
1085 " Estimate Std. Error t value Pr(>|t|) \n",
1086 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
1086 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
1087 "X 0.9000 0.2517 3.576 0.0374 *\n",
1087 "X 0.9000 0.2517 3.576 0.0374 *\n",
1088 "---\n",
1088 "---\n",
1089 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1\n",
1089 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1\n",
1090 "\n",
1090 "\n",
1091 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
1091 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
1092 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
1092 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
1093 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739\n",
1093 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739\n",
1094 "\n"
1094 "\n"
1095 ]
1095 ]
1096 },
1096 },
1097 {
1097 {
1098 "metadata": {},
1098 "metadata": {},
1099 "output_type": "display_data",
1099 "output_type": "display_data",
1100 "png": "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\nHwT+H3+Bv8VJdwumAAAAAElFTkSuQmCC\n"
1100 "png": "iVBORw0KGgoAAAANSUhEUgAAAeAAAAHgCAYAAAB91L6VAAAEJGlDQ1BJQ0MgUHJvZmlsZQAAOBGF\nVd9v21QUPolvUqQWPyBYR4eKxa9VU1u5GxqtxgZJk6XtShal6dgqJOQ6N4mpGwfb6baqT3uBNwb8\nAUDZAw9IPCENBmJ72fbAtElThyqqSUh76MQPISbtBVXhu3ZiJ1PEXPX6yznfOec7517bRD1fabWa\nGVWIlquunc8klZOnFpSeTYrSs9RLA9Sr6U4tkcvNEi7BFffO6+EdigjL7ZHu/k72I796i9zRiSJP\nwG4VHX0Z+AxRzNRrtksUvwf7+Gm3BtzzHPDTNgQCqwKXfZwSeNHHJz1OIT8JjtAq6xWtCLwGPLzY\nZi+3YV8DGMiT4VVuG7oiZpGzrZJhcs/hL49xtzH/Dy6bdfTsXYNY+5yluWO4D4neK/ZUvok/17X0\nHPBLsF+vuUlhfwX4j/rSfAJ4H1H0qZJ9dN7nR19frRTeBt4Fe9FwpwtN+2p1MXscGLHR9SXrmMgj\nONd1ZxKzpBeA71b4tNhj6JGoyFNp4GHgwUp9qplfmnFW5oTdy7NamcwCI49kv6fN5IAHgD+0rbyo\nBc3SOjczohbyS1drbq6pQdqumllRC/0ymTtej8gpbbuVwpQfyw66dqEZyxZKxtHpJn+tZnpnEdrY\nBbueF9qQn93S7HQGGHnYP7w6L+YGHNtd1FJitqPAR+hERCNOFi1i1alKO6RQnjKUxL1GNjwlMsiE\nhcPLYTEiT9ISbN15OY/jx4SMshe9LaJRpTvHr3C/ybFYP1PZAfwfYrPsMBtnE6SwN9ib7AhLwTrB\nDgUKcm06FSrTfSj187xPdVQWOk5Q8vxAfSiIUc7Z7xr6zY/+hpqwSyv0I0/QMTRb7RMgBxNodTfS\nPqdraz/sDjzKBrv4zu2+a2t0/HHzjd2Lbcc2sG7GtsL42K+xLfxtUgI7YHqKlqHK8HbCCXgjHT1c\nAdMlDetv4FnQ2lLasaOl6vmB0CMmwT/IPszSueHQqv6i/qluqF+oF9TfO2qEGTumJH0qfSv9KH0n\nfS/9TIp0Wboi/SRdlb6RLgU5u++9nyXYe69fYRPdil1o1WufNSdTTsp75BfllPy8/LI8G7AUuV8e\nk6fkvfDsCfbNDP0dvRh0CrNqTbV7LfEEGDQPJQadBtfGVMWEq3QWWdufk6ZSNsjG2PQjp3ZcnOWW\ning6noonSInvi0/Ex+IzAreevPhe+CawpgP1/pMTMDo64G0sTCXIM+KdOnFWRfQKdJvQzV1+Bt8O\nokmrdtY2yhVX2a+qrykJfMq4Ml3VR4cVzTQVz+UoNne4vcKLoyS+gyKO6EHe+75Fdt0Mbe5bRIf/\nwjvrVmhbqBN97RD1vxrahvBOfOYzoosH9bq94uejSOQGkVM6sN/7HelL4t10t9F4gPdVzydEOx83\nGv+uNxo7XyL/FtFl8z9ZAHF4bBsrEwAAQABJREFUeAHsXQe8E0UTnwsgiCAWQCkqKL1I771K7yBF\nkKqAIh1soPQmHRGkCkivYqE36dI7IoqCAgqiYBdy3/4HL19eXt57yUtyuUtmfr/k2t7u7P9ub3Zn\nZ2c0XREJCQKCgCAgCAgCgoCpCDhMLU0KEwQEAUFAEBAEBAFGQASwvAiCgCAgCAgCgkAYEBABHAbQ\npUhBQBAQBAQBQUAEsLwDgoAgIAgIAoJAGBAQARwG0KVIQUAQEAQEAUFABLC8A4KAICAICAKCQBgQ\nEAEcBtClSEFAEBAEBAFBQASwvAOCgCAgCAgCgkAYEBABHAbQpUhBQBAQBAQBQUAEsLwDgoAgIAgI\nAoJAGBAQARwG0KVIQUAQEAQEAUFABLC8A4KAICAICAKCQBgQEAEcBtClSEFAEBAEBAFBQASwvAOC\ngCAgCAgCgkAYEBABHAbQpUhBQBAQBAQBQUAEsLwDgoAgIAgIAoJAGBAQARwG0KVIQUAQEAQEAUFA\nBLC8A4KAICAICAKCQBgQEAEcBtClSEFAEBAEBAFBQASwvAOCgCAgCAgCgkAYEBABHAbQpUhBQBAQ\nBAQBQUAEsLwDgoAgIAgIAoJAGBAQARwG0KVIQUAQEAQEAUFABLC8A4KAICAICAKCQBgQEAEcBtCl\nSEFAEBAEBAFBQASwvAOCgCAgCAgCgkAYEBABHAbQpUhBQBAQBAQBQUAEsLwDgoAgIAgIAoJAGBAQ\nARwG0KVIQUAQEAQEAUFABLC8A4KAICAICAKCQBgQEAEcBtClSEFAEBAEBAFBQASwvAOCgCAgCAgC\ngkAYEBABHAbQpUhBQBAQBAQBQUAEsLwDgoAgIAhEMQJ//PEH/f33334hoOs6/fLLL37dI4ljIyAC\nODYmfp+5efMmaZpGmTJloscee4x/mTNnpoYNG9LVq1f9zs+44cknn6SjR48ah67t559/ToULF3Yd\n+7uza9cuevrpp/29LdHpGzVqRClSpKD7778/xu/777+n/v3705tvvsl5r1+/nrZs2cL7ly5dosmT\nJ/tdZrdu3WjEiBF+3yc3CALBQKBixYpUrVq1GFldv36dvw937tyJcd6Mg4wZM9LZs2e9FvXxxx9T\nmTJl6KmnnqKcOXNSlSpVaMeOHV7TGifRZtGeH330USpevDh/R0aPHm1clq2fCIgA9hOw+JJDWF68\neJF/x48fJzS4119/Pb5b4r22c+dOypMnT7xp7HJx6NChhI6K+w8dltdee4369u3L1Zg+fTqhgYPQ\nydiwYQPvy58gYCcE0G7nzJljaZaXLVtGvXr1on79+tG3335LFy5coDfeeIMaN25MmzZt8so7OsXl\ny5en0qVLE75vX375JW3cuJGQV48ePbzeIyfjR0AEcPz4JPrqgw8+yL1LQ00DlQ2EEEbGEDzDhg0j\nnAPNnz+fHn/8cXr44YepadOmdOPGDT7fpk0b+vrrr3l/5cqVlD9/fsqSJQutWrWKz+Fv+PDh9N57\n77mOUQYEGejUqVNUqVIlSpMmDT3xxBM0fvx4VzpjB42oZMmSlDp1ah5V79mzx7jk2nbp0oWWLl3q\nOv7oo4/ohRdeoNu3b1P79u3pgQce4PxHjRrlSuPrzqxZs/hjNXv2bG7MGBFj5Nu7d2/atm0bPffc\nc5zV9u3bqUCBAlwWeuDXrl3j88AQH5IMGTJQuXLlCB8JIUEgnAhAqKFjGZf2C+8y3uGHHnqIGjRo\nQFeuXGF20X6GDBnC34ju3bvTmDFj+Fe2bFlKnz49a3bWrl1L0IyVKFGCjLYKFXLnzp35u4I88Q25\ndetWvBCMHTuWy6pfvz7dc889nLZy5crM94QJE7zei29AoUKFqE+fPswPEj3yyCOEbxPa7G+//eb1\nPjkZNwIigOPGxu8raFjoPa5bt44mTZpEaFCGAIGQXbBgAaEBrV69mhYtWkT79++nv/76i7p27UoQ\naufPn6fff/+dpk2bxmVD+OI6thB4aJy4f/PmzS7efvzxR5cwwkk0eqi8QCi7Vq1a9MMPP7DwxUjz\n559/5mvGH0bo9erVI+TTrl07eumll4xLri1UTeDfINSjWLFitGLFCvrqq6+Yb9QZnQoce6N9+/bR\njBkzXL/Dhw9zMoP/Vq1aEdR3AwcOpI4dO9LgwYO5AwMsfvrpJ6pbty6PlE+fPs0dCkPNPHXqVFab\nbd26lXn/9NNPvRUv5wQB0xDImzcvtW3bljAd4knffPMNtze0uWPHjtG9995Lzz//PCdDW5g4cSJN\nmTKF0B7w3uM9h7BEW8NUDQQdNEMQnEgLwhbfDrQpCGXku2TJEr7m7e/ff//lqS10vD2pSJEidPDg\nQc/TfPzFF19wZ93zIqbd0qZNy+V7XpPj+BFIGv9lueoPAgMGDODkEEIYrWE+s2DBgnzugw8+YAGH\n+RYQRo4QprjudDo5LRodhLPRI+WE6g9qHjRq9JZBEJTz5s3j/fj+3n//fe6xYpSIkTMaOxq1OyVN\nmpQbHOaJIHzRk/YkzGVDxYReNdKDHwhGjFChct+9ezdVr16d806ePLnn7XyMj8Kvv/7qunbfffcx\nb8YJ3JcsWTLCefCJLY5TpUpFH374IdcfHy0QVGUQyPgwofeNj12uXLn4h46PkCAQbgTQkcT00Zo1\nawgjWIPQvvPly8fvLM6hU509e3buAOMY77XRzpcvX87CGqNdELRn0Iply5aNateuzZ1ZnG/ZsiXn\nh1Hyn3/+yfkZo2pc9yR0wtGxh5bOk6BJQiceQhrtz50wPYR5Ym+EOWHRPnlDJv5zMgKOHx+/rsKA\nAWrfAwcO8KgVwskgvLxQKcHYAT/so8cKwQPVDgQ0VNNoWJ5GExDo6JkaZDRI4ziuLYQt1LJomFAb\nYU4awt6dxo0bx40No9zcuXPHUDUb6aBihir7k08+oc8++4zngAz1GRp/hw4dWBWFEXZc1pSdOnXi\nnjt67/jhPl8JDRtzTgZ2qBNU+8AUPX93bLz16n0tR9IJAsFCIGXKlDxahXbLveOJ+Vb3dxTCFFNP\n0FKBIGTdCUZUBqFjijYAwncDU0CgJEmSEFTWUAfj+3Hu3Dlu63zRyx/S4ffdd9/FuooROqbDIHzR\nxjEYwA8aLgwq3L9p7jdfUHPIxuDC/bzsx4+ACOD48UnUVVgYYy62rRqZGT1RqGyhTrp8+TL/0EgW\nLlzIAhEWzTDgwg+Wwp5qYDQICHaD0EgMcjgcMYSeMcJFLxcGFZhLReOG2hojYWPe2bgfI1qot8An\nRr/oYRsqbCMNts2bN+e5Z6TFPgjC1sgfdcGIfu7cuXwtmH/oHMDww8AOW6jJ8HHyxMaYMw9m+ZKX\nIJAYBDCaRbvHnLBBUNW6t2W8y2irWbNm5SQQpu7keex+zdhHu4WwRCf1xIkTbJ3s2c6NtMYWbWrx\n4sXGIWuS/vnnH1ZdwzIahGmdvXv38g/tD/dgsGBYc8PYDJ1jCGfwGSkGoy5QTNgRARwikNEoYCwB\noyIQ5mxgGQkDKzQOzM/CKArGRFBJ4UWGmrlmzZqxOKpQoQI3AhhMQXXkbhCFnizmV5EnGjPUwiDD\nIKJq1aq8BAhzzrgXqiV3Qidh5syZ3IChAkfP2lvjxccEy5eQv6EiQwNu1qwZL7EA30bv3D1/f/ah\ndjaM1rBvjBxQB9TRmDfGHHSNGjW48wKVGPDA3DlGFwkto/CHH0krCASKAKZEIKAMeuaZZ9jC/+TJ\nk/z+wi4C7R6GkokldJgNQy18RzBF5NnOPfN+5513+HtkDAJgu4JpHLQlGHaCMOLF4AA/DAxatGjB\nI3TYo+D7gjnrUqVKEb4hUKVjukjIPwREAPuHl8+psS4YxhQQFjCMgDEU5kkwF4s5H/QiIZyhHoZx\nBRoQGiJeZMPAyCjMGFGjFwqVFdbUGgRBjkYH9TWsGA0BjpEhjDvQiKCiheoYqi8IcXdCebCahvoZ\nv0GDBrFBhXsa7EMgQvWLPGAxDWrdujWfh+oJ5WE07o9qmTNx+0P+GFGDJ9QZIwXMkUP1ho8CrkPI\n4+OBOWj0umFEhuvAFB8DX9XzbsXKriAQMgTQLt566y1X/hgRY34Yo0l8C7CEx31VgyuhHzuY+sE3\nBG0TWi/YbEDDFh/lyJGDNXBYQYFROTrT4BUjcXy3YFntSdCWgV8IXwwuIIjxLcB3C3U4c+aM5y1y\nnAACmhrt3F0Lk0BCuRwcBDBSA0GgeRLUx+nSpfM87TpGrxajWEMAui6onbjuRXnoDGBOKj7CyBz5\nopH5S+AJ6iv0kgMl5IX5JwhXzFdDzQ0BC0KnBSNkzJl5EkbL6IH7orLzvFeOBQGzEcD8Ld5Zb+9y\nYnjBZxwjYQhTfwkCFe0eHXt8Y9C5xUoEo915yw9tE20Rqm8QNGNot4b62ts9ci42AiKAY2MiZwQB\nQUAQEAQEgZAjICrokEMsBQgCgoAgIAgIArEREAEcGxM5IwgIAoKAICAIhBwB/yf8Qs6S/wVgDa1M\nZfuPm9wROgQw5w4LcaGEEZD2mzBGksJcBMxqv7YfAcMjVCjWnpr7uKW0SEMADk4QbSaSCUZx3qxl\n/amztF9/0JK0ZiFgVvsN2wgY1nZYthKo1SpGvlhug7VoQoKAVRCAc4VI08rADzGWtSEiDpauGWHo\nYPmK9axYQ+4vSfv1FzFJbwYCZrVfU0fAML2HS0SsGzV898IJBbxGJbRw3AzQpQxBQBCIGwG4/sTS\nGSxtg59xOEbBelOsHUVQDCFBQBDwDwFTBbARDg8LtuHDF4330KFD7AYRHlmEBAFBwPoIYN0oHKRg\n3Te0WHXq1HEFE7A+98KhIGAdBExVQcMnMWJVukfZgKNvRLlBaD4hQUAQsC4CCDuH2MvQYMFLGTyw\nwZUq3K4aMaity71wJghYDwFTBTDcJiI6CNyloTGDEF0DsWbdY9xaDybhSBAQBBAkBD/43D5y5Ah7\nc4M/YBhSwR2hkCAgCPiHgKkCGD6JEQ8T1qGI3AF3ZvA/CuELn8hCgoAgYH0EnnjiCcIP5C2mrLca\nwG2ht/B38E2OcJdCgkA0ImCqAAbACPiM2LD+0vbt22nUqFGxbsN8ctGiRcUKOhYyckIQMAcBLNmA\nNTMCacRFCBOJ9b6ehM43HPsjoICQIBBtCJgugL0B7EsDRrQgRBDxJKi0EWxASBAQBMKDAKLiJERG\nWDvPdOiMR9pyLc86yrEgEBcClhDAvjRgrBf2Fp0DUTzs3oARiQjxbrGe0luko7genpwXBKyAgMSB\ntcJTEB7siICpy5DiAggNOFoa8Zo1a9iBAeJvghB+r3379hwODPF14V1ISBAQBAQBQSB4CCxZsoSn\nSN544w22PULOZ8+eZS+KK1euDNsgztQRMAKpb9261SuqrVq1CiiYu9dMLXby7bffpl27dlGPHj14\nzmvHjh0cXB4BsDNlysTODeDowIixaTH2hZ0oRyDa22+UP35bVx82CGPHjiV4c4M9EeKxY0nswIED\nac6cOXx+06ZNAXtm9BckUwUwRnhwuAFjjUKFCsXgNb5A9DES2vTg6tWrtGDBAoLVJ5wX1K5dm1q0\naEEXLlygPHny8Ki4ZMmSInxt+nyjge1obr/R8HwjuY6vvfYaaxs3btxITZo0oZo1a/KKHMihDh06\nULdu3Xh1Tv369U2FwVQB/Mgjj7AQGjBgAGHEG00E1XKJEiVIO3acbhcqQUmO7GdBjKVYgwcPJmDz\n4osvRhMkUlebIRDN7ddmj0rY9UAA7lPbtWtHb775Jq/EgR+KHDlyuFLlzJmTXay6Tpi0Y/ocMEZ7\nK1asMKl61ikGy6/Sp05NZ9u/QDfHjaat/V6jnTt3EtZHzpo1i3bv3s1BJS5fvmwdpoUTQcADgWht\nvx4wyKGNEICRbsuWLVkAQ9MKV6qlSpWiBg0a0K1bt+iLL77gEXDFihVNr5WpI2DTa2ehArFUanTu\nfLRs/0HasH0r9T3/NZ04cIBSqxcCnoWEBIFgIgCremhcPvnkEzqg3rNXXnnFZ6cZweRD8hIEwo0A\n7GqgakabwK9Ro0bUv39//u5C5YzRMDy7ZcyY0XRWRQCbBLl+5iw5tu+gFju2Uktl9X3n9QGkHT5C\nVL2aSRxIMdGCAAwdYe0Jr3NYJw/3kT179pS42dHyAkg9YyAAT2swgPUkK/gvN10F7QlCNBzrav7X\nOeod0l55iTQlfEGOZ6qRvn5jNFRf6mgyArC0HzZsGBuVwNKzX79+hFCCQoKAIGAtBEQAm/A89IVq\nzW+GR8lRscL/SytdiujcV6T/9NP/z8meIBAEBODa8cMPP6Rp06axxSdi92bLli0IOUsWgoAgEEwE\nRAAHE00veekq2pO+fCU5er4S46qWLBlplSqSvmFTjPNyIAgEigCWt8FtK0IHYmnb7du3acSIEYFm\nK/cLAoJAkBGQOeAgA+qZnfOd8aS1bUOaMrbyJE2poZ0jxxC1auF5SY4FAb8ROHz4MMGrjzthyR8I\n5+FxTUgQEASsg4AI4BA+C+faT4juOElrUM9rKVqe3KT8ohEMtLRcOb2mkZOCgK8I3H///YT1jN4I\na3iFBAFBwFoIiAAO0fPQf/6Z9FlzyDFBGV/FE61Jq1Gd9HUbRACH6DlEU7ZPPfUU4eeNoIYWEgQE\nAWshIHPAIXoezgmTeeSrZckSbwla9aqkb91Gunwg48VJLvqOwLVr16hWrVqUN29eyp07N2XPnp2d\nvPieg6QUBAQBMxCQEXAIUNZ37iL69jvSBryeYO5a+vRETz1JtHsPUflyCaaXBIJAQgjAAhrxd8uX\nL8/u9m7evMke1xK6T64LAoKAuQjICDjIeOt//EEY/Tr69iJYOvtCGAU7xRraF6gkjQ8I/KHeQbjV\ng7u9EydOUNu2bTkCjA+3ShJBQBAwEQERwEEGW582g7QypUnLl9fnnLUK5YmOHCVduUwTEgQCRaBK\nlSr01ltvURY1/QFvWFgPnDx58kCzlfsFAUEgyAiICjqIgOrHT5C+Zy85PpjlV67avfey0NY3bSGt\ncUO/7pXEgoAnAlgDPHLkSEqbNi1vEec03OuAN2/eTEOGDPFklYOiFyhQINZ5OSEIRAMCYRXACNH3\n999/U8qUKW2Ptf7vv+QcM44cPbqRloj6sBr6fSW4RQDb/l0IdwWWLFlCQ4cOjcEGIsBMnTo1xjkz\nDzAqx8+TOnXqRIhWIyQIRCMCpqqgJ0+eTDt27GCc4Qgb8Rjz589Pbdq0YUFs5wegz/+QKGsWHskm\nqh6FCxFh6dKFC4m6XW4SBAwEEO0F4S3xQ2CG3r17E9xTCgkCgoC1EDBVAMMhPEJDITgy/NPCc8+5\nc+coa9asYe2dB/pI9G++If2jj8nR/eVEZ4W1wvCMhTXBQoJAIAgkU8Z/qVXsafyghn7++edpzZo1\ngWQp9woCgkAIEAiLChrqsIIFCxI894Dq1KkTy4VeCOoakiyhPnOOUe4mO3Ug7aGHAiqDXVP26EP6\nCx1Jc5jaNwqIb7nZWgjs37+f1q5dy0w5lac1WELnyZPHWkwKN4KAIECmCmAEPoaDeHjrOXXqFF26\ndIngNKBz585khdiMiXkf9FVqZHFPMnLUrpmY22Pcoyl8CC4DDxwkKl4sxjU5EAR8RQDxT91dUpYt\nW9br/Kuv+Uk6QUAQCA0CpgpgBAbH79tvv6UjR47QfffdRz/++CPNmzePvfaEpoqhyxWhBPUP5pNj\n6qSgFcKesdSaYE0EcNAwjbaMYFuBn5AgIAhYGwFTBbABxRNPPEH4gR588EHjdLzb8+fPE5YyeNKZ\nM2fo0Ucf9TxtyrFz3ETSmjUhLVOmoJWnValEzpmzCQ49EmNNHTRGJCPbIYB53oEDB3rlu1ixYjRz\n5kyv1+SkICAIhAeBsAhgz6qOGzeOlyLAWjMuSpo0KRuVeF6HwYkjDPOlzi1bia7+SNrQQZ4sBXSs\nKcMZKlJY+YfeTloQ1NoBMSM32wqB2rVrU+XKlenQoUM0YcIEXnebSXUO4ZrSsLewVYWEWUEgwhEI\nmwD+V62bheBMkiQJvfDCCwnC7D5qdk+8ZcsW09cR6rdukf7uNHIMG0ya4j/Y5IBryqXLiUQABxva\niM7P6KTu27ePWrduTfny5eP6Yq1tvXr1eLlfRAMglRMEbIaAqQIYIdFeffVVWrVqFcMEAQwXec2b\nN6f+/fvbBjoIX61yxdCFECxZgkg59dCvXCEtTOp12zwMYTQWAlWrViUI3Svq/Xn44Ydp8eLFPDKO\nlVBOCAKCgFcEsFLHDDJ1rcv48eO5Tpi3xZwu1gBDXYYPxcKFC82ob8Bl6IcOk678Nmsd2gWcV1wZ\nYFStVa0sa4LjAkjOx4sAIiHNmDGDjR23b99OLVu2tFUHN97KyUVBIAQI3Lhxg3744QdXzvfcc49r\nP5Q7pgpgVBBeejBvaxAqCvXYxYsXjVOW3er//EPOd8aTo1d30lKkCCmfWnXllEMiJIUU40jL/MCB\nA7R06VLau3cvwR0lCM44cN6uy/wi7RlJfayDABxCGXRBeSBM4fZNN0sAm6qCfu6556hr167UuHFj\nwppgEATv/PnzvVo4G+BYZavP+YC0vHlMWSKk5chOSj9PCPCg5b87l2cVHIQPayIAr1dwvAG1c5Ei\nRWIwmR5xp4UEAUGAEYAPim+UB8Ny5crxcaFCyhVwGMjUETA+CgiPhqVHx48fp6NHj1KqVKlY+Fr9\nA6F/9RXp6zeS9nIX0x4Tu6ZUZQoJAr4ggPCDiIQERzcwWmzWrBmvtT99+jSFIuIQgqkg9rCQIGB1\nBNAxhcGuQeikGsLXOBeOrakCGBXMkCEDG4gMHz6cQ6VhRGx54asennPUWNK6vEBamjSmPSd2yrFt\nO0H1LSQI+IoAAjD07NmTndygfd2rwl3iOFCK5GAqgWIj91sPgZ+UoyRE2wPBANjwPYFjtAkrkOkC\n2AqV9pcHfdkKogfSkKNaVX9vDSg9+5bOk5v0nbsCykduji4Edu3aRcOGDaOPP/6YmjZtSv369SME\nQgmUIjWYSqC4yP3WQQDLWw2CLQSC3IAwpwvNkNUoTgGMtYSgTz75hAYNGkSwEotG0i9fJn3hYnL0\n7hGW6osaOiyw27pQhB6E841p06ZRkyZNOPJYtmzZglYn92AqWEqIYCpwKSskCIQTAbg3hptjg+rW\nrcuC1zi24tarAA6VCsuKACTEE6yetVYtwrYeVytXlujUadJVrGAhQcAXBFq0aMFzwT169OB42xgV\njBgxwpdb401jBFNBeMONGzdyMBV89BBMBYaVQoKAmQjAihmRvgzKnDkzBbOjaeQbyq1XARwqFVYo\nKxKKvJ3r1hP99jtpTRqFInuf8tSU6kQrX470jbH9YPuUgSSKOgSgdsMa+6FDh9KiRYvo008/pa+U\nEWGghEAqyBdLmjAfjGAqMG5BMJWiRYsGmr3cLwgkiIC7JvZnNShB5C+DsArAbuR1GZKhwjp27BhN\nmjQp6CosO4Ck//IL6e/PIsfo4WGPzctxgidMJnq2qR2gEx7DjMDu3bt57mvw4MH0i3qP4RcaQRog\njINB7m5hfQ2mgpHyggULYhWPqa6sWbPGOi8nBAEDAcRcR6cSBlWwZDa0LcZSViOdHbdeBTBUWJjn\ngUu7kiVLsreqYKiw7ASQPnkqaTWqkxbEubPE1l97Oj/Rn38SlkJZgZ/E1iPS7rt+/TodPnyYAx1g\n+Y9V6OTJk9xu8eECYeWBYQ0aCh59CaYCoY3viifBIx5G0kKCgDcEIHAhg1KmTMkOnAzh6y2tHc/F\nEMD4mKxcuTJGPQYMGMDHON++ffsY1yL1QN+3n/QzZ8nRv49lqsjGWOs2qHXI2SzDUzQzAmMPGHng\ng7B8+XKqUKECTZkyxRKQwLd6+fLlORgDAjQsW7aM2rZtG1Te/A2mgpGyp3MQMAS1odFRCCqDkpmp\nCNy8eZPf/6tXr/JzbtOmTaLKh8YGncVHHnmE74d2BMIXFI6od1xwCP9izAEjZFnOnDm9/jJmzBhC\nNqyTta5Gms7xk8jRpydh/tUqxAJ4k4r8pJwfCIUfAQhfrGUfqAyd4FQGaw43bNgQfsYUB3A/CSMp\nOBpAu4X2ytvo019msZayT58+vJwjV65chB8iLkHFjaAqQtGJADpjeBfQ2UMULkyB+NMZ/VN9cw06\ne/ZsDMvlSJ+eiDECxjop/K5du8ahy9DLh5EFGh5UbDVq1DBwititPmsOaYULkVaooKXqqCk1Ij3+\nOJEanVPpUpbiLdKZ0ZVwpe9/IF391IJa3o66cYuqTnqPnPsPUpLBb9EzzzxD6P1bgb7++mtut76E\n+fSHX/dgKoY/93+Uk5hevXpxMBVYRwtFHwII+IFY1FhvDkKnDMvfXn755QTB+O6779gdcZkyZTht\niRIqElwUUQwBbNQbawgRUQVqrBw5chDUC1ANRDrpp8+QvnU7OT6YZcmqsjGWck2ZRARw0J9PDCGr\n/MSysL2knFf8cJkolZqjzJSRNLXMAVtH5Yp0+OK3tFWdH62ELwRvhw4dCEaLViAj3Gfv3r2Dyg6C\nqcCxhyF8kbkRTGX/ftUxFIpaBNyN8TClgOAG3giDuT179rjcQMIlZCQYU3mrqy/nvApg+HetWLEi\nNzT0bmBB2bBhQ8K6wkglqHado5W7yW5dSVP+qa1IWqUKpE+dRroykLMqj1bEzeBJh7MIYyTrKWTv\nT31XyGbKdFfIVqlElBn7mbxGvupZvBh/RCpXrsxGROvWreM1t0ZZ4dzCaAWBT7788kueYwUvUOV1\n7NgxILbsHkwloMrLzXEigNHrxIkTOQRmwYIFOeAOQmAahOVCmBZBxw3q6kfdYpxHuwGeVwFcpUoV\n9h2LGL3wIQtfzZE+xwNvV5ThUXJUrGC8N5bbasoYQStZgvTNW0mrX9dy/IWCIYy64FYRPWr0sufO\nnctzTXGVxUJWjVzvjmD/G8lCdYyRrLuQVcLVodx8uoRs8uRxZen1PHzJIsyfFQntFZi5k2HU4n7O\n330jmApcXGLeG9NTj6tpkc2bN1ven7u/dZX0viOAtgBDRCx7Q6cPmheooA3atm0bh5zFMdJmz57d\nuBT1W68CGPO9I0eO5N4ztps2bQqKJx13tN2tKN3Ph2NfVyER9eUryTFzWjiK96tMVkPPnU8UBQIY\nnm4yqREoYtsOGTKE7RIGvPkmDUdgAUPI/jcni2MWsmnuZ6GqYSQLIZsv710hq4yRND+FrF8PxkKJ\n8YEL1UfOCKZioeoKKxZAAAM0o9OH1TQIM2sYUCEGvJB3BLwKYCQ1QjVVr16d8AsGQf//6quvkjFH\nBbNyPDgsm+jfv3+MuaVglOdrHuxusm0b0tKl8/WW8KUrquK8jhxDulKh8pxk+DgJecmYV0Rvuqla\nj+4cPorWPJieDs+aR86vv4spZBEvWc3NsrrYQpbrIQdIChAELIAApiwhcLGCBgTLe6tHuLMAbMyC\nVwGMEQfc2LkTBPLUqVPdT/m9b0UrSufaT4juOElrUM/v+oTjBk11WrRqVe7GJu7QLhwsmFYmDHww\nf+QcNpI7Gzdbt6JmWzfQ10sXmsaDFCQICAKxEbh16xbP6+IKjBDd53KDMd0Ru8TIPBNjHbBRRagM\nsJYLPwRmwCgE7ikDJcznIW9vVpToQZlNCHCgz5xNjr5qze9/YavM5iEx5cFDl66cckQ6wbgj07ff\n0bp5C2hVhvRUvvVzNHT06EivdqLrt2bNGipQoIDXX6AGWIlmSm6MOAQwNYRpSYOgakYgBCH/EfA6\nAoaANIQkrNewvg9LkrAIPxCymhWlU/lX1hrWJ025ybMTaeqFVxZJpB86zGuW7cS7P7zqSrX19kPp\naNOrfeiKcvsIDUzZsmX9ySKq0mItJqyyDx06xM4xMG+OOXQsK4STHaHIRQBGcQgdi3XZXbp0oXRB\nnk6DS0i0PWilMG3YoEGDyAXTxJp5FcCYe1u7di2zAUtHhHzKkydPwGxZyYqSg9xf+Ja0gW8EXK9w\nZKBVr0r6hk2RLYCnzyStVEl6pld3eiYcINusTHgiQocZAQ7gkQgOEUCdOnViK9TEuge0GQxRx+6Z\nM2d46Q/sa/766y+qX78+R6gKJDQffD9AmBsRhrBWF8IXhPdMKDgIeEUSIZ6MCXUUg54PliYFgxJr\nRQn/oHgpPAluzNxDUuG6+/yE12O1HjTlxCnkeOtN0tTLlGB6t/kOr/mF4XoqNQ/snDuP9L+60W9q\nbR0+vAbZsT6e/KdSqmd9125yzJtty+djPItwbBFEBUL3ypUrBEcHixcv5pFxOHiRMkOPACLWwWYH\n/shBMHZdsWIFG7b6Uzq+scZyU4yo3QddobKq94e/SEwbYw7YmEOCt5sxY8a4fuhZde3aNWT1RzSV\nsWPHxps/1lwiHqnnD/PUnn6q4YrPnTyPz6s4v1qZ0qRhiYoiz+t2ONbSpCEq8DTp23fYkv/4ns/X\nKuqTc8w4cvToRlj7bIfnEV993K+ZsQ8vdjNmzCC4koUjHThFwCoDochEANMLxugUNURn9o6fPuMv\nXLjAkb0MhGB/4e7dyjgv2yAjoNyGuUitzdXVKFPftm2brnT8uuoFKTuln3UVfFv/4IMPXOmCvaNG\nbDp+iSFlXKIrN4A+3+o8dly/3aS57vz9d5/vsWpC57bt+u1efa3KXqL5ujN7rn574KBE32+FG1WH\nUv/oo4/Cyor6CCunab/pahoprHzEV7i/7Te+vKL12ueff66ruX99165d+vr16/XSpUvrqvMVLxz4\n1iuXkK40v/76q3IGeMd1HO07ZrXfGCNgb3NI6AVBnQVDjmASHHEYvbRUyvUjfqEmXZXpPrIKdXkh\nz1+N4unLc8R+jENemDkF6Konrq9ZS47uL5tTYISW0rdvX54DXrRoEdWpU8eyXrsiFH5Tq4UpwlGj\nRnFADBhLIRIRPJR5Evz5w6YHhKm7hx56yJUEo+hIDPfnqqBFd7zOAYdqDincjjj0+aoTkTULq58t\n+jz8Ygvz11rlSneNsVrFDnbuV2YWSKx63aqDNJ60ju1Jc/s4WIA1W7GAaRksq4NrQHx0ES4Q/twh\njIUiE4GiRYsSfp4EgWsIVvgrb9asGSeBmtrd7sLzPjk2B4EYI2CjyFDNIbk74jh//jydO3eOl0zA\nWAR+p0NJ+jffkP7RxxE3suI4wes3hhI60/LWV3+kTCyTkKNOLdPKjMSCTp48SQjIYKxth+EjDGyE\nogsBuIS8pDzmGQSPg4YwNs7JNrwIeB0BgyUIYfyCSeEKZ+YaWXXqEHEjKw0BBdTIEaEUtdy5gvm4\nTM0LanRdWXU7pkwwtdxILAwfWqzbxzIkTCstW7aM2rZtG9aqIsY4gq17EjrfskbZE5XEHcMl5OXL\nlzmmO3KARyr3yEOJy1XuCiUCMQQwLI1hcYr5A8Nfs1E4PGG9+OKLxmGituFyxKGvWkN0TzJy1K6Z\nKL6tfpMxCrazAHaOm0ha08akqfWGQoEhANXixo0baeXKlWwJ3a1bt6B3pv3lEJ3vzz77LNZtGKE9\nYTNHOLEqEcYT8EpluIH8XgUmQbQhgzxXhxjnZWsdBGIIYCy6xpwB1g7CaYY7BcO5djgccfDI6oP5\n5Jg6yb06EbXPEZI6vEj6y114XbPdKufcuk05lP2RtKGD7Ma6JflVqxjoxo0b9MILL7j4gxBWqxlc\nx2bvPP3004SfJ8GPMDRUQv4jgPX+MLqC4w2QrNX1H8Nw3xFDAGfJkoXwA0FlVKJECXZvhpFxtWrV\n+Hygf4l1xOFPubDwQ8xSeHKpv/8gpWzWhDg8nT+Z2CgtR3HKno1IOa6gCuVtxLnSnv/2G+mTp5Jj\n+BDSkiSxFe9WZfbUqVO8rh4qX6zhB8GbnZD9EYDArVixIs/lwmlG3brRERfc/k/Oew28GmEhAENP\nFXP1R+UxCg44oNbAsR0IS5sKFixIR44coRR79tGiSZPpbIH8dmA9IB7hmtKpXFPajfSp05Uld0XS\ncuW0G+uW5hcGj3DEodbIc0fU0swKc3EigFEuLNkNwpyuYUgF5xvGvnFdtvZCwKsAVgu6ObgyRpHw\nitWvXz/C/IIdaN68eRzLeKjq+Te4fJXyzp5Bk/8Lo/iTMvQJdB7bqhhoGPkeOUr6r79alcVYfOmH\nj9wNKNGhXaxrciIwBJIobcJ7773HLmWxDlj89waGp5l3w0eCQdA+GtbsOOfuHtJII1v7IhBDBW1U\nAwZXcLxx7Ngxgp/R999/nwJx7G3ka8YWRgmsLlc9R8z7Pq5e5kurVrI5PtzxefMnbQZfoS5DS5GC\ntLJlSN+0hbTGDUNdXMD562p6wPnOeHL0fIU0N8ORgDOWDPgjbThZQOcZRk6bN28WZGyAwDdquSQG\nCsWLF2duK1WqZAOuhcXEIuBVALdo0YKUCzt24J4/f346ePAgjRgxIrFlmHpfuXLlWADnU2p0qGsq\nq+P27duzv2h0KlC3SCU2xpo2g8gOAlgtOYLVtlbi7ocmUp+JmfVyX8WAd93de52nUaWZfElZcSOA\n0S4GOsbzQWAZsQqPG69Iu+JVAEPlAScZiC+JtWWffvopG2R587RiNUAQkHz58uXsPhNm+N27d+d5\nbEONE8kWl1rhQqTMXwnuHLX/jOms9nzAj66CLeifrSfH3JlWZM+2PIV6FYNtgbEY49DCGWufobFz\nd8MrARAs9rBCzI5XAWx3V3ZwQoA6RCPxmuB1G0jr/P8lKFbCQUUGuOtusnMn4ohOVmLO5rwcPXqU\nXU56q0axYsXYetbbNTkXegTcXUKuXr2ajNjMGPF6hlMNPTdSglUQ8GqEFcmu7GBUFsnEAnjjZoKg\nsyLpy1cSpbqPHM9UtyJ7tuapdu3atHPnTrbbMOw4sCYYwVTQKRUKDwJwCQmPXwbBIZGQIAAEvI6A\nrejKLliPq3HjxsHKypL5sCcp5YKODhwkKl7MUjzq6iOkf7iIHNOmWIqvSGHGWzQz1A0CuF69eq5R\nV6TU16r1gB8CLOE05nLh2MjdJaQsHbLqkzOfL68C2Iqu7MyHxr4l8ih4/UbSLCaAYfWstWxOmgoO\nIBQ6BEIVzSx0HNs/57/++otSqJUIIFgyG3O8OPYWGhDnhQSBWCpoGF9h2REWgMOV3bBhw+jnn3/m\nBf0Clz0Q0KqoEIV795GuDOisQs4NKmLTzVvs79kqPEUqH6GKZuaJF5zewEgz2kkFs2ff2wYOWKub\nOXNm41C2gkCcCMQQwHCYjt4zvEhhLS2OYUUMQRyK5TvSgON8LgFd0FKlIipahPSt2wPKJ1g3wzmI\nrpZHOfr1Is0R45ULVhGSjxsCCKiCERiCtE9VTmiCZfcAX9I7duzgkqZPn045cuQgLFOEQVG0hTvE\n3LpBGPlC3bx06VKCEyN3ev311+nMmTPup2RfEHAhEONriHWETZo04UY7ZMgQtppED/f48eMsmF13\nJXJHGnAigUvEbY5nqpGu1NBWIH3KewS1uJYtmxXYiXgeEMlszZo1Qa8nvOFhtIelM9CSwbgIGrOs\nWbPyNyPoBVooQ9TZ3YmP4egELK5fv57atWtH169f57n2MWPGMOfww71v3z5xBWqh52g1VmIIYLxA\nRkSNx1RYOFhSzpgxwxXuKlDmo7kBB4qd3/fDwYXyBQzDp3CSvv8L0k+eIq3d8+FkI6rKLlmyJE2Z\nMoXdrr7xxhuE38yZwVtzDSc98LeOUTYMiuDqEkZHkUa3b992VclzZGtEdkKHBBqAdevWUZcuXdja\nGZboCIgxfPjwoAxcXEzITsQh4NUIC7WE44qnnnoqJBV2b8AoAA0YsUuFgocAIgtp1aqQjjXBbdsE\nL2M/ctKVYYpz7ARyvNqXNOU4XsgcBBA6FLYb7gQnHYESOuW9evXi7wIEDGL5Impa586dCSrpSCKo\n8REEAfPpIEzJGc583OuJbxmWf6VLl45PJ0uWjAcxsJsRa2d3pGTfGwKxBDB8P0MY4uXD2jWomEDw\nMGWoVrxl5Mu5aGrAvuAR6jSaWmvrfGswUbgE8MzZBO9cWqGCoa6q5O+GALwpLViwgKMhwQEERnLw\nLVy9emBrr1966SXCD1GWYCeCQPAY+SIASt68ed04sN8uXEKePn3aFbMYo3tjGRFq40344jyWF0Ho\nYr4dfrfhc3vs2LFxOkTBPUKCgIFADAGMkWhc0TbczeqNm/3dRnID9hcLM9JriBGsYobqx0+Qlj+f\nGUW6ytDPnGUjMHE36YLEtB34gMbIDc43YCiFuUv3kHaBMgLBZAgnO7tOxLwuOhEgqJIR3s8gXzUG\niDoF2xZ4Gtu4cSMLZMMIDnnBN/0jWJcvJAh4QSCGAIYaxVCleEkbtFOR0oCDBkgIM9JqVL+rhjZR\nAOtqeYpzzDjSXupMWurUIaydZO0NARhOVqxYkUdm27dv59FYw4YNqUePHt6SB3xu3LhxBB/rvXv3\nDjivUGcAPo3R7LJly6ht27ZcJASur0LXk0f4TYjL0rls2bKeyeVYEHAhEEMAu86avGOnBmwyNAEX\nh3lgZ5v2pHd/2bR5WH3REqL06chRWUKpBfwAE5FBlSpVqGfPnrRw4ULeYk44udKEBJOgssUcJ0aA\nWKaYEEE1i5UVnnT27Fme3vI8H4rjQ4cOUaZMmVwjUsMfcyjKkjwFAV8QCJsAtmMD9gVQq6XRHnpI\nRfHOTfrOXaSZIBB1ZZijL1tBjpnTrAZF1PCD+d6RI0fyiA7bTZs2BSWcKOaSsbQGy5xAEMAQ7HBd\ni1jb8RE6Bfh5EtxkhipCGVxCwhgKQheUJk2aGBo+MZLyfBpybDYCpgpguzVgsx9GqMoz1NBkggBm\nd5PK6Ev7zyo0VHWSfONHAHOPIBheBWp8ZZQ0fvx43oW6FYZHoH/++YctozHafv758C81Az/GXO6X\nX35J8MNsUKhWdRj5y1YQ8BeBGOuA/b3Z3/TuDfj8+fNsYQ21EKyt0YCFQoOAVrYM0anTpKvRQCjJ\n+cln6ov8L2kN6oWyGMk7DgTgfAOrFbz9OnbsGMddvp+GZ7xGjRq5hC/uhLBDoIeLFy/6nlGIUt5Q\nsbAx2jcIOIhLSAMN2VoRAVNHwGjAcItn9J4BiNGA9+/fb0V8IoInrMHVKpQnXYUp1J4NTThGCHd9\nxixyjB/jMnKJCPBsVAmsR61cuTKhUzthwgSec4X6FVbRwVjFgDB6Xbt2JUQUw5JCEATv/PnzeflN\nOKCC0wvD0AkuIYM12g9HXaTM6EPAVAFsxQYcLY8camjnuIlEIRLAzolTSKtXhzTlllAoPAiEOhxh\nkSJFCMHkP/74Y3ZPizXGiPQDAysYeplBmNdFucbyIWOLsu+9914zWJAyBIGgIWCqALZCAw4acjbL\niNcBK89U+rmviNcHB5F/GHjRNxdIe/O1IOYqWSUWgVCGI8ygQknCcMpMgsA1DKa2bNnC65uN8gsV\nKmTsylYQsB0CpgpgoBOOBmy7pxIihu/GCVauKeGgI0iEkIcY/ToGvkHaf4Y5QcpaskkkAkY4wiVL\nltCJEyeoZcuWQYuI5M4SfEznzp2boNkKFcFWBO4eMZ8LqlmzpksYh6pMyVcQMAsBU42wPCuFBgyX\neULmIMDW0GoeGI4ygkX69JmklSppuqetYPEfifnAGGnQoEEcEQlGSWhnrVu3tkVVsTwRfqYNSpUq\nVQw3l8ZI2LguW0HAzgiYPgK2M1h2511TfmuVD0GifcrgrXSpgKujnzhJ+q7d5Jg3O+C8JIPgITBn\nzhyCahYrC4wlOYb3p+CVQiwYjTW2wcoXEdnchay4cQwWspKPFREIqwCGA/dgN2ArgmwlnqCGdqo4\nwUkCFMC6Gqk4R48lR49upKVMaaUqRj0vsHhGvFp3A6VQgALVdjDIfVUEghvgJyQIRAMCYRXAwWrA\n0fCgglVHrVIF0qdOI13Nq2lKvZdY0heoddtZsxCvMU5sJnJfSBBArN4GDRrQZ599Rln/s0pHbG9f\nXEaGhKEEMoXaWUgQiEYEwiqAoxHwcNcZo1WtZAnSN28lrX7dRLGjX7hA+pq15Jj9fqLul5tCi8AD\nDzzAIfHcSzFrmZB7mbIvCAgC8SMgAjh+fCLyKquh584nSoQAht9e55jxpHVsT+xnOiIRsnelsmXL\nRvi5E9zACgkCgoC1EAirFbS1oIgibooWIbp6lfREuA/UV39ElCwpOerUiiLA7FXVa9euUa1atdhI\nCsuEsmfPbgk/zfZCUbgVBEKPgIyAQ4+x5UrQVBQbhCnUlTEWRrK+kv7TT6R/MJ8ck+865ff1Pkln\nLgJwPYm1wOXLl6ccOXLQzZs36ZdffjGXCSlNEBAEEkRARsAJQhSZCXhNsBLA/hBcWWpNGpH2nx9g\nf+6VtOYh8IdyjlKxYkUqVaoUO+JA0Pnt27ebx4CUJAgIAj4hIALYJ5giL5GWJQvRgw+SfuiwT5Vz\nbt2m1NY/ktbiWZ/SS6LwIYC4u2+99RZlUc8YvpunTZvGcXvDx5GULAgIAt4QEAHsDZUoOXfXNWXC\no2AsWdInTyVHv96kJUkSJejYt5rFixenkSNHUtq0aXn79ddf04gRI+xbIeFcEIhQBEQAR+iD9aVa\nWtXKhEAKugrSEB/pU6eTVrkiablyxpdMrlkEAYTogwcpOOJAeD4I43nz5lmEO2FDEBAEDATCZoSF\nxfdwOZdERlTGszB9q6VJQ1SwAOnbd5D2THWv5euHj7Ca2jFnhtfrctI6CGDut0OHDuxLGT6U06VL\nx8whmMGDarohnPTFF1/QzJkzY7GAzoLnkqlYieSEIBChCJgqgLEW8dVXX6VVq1YxnBDAyZMnp+bN\nm1P//v3J3SVdhOJtuWo54JoSS4u8CGD9n3/I+c54cvTqTprEWrXcs/NkKKVysjJ06FAOwgB3jvny\n5SMIZQhfzAeHk3LlykW9e/eOxQICR6RIkSLWeTkhCEQDAqaqoMePv7t85cyZM4QwY+fOnaNDhw7R\nlStX2HF8NABuuTrCJ/RX5wlLjDxJnzuPtNy5SCtezPOSHFsUgbVr13J7gpvX5cuXU7Nmzahhw4b0\n/fffh5Xj1KlT85IoLIty/6VRWhgjYERYGZTCBYEwIGCqAP7hhx+oUaNGMUa6aHz16tWji4lwChEG\nvCKuSC1pUjW/W4nXBLtXTv/qK9I/W09at67up2Xfwgjs3r2bli1bRt26daNvv/2W533Pnj1LU6dO\npddff93CnAtrgkB0ImCqChqBu7t27UqNGzemx/5bSwrBO3/+fNq8eXN0PgEL1JpdUw4fRfTc3eg2\nutN5191k507E88QW4FFYSBiBffv2UatWrbhtYelR/fr16V41dVCmTBl65ZVXEs5AUggCgoCpCJg6\nAi5SpAivS8Sc1PHjx+no0aMEYxEIX3EWb+pzj1EY1Mwg/fSZu9tlK4hSpyKHl3lhTiB/lkQAy44u\nXbrEvH388cesWcLBiRMnVBhoFQdaSBAQBCyFgKkjYNQ8Q4YM1KlTJ0uBIMwQncqcic692IW2PpqO\nBv94gx5YrII1CNkKAUzljBo1ivbs2UP/KAO6ChUq0KZNm6hHjx40evRoW9VFmBUEogEB0wWwN1DH\njRtHiLLjzUrSW3o5F1wEdu3aRRP27qJpukbFktxDE65epobKMK6gBEYPLtAhzg0GTQcOHOARb/78\n+Smpmt8HzZ49m+CcQ0gQEASshYAlBLAvgcJhOf3JJ5/EQu/YsWOUOXPmWOflRNwI7N27lxYvXkxO\nNdcLJw0LFy6kvmrklKbPa5Tm24tUfMxIWrduHSGwu5C9EMCSnqJFi7qYrlq1qmtfdgQBQcBaCFhC\nAGMeOCG6//77KWfO2J6Y0NPPmDFjQrfLdTcETp8+Te+88w69++679PnnnxOwxXrMpDvuGsL9vnQp\n3blzx+0O2RUEBAFBQBAINgKWEMC+VApC1pugvX79OquvfclD0txFoF27duwMBe4Jt2zZQnDa0KVL\nF3bacOvWLXbeDyMeIUFAEBAEBIHQIWCqAMaoa+vWrV5rg+UTcB4gZA4CcM6ANdhTpkyhN954g1au\nXMmqaMzFL1q0iB566CFzGJFSBAFBQBCIUgRMFcCtW7fmjzyMrQoVKhQDcsNvbYyTchASBF588UUa\nOHAg/fjjj/T4449zGRgF9+rVKyTlSaaCgCAgCAgCsREwVQAjQsuCBQtowIAB7DAgNjtyxgwEBg8e\nTB988AH7B4ZnMiFBIDEIwE7g77//JvigFhIEBAH/ETDVEQfYy5MnD61YoRw9CIUNAXSE+vXrx36C\njaUqYWNGCrYNApMnT6YdO3Ywv9OnT2efzjCCbNOmDQviYFXkLxUeE36sYal/7do1zha+rLt3707Q\n3sDNppAgEAkImC6A3UHD3CNGxEKCgCBgfQQgBH/99Vf6/fff6f3336fDhw9zQJWsWbOyv+lg1ACj\nakxPIUjL5cuXOaQi/FnDc16fPn0I01gffvhhMIqSPASBsCMQVgEc9toLA4KAIOA3AogvjDXiWL6G\nkKJ16tRhewK/M/JyAyzzS5YsScOHD6eePXvShg0baOLEiVSjRg36SUXsgk/runXrerlTTgkC9kMg\nrAI4b968rqAM9oNOOBYEogsBBFCBod7zzz9PGzduZL/TR44coc6dO3OAlWCggdF1rVq1XFlhysoI\npVi4cGH2JT9s2DDXddkRBOyMgKlGWJ5AybIjT0TkWBCwLgIvvfQS4Yc5WAje++67j0e+GLWiMx0M\nQuSmmjVrUr58+Xh9epUqVQhR1MaOHUsI5gJ3m978AQSjbMlDEDAbgbAKYLMrK+UJAoJA4AggspIR\nXQmRzeDLHa5Lg+HLHfO/S5Ys4VE2XMy+/PLLLPRhmAXLfdCgQYMCr4TkIAhYAAERwBZ4CMKCIGBn\nBHzx5Q6DKoQf9STEA4cQdydEcdq/f7/7KY5rDFW3kCAQSQhEhACGQwn0mgMlxE29oqIA+eKb2tey\nYNUJ4xE4uggmIe5rsINQ/PLLLxxBJ5rrnz17dnrqqacCflRYPoO8ooF8eV/wbnkTwPC8lixZsoDb\nLwT2H3/8QQhGES4KRZv0py6haL/+lI+04cYABoL41mIKIxAyq/1qqgHogTAa7nsh4LAmEdaYgdLq\n1asJDzCYgg2qMyypKF26dKDsxbgfPpwrV64c41ygB+fOneMPGIxtgkV2qz+EZsWKFQOufvLkyXl9\nbJIkSQLOK5IzCFb7nTt3Lnec06ZNGza4QtEm/alMKNqvP+UjbbgxQAcAHcIGDRr4y3qM9Ga1X9sL\n4BioBXgARwOZMmWiYHqHunr1KjsQgFOBYBKExLZt24KZJfuFzpAhQ9AsWsEctBPdunULeITjWdFQ\n1B/RoeCkpEmTJp7FybFCwMq+3F9//XVenlSqVKmwPatQvJP+VAZ+3YPdfv0pH2nDjQF82sNqHt8c\nO1BEqKDtALTwKAjYHQHx5W73Jyj8Ww0BEcBWeyLCjyBgUQTEl7tFH4ywZVsEAp84tW3VhXFBQBDw\nFwHx5e4vYpJeEIgbARHAcWMjVwQBQSAeBMSXezzgyCVBwAcEkrytyId0UZEE1nNwMPDAAw8Erb6w\ngoXqDg7rg0mw9syRI0cws2TrwWivP+Ije65LDSrIEZQZLF4Rx/vpp58Oe63glxptDN65wkWhaJP+\n1CUU3y9/ykfacGNw77338iqW9OnT+8t6WNKLFXRYYJdCBQH7I7Bw4UJeNQDHGUKCgCDgPwIigP3H\nTO4QBAQBQUAQEAQCRkDmgAOGUDIQBAQBQUAQEAT8R0AEsP+YyR2CgCAgCAgCgkDACIgADhhCyUAQ\nEAQEAUFAEPAfARHA/mMmdwgCgoAgIAgIAgEjIAI4YAglA0FAEBAEBAFBwH8EoloAX79+nRCNxRvd\nvn2bEMnH+HlLY+a5f//9l8CvN/rnn39cfGI/XJQQZk6n08UncMVxOOnnn3+muPBKqC7h5FvK/j8C\nCMGHdykuQjCUUAZ8wzuEtumNQv0OxVc2+EF4xlu3bnljLSjn0H4RajUuMr6d2AKLUBFiTcdFoYwb\na3EAAEAASURBVMYgrnJ9PR+VAhhCt379+tS1a1cqVqwY7du3LxZeiKZRqFAhKlOmDP9+//33WGnM\nPNG3b1+C5yFvVLhwYRef7dq185bElHMJYbZs2TKOkWtgunPnTlP48lZIx44dqW3bthzS0VukqoTq\n4i1POWcuAjdu3OAwn8ePH49V8K+//kolS5akDh06cDtGVK5gU5s2bahVq1aUM2dO2rVrV6zsQ/kO\nJVT21KlTqVq1aoToUBMnTozFW6An8M3E97FZs2b88+zkoOODuLxGW580aVKgRXq9f9q0aYS27I1C\njYG3Mv0+h3jA0Uaff/65PmLECK72Z599pjdv3jwWBOrF1dWIM9b5cJzYsGGDXqBAAf3FF1+MVbzq\nGOgFCxaMdT4cJxLC7NVXX9VXrFgRDtZilKk8OLme+c2bN3UVyi7GdRwkVJdYN8gJUxHYv3+/nj9/\nfl0JPx37noR3bd68eXx65syZXp+x5z3+HK9bt05v374936Li8OpK0MS6PVTvUEJlq44JY6NGqLoa\nnet58+bVlaYgFn+BnFDxzfULFy5wFs8995yOb5Q7gUfVAXE/FfR91bli3GvVqhUrbzMwiFVoIk5E\n5Qi4bNmypBoonTlzhmbNmkWVKlWK0XGBauXixYuEXtvLL79M3nrYMW4I4QHUzqNHj6a4PIaCN7hf\ne+mll2jIkCGEnmc4yBfMjhw5Ql988QU9//zzpBpoONjkMrdv307FixengQMH0qJFi+jNN9+MwYsv\ndYlxgxyYjgBcT27dujVON5hHjx7l0TEYQ3s/ePBgUHl0zz9btmwcg9a9gFC+QwmV/eWXX5LqsJOm\naZQ0aVJSHRU6ffq0O3sB7+O7BLe1IG/4oq1DRY62jm9sfNMEiWUG2r7333/f6+1mYOC1YD9PRqUA\nNjBas2YNC1oIMHfCi1OuXDlq2rQpNWjQgH9//vmnexLT9tEBGDVqFAtZb4X+/fffrGrr168fPfzw\nw/zCe0sX6nO+YAY/y3Bb2Lt3b+5Q7N27N9Rsec3/ypUrNGfOHMYN+506dYqRzpe6xLhBDkKOAAQa\n5lrxUwMNVvvifY+L8FzTpEnDl1OnTk2YKw6UMI+J8jGF5Z4/8k2WLFkMIRPKdyihsj2vB6v+Bn5K\na8SC3Tj2lj/8UpcoUYLb+Z49e2jChAlG8qBtod6Oi0KNQVzl+ns+qgVw//79aePGjYStu5EAHIrD\nz61S3VDVqlV5HgOO580mpR6nY8eO0erVq0mp03j06DlyLF++PI0bN457o5jTxqgeDcRs8gWz6dOn\nU40aNXjU8sILL5BSR5vNJpeHYBtq2oGU6ooGDBhAu3fvjmGM5UtdwsJ4FBc6f/58yp07N/+82Wx4\nQgPhbLQDbDNmzOiZxO9jCBTw0Lp1a+7sGvkjIwRdSZEihSvPUL5D7nXzVrbn9WDV36gcBK77iNZb\n/tDIYQ4cATLUFI/pbT3UGBhYBLqNSgEMoxu8FCAYV8FYAKoag7777jsWvDhGbxsqn6JFixqXTdsi\nysyYMWN4pJYrVy6OqmSofQwmlixZ4jLOMnp9UM+ZTQlhhhEMeqzXrl1j1qASxActHIRy1bwdFw1V\nGni75557XKwkVBdXQtkxDQGoMr/66iv+wbgqIcIUw7Zt2zgZtspOIqFbEryOdxY8oHPunj/Uu54C\nPpTvUEJlY+CAbxYs/KEhO3nyJD355JMJ1s/XBFBt45t5/vx5vsUbvq+88gphAAEKR1sPNQZcsSD8\n/V/qBCEzu2TRqFEjWrlyJTVs2JAF8MiRI5n1Ll26sGUfRmfKgIJq167NczuNGzdm4Wd2/TJlysTR\nZlAuetjff/8998AhaGH5/MMPP7B6fOnSpbw9depUSFQ9vtQb6mVvmKGz89FHH/FHq1evXvTss89y\npwa96Dp16viSddDTwAIezx/PF3P9U6ZM4TKs9vyDXvEIz9C9XXTv3p0gBPD+QQh9+umnQa09LIyV\n4RFrdLAMBiN0kBnvkC9l9+nThzU8UL1jHyrhYBK0btC4YSSMOWZo4tzxBw54BrBEvnTpEi1fvjyY\nxceZlzv+ocYgTib8uBDV0ZAw+o0vfih6kBgBJ0+e3A9Iw5P0t99+o5QpU5LDEV6lhi+YYW0iBHC4\nCXwAM3RuvJEvdfF2n5yzDgKw3fC08QgmdwnlH8p3KKGyMa2G7xfmp0NFCfEA9XQ4NHJGfc3AwCgr\nMduoFsCJAUzuEQQEAUFAEBAEgoFAeIdLwaiB5CEICAKCgCAgCNgQARHANnxowrIgIAgIAoKA/REQ\nAWz/Zyg1EAQEAUFAELAhAiKAbfjQhGVBQBAQBAQB+yMgAtj+z1BqIAgIAoKAIGBDBEQA2/ChCcuC\ngCAgCAgC9kdABLD9n6HUQBAQBAQBQcCGCIgAtuFDE5YFAUFAEBAE7I+ACGD7P0OpgSAgCAgCgoAN\nERABbMOHJiwLAoKAICAI2B8BEcD2f4ZSA0FAEBAEBAEbIiAC2IYPTVgWBAQBQUAQsD8CIoDt/wyl\nBoKAICAICAI2REAEsA0fmrAsCAgCgoAgYH8Ektq/CpFdgx9//JEQt9idHnvsMfr11185lm1iY50i\nTugPP/xAmTJlcs/a5/1r165xkO8UKVL4fI8kFATsgMA333wTi00EtEesbcSPTmybi5VpAifQ7hFP\n+MEHH0wg5f8vx9cu//33Xzp58iTlyJGD6/H/u4K3Z/CMGMD4dmXIkCF4mUdgTjICtvhD7dy5MzVv\n3pxeeukl1+/69es0fvx42rdvH129epVef/11rsX27dtp/vz5PtXot99+o1q1avmU1luiV199lXbt\n2uXtkpwTBGyLwJ07d1ztrHTp0vTss8/y8bx58+jNN98ktLFQU4cOHbiIrVu30vTp0/0qLq52ie8F\nOu6jRo2iihUrUpcuXQid8GCRJ8+XL1+mZs2aBSv7iM1HBLANHu2IESPo008/df0eeeQRevnll6lo\n0aJ06NAhFsQYza5fv55OnTpFt27d4lr99ddfdObMmRg1/Pvvvzk9BLAnXblyxXUvrn399deED9Lt\n27fpyJEjtHfvXvrzzz9j3IaR+E8//cTnnE4n32Mk8Fb+xYsX6fPPP6cbN24YyWQrCFgGgSRJkrja\nWbly5Wjo0KF83Lt3bxePGCF/++23rmPseHvXcR4jzj/++AO7TLgXwumrr77iYwjB48ePE9oOCG0Q\n7Rhtr3z58tS+fXs+j7+zZ8/ShQsXXMfxtUtXIrWzdu1aWrhwIX355Ze0aNEi2r9/P/OE7wrI4AX7\n6NAb3w98I/bs2UNHjx51CWvwjlHuwYMHXW09Pp6RJwijYXyj3Em+BUSignZ/Iyy6DyEH1RIIKl+o\nwwYPHkx169al3bt306VLl1ioolGgQeMYgnnx4sWUNWtWOnfuHK1cuZJu3rxJVatWpUqVKtHhw4dj\n1XbDhg38wUAvGWXWr1+fBS/SFytWjNwbpHEzGjc+DEOGDOGGiXvwQfnwww9jlb9jxw5OV6VKFe6B\nr169mrJly2ZkJVtBwPIIvPPOO1S4cGEWativXbu213cdghztpmDBgtz+mjZtSp06daKGDRtS+vTp\n+b2Hdqtv37709NNPs0AbO3YsCykIOHS4kQ5teuTIkfTcc8+xOhrt/9FHH+Vz8bVLdyDRzqBFg1rY\noNdee41at27N2rMaNWpwGwbPo0ePJoz8wTdGsDVr1mSBjXY6depU/u6gU58/f37asmULd1CSJUvG\nbd+d527duhlFUa9evejnn3/mTgbU6RMnTuROBr4Z0f4tEAHsek2su/PWW2/RAw88wAzWqVOH+vXr\n52IWDfvEiRPcsNGjhADOnTs3QSUEIZg6dWp69913uUFjdNyiRQtudBiFYhTtTk2aNOGGjZ7xsmXL\nuNHiYwAVNxrp+fPnqXLlyj6NXlGmZ/novWfPnp2ef/55atOmjV9zW+58yr4gEC4E0N5efPFFKlKk\nCAsRCGBv7zr4q169OqHtQmuEDiwEMEbDkydPppw5c1L37t0JQhgjbWiYZs+ezdcgpNA2ly5dytU8\nduwYC3GMXEFz585lgedru8TI130kjTyeeuopFrrY90YYkc+YMYMFLb4V4NUgCE2o41etWkUbN27k\n+nvybKTFwAF8oxMAQrvHaBjfLPkWyAjYeE8svZ0wYQILPl+ZhAoJwnbAgAGuW7JkycJqM4yaQYUK\nFXJdM3ZgYILeL+a5IDwx74XeLbboGaPXCwEPtbQ3MtRocZWPXvG4ceO4Z408MF/90EMPectKzgkC\nlkTgiSeeYL7Spk3LwjSud/2LL75gAYzEMNq655576Pvvv+d70RZBsKHAuRUrVvBx5syZeev5hzQF\nChRwnW7bti0LdV/bJUbYmzdvpjJlyrjyQGf6ySefdB0bO0YbxjFG52j/aPfubR6dDxA0cTDsio8w\nbYUpqh49enAytHd0xOVbcBc1mQOO7+2xwTWojYzGYexj1Js3b14WmgsWLCCMmvHhQEOEGhgEAy5v\nhJ4yhGTy5MnZaANqaU3TCAYhw4YN4563UR7ux8cFPVoQVM+guMpfs2YN9/YPHDhArVq14vkovkH+\nBAGbIhDXu47Rr2GwBfXrd999RxkzZuRawpoahOkgqHnRRiHsDOGO9uZOmAvGCBmEeV+0Z6h742uX\n7ve3bNmSNVqYKkLHoF27dtSnTx8efSMd1NpGG8bIFAR1MwzQ1q1bRw0aNHB9Y3DNk7+4zuE8Rvf3\n3Xcfd7ZRT4x6YQwm3wKgIyPguyjY+B8vMwQfjEUqVKjAc0VQb7399tushoaAhIEIVMqlSpViVTXU\nybly5fLakDACxpwxVGcg5AmVNOagYMCFuSDMMRuEeahBgwbxXFi6dOm4MeOat/JhhAHVOOa2oC6f\nM2eOkY1sBQHbIuDtXU+aNCkLGQhLGF7NnDkzVnuDKhvTSTCMglEi5kZBWCZUr149bnM4xkgT7Q/z\nsdBAQTBCDTxmzJg42yXuMwgjX7TRxo0b8zwwvgcY6WJ6CQL9hRdeoGrVqtHjjz/OS61wX6NGjbhT\nsHPnTh69Ix1+cZEnz0a6NGnSEEbs+OagUw+bFCxNwhyzfAtUZ0Y90ODZohuoy9ZUBNCYMCqFuggq\nIYyEjV425pygWnYnzEn5u5YRRlloTHFRXNe9lQ9jMHeDkLjylPOCgJ0Q8Pauo61hhOlt1GjUzdt9\n6OxCYLmTIQAh3A2Kq90Z1z237m0PhpkY3eJbAWGM8tzzxncFvKED4At549m4D3nh2+RZJ3d+jLTR\ntBUBHE1PW+oqCAgCgoAgYBkEZA7YMo9CGBEEBAFBQBCIJgREAEfT05a6CgKCgCAgCFgGARHAlnkU\nwoggIAgIAoJANCEgAjianrbUVRAQBAQBQcAyCIgAtsyjEEYEAUFAEBAEogkBEcDR9LSlroKAICAI\nCAKWQUAEsGUehTAiCAgCgoAgEE0IiACOpqctdRUEBAFBQBCwDAIigC3zKIQRQUAQEAQEgWhCQARw\nND1tqasgIAgIAoKAZRAQAWyZRyGMCAKCgCAgCEQTAiKAo+lpS10FAUFAEBAELIOACGDLPAphRBAQ\nBAQBQSCaEBABHE1PW+oqCAgCgoAgYBkERABb5lEII4KAICAICALRhIAI4Gh62lJXQUAQEAQEAcsg\nIALYMo9CGBEEBAFBQBCIJgREAEfT05a6CgKCgCAgCFgGARHAlnkUwoggIAgIAoJANCEgAjianrbU\nVRAQBAQBQcAyCIgAtsyjEEYEAUFAEBAEogkBEcDR9LSlroKAICAICAKWQUAEsGUehTAiCAgCgoAg\nEE0IiACOpqctdRUEBAFBQBCwDAIigC3zKIQRQUAQEAQEgWhCQARwND1tqasgIAgIAoKAZRAQAWyZ\nRyGMCAKCgCAgCEQTAiKAo+lpS10FAUFAEBAELIOACGDLPAphRBAQBAQBQSCaEBABHE1PW+oqCAgC\ngoAgYBkERABb5lEII4KAICAICALRhIAI4Gh62lJXQUAQEAQEAcsgIALYMo9CGBEEBAFBQBCIJgRE\nAEfT05a6CgKCgCAgCFgGARHAlnkUwoggIAgIAoJANCEgAjianrbUVRAQBAQBQcAyCIgAtsyjEEYE\nAUFAEBAEogkBEcDR9LSlroKAICAICAKWQUAEsGUehTAiCAgCgoAgEE0IiACOpqctdRUEBAFBQBCw\nDAIigC3zKIQRQUAQEAQEgWhCQARwND1tqasgIAgIAoKAZRAQAWyZRyGMCAKCgCAgCEQTAiKAo+lp\nS10FAUFAEBAELIOACGDLPAphRBAQBAQBQSCaEBABHE1PW+oqCAgCgoAgYBkERABb5lEII4KAICAI\nCALRhIAI4DA+7V9//ZX+/PPPMHIgRQsCgoAgIAiECwERwGFAfvPmzZQ9e3bKnTs3PfbYY1S0aFE6\nevRoojnp0aMHDRkyxK/7v/vuO9I0je7cuePXfYlJ/NZbb9E///zDtz755JMB1TUx5cs90YnAzZs3\n+R3PlCkTtzO0tcyZM1PDhg3p6tWriQYlrnf4888/p8KFCyc63127dtHTTz+d6Pv9vbFEiRK0aNEi\nf2+T9EFEQARwEMH0JSsIoqZNm9L06dPphx9+oB9//JFat27NHwVf7rdbGgj4wYMHk9PpZNZ37txJ\nefLksVs1hF8bI4DO7cWLF/l3/Phx7nS+/vrria6RvMOJhk5u9EBABLAHIKE+hCD6448/6J577uGi\nHA4HvfTSSzRjxgy6ffs2n9uxYweVKVOGMmbMSF27dqW//vqLz3/wwQc8ak6VKhX3tL/44otY7P70\n00/UqFEjeuCBB6hAgQKEvPwl8Pjuu+9SoUKFCKOHQYMGuQQo1OboQKRPn57q1KlDR44c4exPnTpF\nlSpVojRp0tATTzxB48eP5/PNmzfnLXi5du0atWnThr7++ms+t337dub1oYceogYNGtCVK1f4/Jgx\nY2js2LFUoUIFrkeLFi1EVc/IyF+gCDz44IPctn755RfOStd1Gjp0KI+M8a4PGzaMcA40f/58evzx\nx+nhhx/md/7GjRt83v0dXrlyJeXPn5+yZMlCq1at4uv4Gz58OL333nuuY5SBTjcorrbiSqx2vvzy\nSypZsiSlTp2a2/qePXvcL/N+ly5daOnSpa7zH330Eb3wwgv8HWnfvj23HbTFUaNGudL4uoO2iTaL\n7wi+J2i7v/32G58zsENe+D4Bg/hwxHdh5MiR9Mgjj9C6devirT/yKliwID+P0aNHU9WqVZnl+PL3\ntU6WTKcqJmQyAkpdrCdNmlSvXr26PnHiRP3ChQsuDi5fvqynTZtWnz17tq5eel0JOV0JM101SP2+\n++7TDx06pP/88896p06d+H7c2L17d12NMjkPpG/btq2OfJCHUpe58nbf+fbbb/GV0ZXQdz/N+5Mn\nT9bz5s2r79u3T1dqMV2py3XVQeBr9evX19WInfOfMmWKXrp0aT6vhLWuGoyuGqm+YsUKPUmSJPr1\n69d19dHicsCPEux61qxZdSW0dSWE9fvvv1+fM2eOrkYnuhLUrvr07duXMfjss88YG5Q/d+7cWHzK\nCUEgPgRUZ5HfveXLl+sbN27U8T6hvSkhrKsPPd+qOrV6zpw5uV3t37+f3/u9e/fqyjZDVx1d/fDh\nw/wO16xZU1dCle8x3uHz58/rSjjrSvDqx44d05X6WEc7ALm3SRy//PLLuhLu2OU03tqKGlnrSphz\nmsaNG3N61VnXJ02a5MqXL/73h/aN9m6Q6hjr77//vr548WK9XLly/P1Qwl5XQlw/d+6ckcy1LV68\nuL5w4ULXsbGjtHJ8j+qA6EpLx9+TXr168eUaNWro8+bN4/3ff/+d27Dq9Otx4YiESu2vV6tWTV+7\ndq2uOtlx1v+rr77ido9nA77V1JyuOjZcVnz5cwKb/qHnIhQGBCDcXnnlFX7B1ChYHzduHHOxZMkS\nPV++fC6OIJzwEcDH5MSJE3xe9UBZKBuN1WjsEHjICy8v0uNXtmxZXangXPkZO/EJ4FKlSnH+Rlp8\nOMqXL6///fff3HE4ffo0X4JAVT1aFuJqNM7bf//9Vz948CB/vM6cOcPnIOjxQQMZHy/U1xDeOI8P\nBNKpuTkdAhgdDINUL1t/++23jUPZCgI+IWAIYGVroeOXLFky/qijPRlUuXJlXY3OXO1FaV70N954\nQ1daJz1lypQ6jiE08O4bZLzD06ZN43ZhnEdH2RcBHFdbcRfAzz77rK5Gntz21TSOrqaujGJcW3Ru\n0YlVc906BLUarXKnFx1gCC41IuZ6oC7eKC4BjHqp0bcLE7TNXLlycRYQhOiEg5YtW6Y/88wzvB8X\njrgIAfzJJ59wOvzFVX90/CGoDZo1a5ZLAMeXv5HejltRQZusl8CcKFQ56uUn1Runb775hlavXk2v\nvfYaq53Onj3L1wy2YDQClQxUUUo4k+qtk2oMpBqZSy1spL106RIbnaiXldMhrepV0u7du0kJNFZ7\nQ/WN/fhICWdSQtiVBPuYrwav9957L5ePizDiUg2Q1GiXoPpWvW5WTffp04fn2aDKjotQBlRsBmXL\nlo1VfSgHBBW3QWrk71LPG+dkKwj4igCmYaD2PXDgAE9/YD7YoO+//54w5YG2gh/2lYCm5MmTs3pX\nCRyehqlduzahbboT2laRIkVcp2DU5Av50lZUB5VUZ5a/BTDWdFc1G2VAPQz1rhJupEb3pDq0ZEzn\ntGzZkjp06MBqX9WhJdWBMG5LcIvvCObKDUzQrqF2BlaYKoJ6Gt8wpVkgY4opLhyNwmAAZ1Bc9cfU\nlLsRW7FixYxbuGxvz8mVwKY7SW3Kt23ZXrNmDY0YMYLc52/r1q3L80ho4GhA69evd9UPHwt8OGDR\niRcegleNkAnzPRDa7gTBjDlYNB6lxuZLeNlxrlatWoQ5IxDmtOIj3Hvy5EkyPijID5afmD+7desW\nKXUyZciQgbNQajCqUqUKKZUZz5nhQ4WPlxo9QLsSZzEoA1afBiFPpVonNbrgUxDuQoJAMBGAhTHm\nYtUUDb/fjz76KOEjr7Q7rk4pBAs6yeg8QhjAgAttYeDAgWyrsWnTJhdLmB+G8DMIHVSDYNvhLvTQ\nDtFm8I770lbUFBW3dbQ3dAIw76zUv7HaLgQg5p6R3hCGKLd3795su7FhwwbmW00p0YsvvmiwF+8W\ngwMIc9xrEDrG4B/tEh18fMewmsOY144LR+N+dNJB8dUf5aqpJk6HP/eVIQnl77rJZjsyAjb5gUFY\nwcACy4aUiowbOxqQUtfyS48erZrnJaXmZc7Q68OLiBcXS5cgfCHY8KKih+xOGN0ifxhQ4QMCoyZY\nHCNvfCzwQcEPhhkGIV/3HwzBMKrF8gTwh2tK1cSGKxiV4iMG4xTwgGUX6KkbBIOJFClS8L0wHAN/\naHgQyMjLnVAG7sfHDbzCCA0fCXQWhASBUCHQuXNn7kz279+fi1DqVFJ2CAQDK7zTzz33HBsQwugI\nbQ2jQbyXag44FkswElTzxdye8b67j1JhcKSmmThPdC63bdvG90PAg7y1Fb7w3x86CTNnzuQOeatW\nrbgNeevQovOOjizyx+gUpOaAqVmzZiwswTdGsnER+HFv/zAQBW/gHZoA0IIFC1j4GxotCHp0SNT0\nlqu9xoWjZ7nx1V/ZxBCMzbZs2cK4KxW063Zf83fdYJcd9VCFTEYAhlQwcoIhlhJOuhKIuupNurjA\nXBIMrpRaVofRA4yxMA+lhCcbemA+C/OyMBKBIYQxB4wMkDeMlpTA5flWzG95I2MOWL2nPPdqbJV6\niY1O1EiWjVXSpUunqw+AjrldEOZvMAeGOSbMQavROp9XHzauB3hUHzGeQ1IfJL6GOqCumMM25s9w\nQVln8jybUk/xvLdhKII54DfffJPvxZ/nseuC7AgC8SBgzAGr0WeMVDCygq2Emprh9qPWBfNc6lNP\nPcVGTZhPBcFOAW1TdWK5PcFIC+T+DmPeEoZYyoJax7ytMQesBDfPm6pRI2+VQHUZYcXVVtzngJXW\nS1dWyHyv0oqxgSMX7uVPCUSeLzYuoa3Wq1ePecf8KwzIME/sSZgDNtq9sVUrMjgZDCzxDcqRIwfz\nAWNMg4APvj0w9jII36G4cAQPqqNtJNXjqj8SwLAMmOMe2IGgfFB8+XMCm/5p4FuBLxQGBOAFS71Y\nLnWxOwsYieKa54hQGVqxKhgqrvgIKi+oeQNR5ULtrQxXeN7XsyyMEAw1t3EN/KI8qJ89Cdcwl+tJ\nqCdGxwmpxT3vk2NBIJgI4P0EeXtH0ZZURzTO4qDpwQgYdhqeFNe98bUV9zwwMke+UDH7S+AJfgeU\noZa/t3J6qOIx9+tP24wPR3cmvNUfKnzMA0OLB4JGYerUqS7tAc75mj/S2oEsIYCNPkAgwsIOYAuP\ngoAgIAgIAt4RgPob6vKOHTtyp19ZY5NagsX+BrzfYf+z8Q+jglw/9ObgVAHGDzAIMPwgo6cDb0lC\ngoAgIAgIAtGJADRnME6FISb21brhiBa+eMqmCmAso4HhAlQN8PLUpEmTWIZE0fnqSa0FAUFAEBAE\nMDiDxbdyXMLGb5GOiP8TCwEggnVz8HuMtaRw0A8Xh1irhiUygRDM9A01diD5yL2CQLAQQA8elqhC\nCSMg7TdhjCSFuQiY1X5NHQHDpyhUzzDdB0EIw1wfJu2JJeUWjZfkJPZ+uU8QCAUCWJ718ccfhyLr\niMpT2m/8jzPt+a+p7HszKPmtu8uX4k9t4lVlu5vh+EnK89n/1wqbWHrIizKr/Zo6AsbibuV7NMaa\nUKxzVab7ruAE/iKLke/zzz9PWDcn5BsCsG6ENxuoeyQykW+Y+ZsKaysjXSuD9whOHzBaSCzF1X5h\nZQ+bEax9j3bSX3uVnsIKg3gsscOFka7egeJJ7jrZAA+68palqaAWdiez2q+pI2A8FHhUgsB1J7hN\nw3xwfITlKvAK4/mDWTqWAQj5joDydcvLC9555x1STuT5RszPoxODxfDuHnB8z1VSRjoCas2rK7oW\nPCCpNZrswQ1zdu5en4KBA5a+qHW5wcjK9nloqoPjLnz1fftJVw5CrECam/AFP/q8D+nOq2+QfuKk\nFdizPA+mjoDjQgPDffSE4T4tLoI/YwgMT4KXKIziEvJv7HmflY7R04fnGYQg9LaWMNi8QgBjfSD8\nx4LgVg5uLhECEJ5q4Pv5008/ZX6CXbbkZ18E4O9XOWDhtZgq6g57SkJoTNhyYL1mz549g1Y5LEmU\nZYlxwPlIenJ260la9aqktXmONC/r6+O4M+Sntf59iNZtIOdwFQLxyayUZOigkJdp5wIsIYARwzIh\ngr9W/DwJgtdOqj4IO/h8hnNyLMnCYnnE7kRMYBiowdez4TfVs66JPVahiEhJ1ru/3/+gVEprsGPP\nbvr7/Hm6tWo13dy8lcYqn7iZJk4hx6CBzAPcwaFDICQIeCKAThoChBgOHhAXGnFchcxBQFOdIMe8\n2aTPmE3O1u3IsXQhaYlw1BEKbjXlIEirVYP0GtWJdv7f13soyoqEPC0hgNGLjgaC0Rl8nWKkgNE+\nfCFjVK/cvnHEFYwq4BUKARkMUnHI/hOcylPPb+qnhCd+OvYhVHH833nlr+3uObd0pAQuJb8HLn6I\ngLP6rfr+IjUqXITSFClGy9TIO9+DD9C3SZNQZtXBcXZ9hb6vUiHonQCjPrK1LwLoNKq4sKwaRnQh\n+EnGXC38KxtO+YNVO5kDjh9JTXnH0np1J71BXVKhwki5yor/BpOvQhBT+XIxSnWuWkPqw0JazWdI\nUx72hNRjExDMQUAFuaYPP/yQlL9j0jdvoWcGD6X3lPC9MWI0ZVCNaeSG9VT89r+U5vWBdMddsOJF\nvk8ZufwnPHlfCVMNx8b5xzLzvgNClgXtf8L2v2NuDG7V/F0t2+p/4gQbufSfOIHdTWLx+5h0D1Nl\nxd/+Y0do9K7P3e6QXUGAWEsDTQ1CSR45coTdNuK9hiUzAhYEkzAH7N4RDWbekZSXpmxq3Mk5/0PS\nns5PWoGn3U9bYl8rW5qcU94jfc4HpNWtTVrbNuT5bbIEoyYyYaoAxmhv69atXquHiB8wxopUghEZ\nh/fb/wU5q9Umx8SxpGa56N8H0tDgI4fp0YJP04stVP1Z0BqCNFVIVEuwGsccMKInGYR5aIQ4vFK5\nIo35/jKlhPAWEgS8IKCc5bsiaiFEJWw41q1bF68NB0LXIQKYJ6FDipi6bZUBoDvJHLA7Gr7va4UL\n3Z1/zZyJHO3bkpYzh+83hzglDMmSqCkuWErry1eRCtdGyiNTiEu1dvamCmDMcWIZEtSvnpbQ8Tk7\ntzaEvnGHWJqZVai+rzp2plTbN9LcXTtp2uVL9HSJYjRn0gSqWLEi7Zk0kVT0IlesXd9yTlwqd+GL\nHBDcG9asoDttO5J+8BBpRQrzsfwJAvEh4IsNBxzsG0723fOymw2HO+9W3Nfy5rk7P7x+IznfHkKO\n9yaTptq2lQjLlLTuL8ew3dFVvGFSa56pbJmoMr4zVQDD6QZiSw4YMIAw4o02GpryfprxwP20bcpk\nUqEGSYXnY6tnqPSsRFqr5uT8cBElEQFspcdiWV5CYcMhc8CJf9xYGgRDqDvVqtDnar3/I2ruHkEO\ndDW1xVNXic86qHfGsHJXccCdS1cQvTuNtAb1SGvUgDQ3DV1QC7ZQZkmhisTyAswBmkFYMgRL32gj\nfckycjg06rJjK3VVSyysTFrlSqTPmkv6mbOk5Yo7mLeV6yC82RsBmQP27/nBvz6WDkKoQdOI5Yxv\nqIEO1PufbtrEPvhrPPY43Zk+kxzNm5JWprR/BYQ4NZZSJZk8nnTlrlhf9RHpK1aR1uLZEJca/uyT\nwpJRBXenWbNmkQrsTE6nM06uYK2bPn36OK/LBe8I6OfUS7V4KTlmvGcL9Qr3oJs3I+eChbKOz/sj\njcqzZtpwyByw76/YxYsXWejCGv2KmlfF8jB81+FnH57EIIyhbatZsyY5mjUm5/yFRGoJk2PYIMt5\nrdKUZlDr24t49YcbBE5luIpOg6am8SKJYqigIWDjW1OLXqmQfwjoylWfc8hwnvNw92bjXy7mp+a1\nfPMWkK7U45oyuhESBKLZhsPKT3/o0KHsV79atWrMJr7TWHHRr18/On36NDtJge0NSCtXlpKon378\nBNG166TWP/J5q/3FUj8fPEzO8ZNIq1qFtPp1SDNJYxtqXNQal/9T2rRpCcZQMMhBDwr7eHCI14tr\nDiyJEfILAR1zGrlzkaNSRb/uC3diNACtSSPSP1wcblakfIsgYNhwwOkGppLcf8E2osQcMCykhRJG\nACNc9yVbCPUK16BYKoY46xDGnvP0Wv58sZYqwXuVfvpMwgWGIYWjX282LqO0D5Nz0LAwcBCaIr1K\nVKikIXRXr17NHm4OHz5MCBkm5B8C+p69pKtlR1qPbv7daJHUMIbQ9+4j/epVi3AkbIQbAbNsODCK\nE1/Qvj3tqlWr0ttvv01wjnLgwAEaNWoUNW3alFc1YEoRsXWNEXC8OaqBglP5JbijVmroXxyIN2k4\nLmrKQZHjuZaUZO7MGMXrJ08RfnakGCpoowLw1oRQah07dqS+fftSlixZaPbs2cZl2fqAgK6i4TjH\njCPHUDXPouIf25HYCXy9Omr+ehmr0O1Yh2jlGb7Fse78k08+4Y/yK6+8QlizaxeSOWDfn1SNGsri\nWUUlgk9udFzgcS9XrlyuQCu+5uRoWJ9I/bAEkQ0wixX19dbwpkudipxvqTXmCgNNucCE5i6WCju8\nHMZZutcRMBbajx8/nkPWwR8w9tmJRJzZyAVPBJwjx5CmhJeWJ7fnJVsda00bk75pM+nKUYeQPRCA\nsxu4O4WXqq5du9K9qgMYzEAJ9kAhurisXbs2IaIZgmJUqFAhoMpj/b+jVYsYeThnKr/Ta9YS+5WP\ncSX8B9rjj1OSOTPI8caryrnHVdJ37Q4/Uz5y4FUAI0YvVBeLFy9mq10I34TCBfpYXlQkcyoTevhn\nRqQSu5Om1udp1aqSviz6lo7Z9dnt2rWLVzZAiwVVJIxxsNTQTiRzwNZ6WlqVSkRHj5Hz2VbkHDaS\ndBVExmoEr18O5R9bqxizA+J8f6ZlVdQxVNAwrsB8r0FQX+EH2rFjB1WqpB6CULwI6Go9nq6shx3T\n340YP6eaWjfoxLyQ6hVbKfRZvA8iii8i5jYMbxDredKkSYQgH3D8YieCKtXdsMhOvEcir7A61gaq\nOL8IBLNlG6mA4kSPPspV1dVgzUo+nWM4+ACHyijNOW4iqdBzyoK6rlqK1YT5tsJfDAH8qAIUHlO8\nURo1EhKKHwGsXXMOVkuOXupM2n8vZ/x32OOqptZ+a6VLkb76I9I8VFP2qEF0cYkwlwgZCOOckiVL\n0qFDh2jEiBG2AkHmgK35uNABRyCFGPTHH3SnRx/SKldU2jK1TEitnrESOerUIlI/XYVf1ffuj8Ea\nvtnhnC+OIYBLly5N+MEIC/6af1G9HKwLhresHj16UOHC4hs4xtPzONCVqkPLqmJ1Vr+7Hs/jsq0P\ntZbPklM1Ml3NCYfzhbU1iCFmHtorz7i8cPsKwnnEnRYSBIKNANxbOnq+Qv9r7yrArai69pq58tti\nfIqFgpIipbSAlIgo3SUI0oiFlICUEgoiXQLSCCqIioCUdGMhZWK3oPJ9Kmf/692XOZxz7px7ak6v\n9Txz78SeHe+cmbX3SrXmHXJ16qbTDZqdHnS6mYjrM26+mbB5EXuqnH6DI4hh4sD+0dkZzKr9B0hx\nWXNgf68qIjmw1QGPHj2aBgwYoC3pEN4MEVTAmIX8IwCzffXuFp2j03+p5L0CQwe6tQipN1cl7yBS\nvOeIgAQJlt2GXL7JRKIDTqanRaSTQDATNl99mQyfmAewqFYQWScicc5irJDV1u3katpSu43adVO9\nu5lc4yaQYiMvJ8lrBWxVDCduZC7ZvXs3IcwZLCinTp2q44paZeT/WQTU778TrJ5N1pEkUrDzsz10\nZg+Wka6Bg0nBupsDvgslFgLwm/XnO4t0mMlEogNOpqd1tq9a/5o/39kT2GNrfFcfXjWyd41R9U4y\n7r0nYaRour93VqYM3hSL0okDwIBWrlxJpUqVojp16uhjZGkyeQHiGjgk89ihv7YMGMZWEDk3bNhQ\nuyDlZQV8vI044FrxzDPPZBk2nM+LFi2a5XwsT7hGPZfpf5aASbCdxEHnFs19vXZLMu6u6WTVUpeD\nCGD1iNSSyLIFbwYw3zJlymjDLAebiWpVogOOKrwxrdzAKhPJH/bs1VJCQhjMBMy0hrgHBEkf07nn\nnksX4PgMwchMWQcO/rdlwI899hitX7+eEFsU4eCgC0Yc2HgS8uVWqlQpSxc6d+6c5VwsT7hef4Po\n51/IGDY4ls3GrS29Cn5hIpEw4Lg9g0ANwwIa9hqVK1emAgUK0IkTJ/Q7HOg+uS4IRAsBLTErW4YM\n3nzpdM/HOF5CITLKl8sSHtO3bKyOM1jChy3aZKsDRsNWYG848vfv319n1Ih2Z7KrHzPic845J8uG\n+NRajJDdzVG6plg8r16czUr5fmkjkjVuK0k8NSS1ZWuUUJVqI0XgLxalYcJavnx5nQWnXbt2OqhO\npPVGej9W476bv+QvogOOFO3kud98/GHiYNXkmjyNTrdqm7gd54A2EJ87SbYr4F69etHq1avd7YAh\nI54oQlMKZSKgOOyZdjnq2IGM669PK1jMVpy2cv4iymC9iFDiIQD7DdhtIP4v/iOFKERq8SSokJC1\nx5eQradYsWK+p3VIRfEDzgJLSp5AtjWdcY3jPPsaa2nLY04QYZQvyx4meeM6flhII0uck2TLgK30\nVmgI4ivkAUUQdqGzCGDlS7mu0hZ0Z8+mx54Bxsv5RNW+/aRXxOkx7KQZJfS9I0eO1BnM8P8dTsge\nbz9g2JXYBfLp2LGjbQpU0QEnzc/N0Y4anInPi/LcSMShJV2DhmYG0njwATJTSP1ly4DPO+88wgZC\nqquWLVvSokWLxBXpzC9DHXhP+7yZs6afOZN+/wysghfwKhgiaaGEQgAxgX1XmwjMgTjBQoJAMiFg\ncAIRo0c3oh5ECuFUf/jRq/s67jPKJGnMfVsGjBf4ww/ZUo0JFpRr1qwhiKWF+EfAHzLEQjX79SaD\n/S7TlYzq1UjNeikza0qhgukKQ0KOG94LtWvX1n2DSyFiQkOnmkyE/v7KCUDy58+fTN2WvkYRAeO6\n64iweZD65x9SCDPJrk5UsgSZXTqScc01HiUSe9eWASOh8z88MBCMnOrWrasNOhJ7KLHpHVIMal+2\nBDSjjw0Cma3AqtFo3pR1wQspg1MuCiUOAjly5CBsIEiw2rZtqy2ik2kSLX7AifN7SuSemEi8wBti\nMSh2c6ITJ4k8GLDauYuoQH7CSjoRyYsBI/oVHJDtCNbQ8Xb5setXLM+53mbDtONfkTGgXyybTdi2\nYJCAxBOK/U21EUXC9jS9OrZr1y73ewyrY0izks2GQ3TA6fWbjXS0OmsbS+V8SW3fSWr4CCKOT23c\nVoKMrp0TymMlCwPu06eP1hXB+ApMF4meEQADgd3TmdQ335CaMp3MF8aQcWZ1kc54YOyICY3k12rh\nEjJYJC+UGAhcyoYsnklVKlasqCPbJUbvpBeCQOwQMB95iNTDrEA+xokY2GiUExsQJ8jWHYD4GsFB\nqFjRgFne1MGPdShKZohkjmcpKCelAKlvvyVXF64feugqlclsd78+H+wfLwZsGV8h9eBLL72krShR\nUevWrWn27NlZDDuCbSTZy2mXo+EjyWBwjTx5kn04jvbfqF+XXM1bk/r+ezJy5XK0bqksPAQQfANb\nMpPogJP56SVW33WcCA6PafiGyOTYEq7XVhAN4wiLHAHLKHUbmQ+2t+28a/QYMqdO5JjR20jNW0BG\nl066nNp3gIyWzcngFIfhxKPwYsBWy/fee6/WG7Vq1YpOnjxJs2bN0q5I1vV0+w8xK110IZkN6qXb\n0AOOF+HbDI4NrRYvJQMzTaG4IbBixQoaNGiQbfulS5emmTNn2l5LxJOiA07Ep5JafTI4sFPG6BGE\nBRYdPkJY5YJgZEvs6fIj59V2ExszGvAMKlyIXJwRyU3wiPn8C50lyWjWJGS3VFsGDNEzDLHgP4h4\nmEjqXbZsWXeb6bSjPvyI1Mo3yXxxWjoNO6SxGpyi0MURbFTb1pTFjy+kmqRwJAhg4lytWjWd/3fc\nuHE0bNgwNhq9TseARqakZCLRAYf+tGCLoSfCPCE2mFEIBYeADpPJbkyWK5PRvw/RqjcpZ86cWSuA\n2PqM+BkXoXqDobJibyFkU0Le4VDIlgGjgvr16+stlMpSrSyyY7hYgW/2fjxhregSAXNtAHFXDVJL\nXyGDI4MJxQcBhGqF1fPOnTt17PZbb71VdwTBLuDJgAQNQqmLgOvpUWTcXpJcI0brQRo1a5DeOBKa\nUPAIaFFyzkvo/9jGxU3/+Q8pTiKh1q4jo0J5UnDr41WxevkVUsVZh4wAImFERPRiwC+//LJOZ3bo\n0CF6//333W1jB7Gho2GIBT/FeIfJ8xqox4Hi/I8IHm6US8/VvwcUAXeN5k10Mm4FfYjHDDHgjVLA\ncQTwnoLpfvfddzqk4+LFi/XK2PGGolih6IBDAxc2GPCFNTo9SGZnji7G4RvVmnfI1bEr0U15ybj7\nLjI45V52CedDazG9Spsjh5N6aR7RVVeSCe8Pxpf1s2R0fjDTE4QlxeaYUSGD4sWA87CBEXQvN7Hs\n2/IjtGq8xsO3yjoX6n8EiR81ahTt3btXh8pDfGmkTIN+CkZf55+xTgu13miUd63foINMmDOnRqP6\nlKsTBljIZqKWv05GqxYpN75kGhAyIc2YMYOsgDqIZNekSRPHhwAPCUygPdO2OdWI6IBDQ1Jt2UYG\np/yzDIEggsamunch2rGTXKvXkpo4JTPjEDNjpAO0yobWUnqWxqLC6MZYniFPEb9lkGVdC+W/6VkY\nMWTBhJGIGBFomjZtSt+ymfWPP/7oiB8hZuKgfv366RU1kjt89tlnOs3g8uXLPbsS133FM0nFKffM\nQf0TJnF0XAEJsnGjZTNSr7xGCqb+QjFHYM+ePQQp1o4dOzTzRQcgksb5adMit2GYMGECwUMChPpg\naY1c3BBtgxE7SWAO0K0JBYeA2ryFjIoVshSGoRFit2dwulRz4Vwi1nW6XpxDriYtyDVthvbhz3KT\nnIgZAl4rYKvVp59+Wr9QWJ2++uqrmhljhYq0ZpHQwYMH9cuK7CdXsmN0hQqZP5g777yTXnnllUiq\nduxepEdzDRuRaVqeL59j9aZDRQaSWRe5hdSbq8gQi/GYP/L/sJ4KgTewerz99tu92kdGpEjpa47F\niwn6n3/+SdOnT6f9+/dzFrmLaMiQITp2ADIvCcUeAUSBgp8rlfJ+5r49Qehc/V7yu6m+/DJTRN2r\nL9Hll2fqimtUI9hzCMUOAdsp5vbt22no0KH02muv0RNPPEGPPPJIFp1wOF1s0aKFNg6BPhkfiE6d\nOmn/YlhdN2/ePJwqHb9HLVhElOMcMtmkXCh0BEykFFv8cqZpf+i3yx0RIADmCCnWzTffTDdyijdI\nsC5k0RlS/hUvXjyCmr1vRWKHEiVKECyrsUq97777WP3IsXgdJOiAjx496mCNqVuV2raDjNKlQgoQ\nhMkyfF7NlxeyzvhBoqPHtCfD6f4DSW16l3SQitSFLGFGZsuA8fI+//zzOon3HXfcofedcEMC0920\naZPW/8K3uHfv3loHDP/EwoULxx0UBV8wFqGaMEMXCgsBoyAHgLj+OlLvrAvrfrkpcgSQexerUTBF\nTG5hW+HE6jR37tz02GOP6RgBa9eupa+++ooOHDhAXbp0oUaNGkXecY8asIrHREIoMAJqy1YiG/Fz\n4DvZjYZF/UgpavZ9gsxli3Wcexe7Xboac7YzTnKgPjoYTDVSJkwEbEXQzz77LE2ZMoXmzJmjsyGB\n+TZu3DjMJrxvQ5g8SzxWs2ZNwhYMHTt2TGdl8i0LsbYTBmLqv/8l19CnyXy0JxksyhMKHwGTjbBc\nrEOnFMrbGT4asb9z69atBDUSsiDB+AoTXUidIqXu3bsTNqimwHixugaTnzt3LhUpUiTS6r3u14yB\nmYNQ9gjgu0X7ORrTkyxKjpAQaMJgd0KCSyHb/cDlBslnODNPphU13JquvjrCVuR2TwRsGfDfbETz\n3nvv6QAcsKRcunQpIcUZdEzRoLFjx+qk3I8//rjf6uGqBL2xLyF8ZgZn5omU1ITJZBQvRkblSpFW\nlfb3Y0bNprGEmTkMQIRiiwC8GBYsWKDVRgiiA31tPgftGSAhwwa6LMgsM7/99ht9yXpHX/rll1+i\nYkXt207KHiPbz61FCBHpnCSDv7UIsUi8acngmrWZMY/z3Mj6YnZp4rjHTrfpZP+TpS5bBgwXhjZt\n2miGi9Ul3BhgXQlxllOEdIfQH4F5QhcciCD+wuZLyFUMw6lICBaEikOKSbSrSFD0vtdsxSKs+Yso\nQxiwNzAxOIKtBfS0iIoFK2W4/Y0YwRlhokTBTKA//fRT7Wro24XDhw9rt0ff8+IH7IuI/bF2P6pU\n0f6iQ2ehVsKm4IYDlyb2L1aTp2bGSIBLExt/GQlusQ5vG8umoFy5ctp+wSF4IqrGlgHDaANMcdWq\nVbryvHnz0rZt2yJqCDf/y+G6+vbtq427cAwGjJUtDLCQhSkepH7+mVxjxpE56pnMWJ/x6EQKtqlX\nvjNm6QwkekWcgmNM1CFBfIuPzZtvvknwvX/rrbd0KFm4F0aDgplAwzcZmy8hYIjdBFr8gH2RynqM\nGMaKGaLZNfACJuvdoZ/RIRvZ1ziDN8UTPLV+I7nmcHCKUc+RAQvqWjXJYF6RiDR69GjtdYMFH/gQ\naN26dQR1DVQpPXv2zBL7IhbjsDXC6tChg9YdIY8o9DsPPfSQI2HsYNgFQqStTz75RH8k9u3bpyP2\nLFy4MBbjzdKG6xkO39aogZ7hZbkoJyJCwMAqGFblQjFFAJNlMGF4MoAQF3rMmDGO9gESLATiAMEV\nCZuThP6LH3AARFn3y7oAMtiNKNZk8PM2695HGZPH6xStHLeRXH0H0OkHu5CLQ9KqX3+NdZeybQ/x\nLH7lPkGieznjBYlu27ZtCak6EUgGcdQhNYo12TLgKlWqaEd7hLRDQGrMpK8PI86l72C+4Zy60CV7\nRtlCvE3EqT1+/Lhv8agfu15exvkh2cCAXWeEnEfAQILsrzmP8qHDzlcuNfpF4KOPPiKI2cDEQPjo\nOBEoAyuHXr16aevkQoUKETbEmx4+fDjb6XCQeqGYIqA2s41FpfjbWBjMG8wOD1DGkgVk9uDQl599\nTq7729PpfgPItWFjQgTmgToGvGfRokXagPC5557TAWtwvmvXrlS+fHlavXp1TJ8fGrMVQe/atUsn\n9H7yyScd7RDyCkOPDJcFS58Lxjtv3jwtDnC0sQCVKV6Bw+fXnM7GV2c+VAFukcshIgCRldG8KeuC\nF1LG8CEh3i3Fw0UAKp3KlStr5ogEDTCibNeuXbjVue/zlGBZk2gYbMI1CRIsrCicItEBB0YStivm\nxHGBC8awhFGiOGFTD/cgbVuzajUpdmfScahZX2wUzUwQEsMu6eA0MEzEIrJq1ap05MgRbUToGUIV\nPMBOFRLtftoyYKQxGzx4sNtdyKlOwP0IISfhHvHBBx9oYG5gh3DI4p2I1BNsPxEq0TWUdb49u0sS\n+WBBC7OcUZsDl8+dr0PeGWcsZ8OsSm4LEgGEn4SfLqLYwWUIKiQ7/WuQ1bmLQYIFtyaL+eKCJcHC\npN1JEh1w9mjq3LUsnTQ4bWwiksG2PUaN6kS8KbZ01y5NzIhZFJMZdQvMmCUzsSCoMhCeFaqZ/7Lb\nFlQzv3P0MASZwuQRLnWI5naSkyvEmmwZMETPiO+K/5Zup3r16o5kVIE4DIYX8SQ1ZToZBfKTCRGp\nUFQRMFjFYDRuSGrhEp07M6qNSeUaAVgcIyRlMMZRoUAWSwkWViQimfL/dLSLXwKIn/338OwV6KiR\nrJ54UxxxS61eQ65uPTlgz/WZhltwaWJDqGiSpSaxJo/gQTDIggV/Lk4kg6AyFq+LZj9867ZlwFip\n+oqf7XxwfStLhmPFfnNq23YyZ89Ihu6mRB+N+nXJ1bw1IWUasiYJRRcBhJAFZedXH04PEkWCFU7f\nU+0e9S6LnwcPSLphGfnzETbVtTPRrt2ZWZqmTCOjTGm9MiaE1GTGGA2ymK9Vd/v27QlbPMmWAcMy\nLBVJcTAAF5vMm0MGiRN5DB8wHPYNtphUi5eSwbohoegiAAMsrFah67KC58CVENnHIqVYSbBEB+z/\nSanPP4dPJxkOBlfx31p0rmgmW74cZfCmXZo2bGKPCc6WN3oMGdWrZkbeSuLxBYuaLQMO9uZkK+ca\nMZqM+2rHxRAg2bByur9Gk0Y62Ltq25oMDkcqFD0EYE+BUJSeBDFbMpHogP0/LR18I8zYz/5rjd8V\nuDQZde4l4k2xnYHiQB+ugWy0iYl7TQ5/eVf1uLhaxQKRtGHArtdWEJ04SUbbNrHAVdrwQQBpzhBn\nVrGPoNGxg89VOXQSAeTyxpbMJDpg/08P7ke+wTdgXISIZyC41CSrDzWMyox29xPxpt7/gPXFHAKz\nLX8vChfK1BdzZD3YlaQKeTHgAQMG0MqVK23HBvehzp1Zbp+EpNgSVM2ZS+aUCVHTLyQhLDHvstG8\nCbk6dSPF8WWjbXQR88FJg4JADBBAkgSOXERUrKi7NTBfhB9FvG8EOILlOyx+EWUwmcngMWLTLk0c\nVx7MWD0/Xsfr1ytjjt2f7GR6DgAMeMuWLTr2M3J8IoQdGDJmVLCITkZSrCtxDXmaDA7XhtmV0+4S\nyYhJvPoMAywDOp/lr8erC9JukiAg+YDtH5QOvsGhID1jLyM4CoIZIYsdXM/wrUYCjlQhrHjNalUp\ng8MFmy+9yNG/biAXJ885zYadrtkvkfr666QdqtcKGJmFsL0rt1UYAAA3vElEQVT77rs6cLplwAGD\njtmzZ+uIN8kwUsS/hSUoovPU//4nujj39eRif7QRrBd7++23afPmzckwjJTso9GyGbke6UWKdcLJ\nLkpCqNbt27frwO7wj4232G/FihU0aNAg299N6dKlCXm3k4VEB2z/pOB+ZLJbnychJGiZMmXcp7B4\nwncuFUm7NDVtTMSbDqYEEfVDjxJBdA19cbUqBJ1yspDXCtjqNOJiIqoNottMmzZNuzPcfffd1uWE\n/o9weYULF9YWoBcePkKr+/ajw7Xv1nlLYd3tREjNhAYgwTtncOAVKnILqTczE30keHf9dg9B3GvV\nqqWT3SPS1B133BH3cIx4byHBQgpCKyXhxo0btd89ImMlE0EHHO8JTaLhpRAogr9pyD7kSSVKlNBB\nJeD7jUUHFkvFixf3LJKS+8bNN5PJGZrMZYvJbMPhhDmjHdwdTz81lNT2HYRkFYlOtgwY+l44KmMl\nDFcGvNCVKlVK9LHo/iF5BD5Egzm3cMNjn1G+GdNoPP8gr+UZ0p133hmXcGNJAVwMO2ly7G21+OWk\neEH8wdKjRw+9ymhVoQItW7ZMx15GzPR4EsJOIgrWzp07dTpRxGlGvl68y8gPLJTcCKit2zJT//kY\nIeH5ws0M2a4aNGigmW/Tpk2Te7Ah9B7ieKNsGTIHPUnmywu1T7Fr0cvkasTStomTSR05GkJtsS3q\nJYK2mv6RFf1LliyhTZs26f/QDSOItSWStsol4v9Tp07pOLich43MqRPpKv7/zevLE7Gradsn5Bal\n668j9c469vermZQ43HzNtXTzyrfIxaH1MgYPpDx58hB+e4lA0AHio/wdG+tAlLt48WJHotjFcmzi\nB5wVbe1+xFGjfAmSgkmTJvmeTstjHXPg3nuIeFP8+9dW1EOGI2Zqpm8xXJr4nUgUsl0Bz5gxQ8+g\nkTQBjvctW7bU6ZsSpdPZ9QOiNsS+3ceK+e9ZHINVb5UqVbK7Ra7FAQGzVQsdnjIOTUfcJCKpDf3q\nW62e+a1TBy32feSRRxKGySHuM95hWMNiEo33N175tsMFGxOHm1nEKJSJgOKJHnH6QaNcWYEkSASM\nq68mk91OMxa8RObjj+jMbK4HOtLpJ/qSa+07pDENsq5oFbNlwB9//LGXUh/ijd84ilQ8Cab2yOno\nu8HgykqwjP4VLVpUJ3uAZeCjjz5K/fr10wG3rb5jNSAUfwSM20oSK1AJRiXJQshxenrwMHJNnkYF\n582hLxrUpZYPPKB1bkgBmEjBLsCER4wYoS1jGzdmo5U4EyYDsCnx3Y4dO6bzs3p2DxnSPHXAvqlK\n0/KYwzbSLYW1gVFajt/jBxLO+I1bi2gmDH3x17wKVus3ZoqoFy3JkgrXt36Pph3ftRVBd+jQQWc9\nQWvQqcKieNWq+BrN7N+/nyZMmJAFAOi7kJfUk8qWLUsbNmzwPCX7CYiA2bqFDj+Xwc71iU4upFWb\nNkNH7DGe7EtGjhxkpedLxL4j0wt00sj2gvcX2V6gI4wXYZL8559/Zmke532NrWBM5Ely7OLUfsj9\nmxkiWPAI//cBzwvFKrCMmncRQhPTe+/rxCXZ/d48rzm9b7DjtkLYuhdfZP8qD4LxFaw74ZYEFwuk\nDUxEgq4LeRyTycUiEXGMV59Oc5Qbk+ND6xVxvDqRTbuKpS6uZ8cS/XWKzN6PkcF5RYMhZFlBNKo6\ndeoEU9zRMgjCgLSfcE2B5ApqGLgnwY4j0cjf+ys64LNPCta8rvqNtQ8s3HCEoo8ADHmxkPPn1udU\nD2xF0HA9gjk7MiIho8rPP/9Ms2bNcqpNqUcQcCNgtGrOq+DEYwyKV2GuJUvJ1YUnBxw8xJzMEXiC\nZL7uwcVpB+JwJGSw0vnBjuN/0CEmEYkO2ONhsXsN5c6dsvGQPUaadru2Iuh169bR1KlTadSoUVSz\nZk2dvDiWcvG0ewppPGCDczKrF+eQYv9GbR2dAFgo1ku6RvOq9+KLyJw2iWDMkUzUvHlz7QkANyS4\nJkGS1a5du2Qagp48WBOIpOp4FDqrrZ8rJb6aJgpDT/kqbRkwRg0RVps2beizzz6jggULpjwQMsD4\nIIC0ZEbzpuSav5Ayhg2OTyfOtKr+/lvHDFes7zW6dCQzSV2k4Au8du1aHZYQxk/wCoBRllByIqA2\nc+7fF8YkZ+el19ki4JcBw+d3zZo1Oq8omDHk4UKCQDQQMOCzN28BIWmGceON0WgiYJ0KxhjIRcoG\nGuZsNrZK4pSJGzdupF/ZYrtTp07ucYMJ2xkxugsk2I7ogDMfiPr4EEtiLibjuusS7AlJd5xAwFYH\nXL16dS26ggHWyy+/rCOrQI8kJAhEAwFYJhoc31YtXBKN6rOtU7FlrmvMOHINH0Fmj646mk4yM18M\n9uDBgwQ3vJEjR7rHjrjVyUSiA858WnDTM1Io928y/QZj0VdbBoy0g1YqK7gI4EVO1lSEsQBR2ogc\nAaN+3cz4rd9/H3llQdaAj5vONcpicHPuLG1sFeStCV8MLlIQP8Ol8G8WrScbefoBJ1vfneyvp/uR\nk/VKXYmBgJcIGqtdRJ85dOgQvf/++149vOuuu5I2JaHXQOQgIRHQIeTq3MsxopeSwW5J0ST1yy/k\nemEi0Wefk8lhJOGkn2qUwZOKKVOm0OjRownZcWCMJZRcCKgvvyTiAERGgfzJ1XHpbdAIeL2ViGcL\n0Q8yqeTgQAOeJCJoTzRkPxoIGJyi0NXmAVJtW0dNB+t66+3MgBr16pAxoJ8OqBGNscSzzltuucUd\nXap37950I+vV4dmQTCQ6YDoTfEOsn5PpdxtqX70Y8Ouvv04rV660rQMZkooUSb2Vgu1g5WRcEIDu\n1eC8zWrpK2R07OBoH5C0WwfU+O//yBz3HBkcXjXVaM+ePfTpp5/qoDnIfuSZAen2271T2DkxduSh\nhX/xBRdc4ER1XnVgIXB5mgedgPuRybHGhVIXAS8dMLIeIZ8ogrdDbPXWW29phly+fHkRP6fubyCh\nRmY0b0Jq5ZukOMa3E6QDanDqQ1e3nmzMcgeZUyakJPMFVvBcgBTryiuvJDBcz80JV0JYUSNFKQjB\negoUKKBjr99///2OB/pIdx2w+uknTh7wNVHxYhpv+ZOaCHitgGH1jA0v2UsvveROP9i6dWsdcH74\n8OGpiYKMKmEQMHLl0sZQavnrZLRsHlG/dECNUew/eWnOpAyoEerg33vvPb+h80qXLh1xVrCvmSGA\nwSOm8/Tp0wnx2S+66CIdZ3ry5Mk6+UmofZby9gho46sK5Qm5boWigwBipCNsK2JrP/XUU3TJJZdE\np6FsarV9uoiD2bZtW525BDNdhKO8++67s6lGLgkCziFgtGxGatmrhMAY4RDuc3HiBNcTrONt0pAy\nnh2ZdNGswhk33ltIsMaPH6/tOCCChk8w4i0jTadT9Mcff1CJEiX0BwteEpCW/fDDD05Vr+uBDvjo\n0aOO1plMlWn3I4l+FbVHhgkkXPWaNWtGmJw2aNAgLhn/vFbA1miRNSVnzpx6dgD9Dl7oaAXiwGz6\nwgsvtJqW/4JAZjCOIreQenMVGQ3qhYSI4ri50PUahQuROWcmGfw7TheCpTOiYCFDGKLYIRQlCAy4\nbt26BFFxJJSb4xEjuxI8JeBr/NVXXxEYZZcuXbRIOpK6fe9NZx2w4gkOHTpMVDp+2at8n0eqHUPC\nu2PHDq2uAb9DxMf169dTw4YNYzpUWwY8bNgwGjx4MLVq1crRzvz+++906tQpd51Y+teuXZvefvtt\nLcqCOEtIEAACZuuW5Bo0hFTd+wjhKgMRPlpqynRSnDfV7PUoGWXLBLolZa/XqFFDM93vvvtOezUg\nB3a1atUiHm/37t0JG/yLDxw4oCfOWPkiZanTBprQAadrLGi1bTvR7bcRAtQIRQeB6ziyGIwILcJE\nEjYNsSZbBowXGLNl/LeYIqJjRfoSI7nDs88+q41D8HIhjSAScmP5/+CDD+qgAbEGQNpLTAR0Yobr\nryO1bj0ZnLszO1LvbtZ+vUblSpkBNc4/P7viKX8NcZ9nzJhBS5YsIUTAglElUoo6RXBrwga67LLL\nnKpW6jmDgNb/Vs7M/SugRAeBevXqUc+ePemRRx6hffv2aQkO0vLGmmwZMKwnkYrQk2BZGSk988wz\ndP311+ulPiwqc7HBDUTb27fzjE9IEPBBwGzVIjNghh8GrANqPD+e6MvjZHIiB+OWwj41pOchXJFg\nUIIJbywIuY8xmYatiFOUrn7A2u5h7z4y+vRyCkqpxwYBSHeh5kCeA7i7fclBT2CAHGuyZcAVK2ad\nff3777+O9A3+xFhJt+P0aAiTJyQI+EPAuK0kEa9mM+PhegckcLF+WE1nHS/riI2nBpAhkZ7cMMK6\nE+QkQ3RXbrPjmfTB5rI+hch6EIX70u7du7Vlte/5tNUBswqF2H7BEHWc70/C8eNatWoRtniSLQPG\nihQv72+//aZntogli6U6Mqo4QYUKFaI33nhDu0xce+21TlQpdaQoAr/VrkUHuz1EY2++UUtMJvZ/\nkoyx44j+/kenaDPYLUbIG4Fy5crpLGZHjhxxuxLm5cAjUPM4Rf/8w/izBTRCXlpqquzqhs6tTp06\nWYpARG5nhJmuOuDM3L9ZF0BZgJMTKYGALQNG/FgE5Zg5cyaNGTNGbxUqVHB0wAh1OWLECF1nMCIs\nhNKDcZgvHT58WGdr8j0vx8mPAAz2ruIV7sflK9GMLt1oyqOP0uH1tajwyKczV75sRyCUFYGrrrqK\nfPVZCNIRKUEK1rdvX7JW2GDASNrSvHlz6tOnT5bwtZ7tYUWLgD6+BDUUxNdCHHqSjYJggGV2bC9w\npAkCtgwY4eVgdAXx0PHjx7WD/dSpU7XxVDRwCUaEhf5g8yW4WMgL7ItKahzDTQCGEvkbNabT7TpS\nvwZ1qd17+2h+w/qpMcAojQKGUfPnz9fWyvA0AOMsU6YM1axZM6IWkWEJhGQtVqx4SMfgmrRw4UId\nOyCiBjxuTksdMOekZiMZMniyIpQeCNgy4KpVq2qRM3yi8NJBfJUvXz5HEQlVhOVo41JZUiDwf+yG\ncfLkSR1CMmP5UvrjxhtoW/HiSdH3eHYSAThgCY3gG3CtOHHihCNBBr755httTW0xX4wRzwg+xrt2\n7XJ0yOmoA9bi54rOShodfShSmeMI2DJgzGjhlIwUhIhGA10wHPsjpUhEWJG2LfcnHwJQe0AdAskH\nVsKDWrWkgQMHJt9AYtzjvziOdpUqVfQqddOmTdrWAq5+sOOIhBCSFkaUjRo1IgTlAEFCNm/ePMez\nLaWjDlht3kLm2NGRPCK5N8kQsGXAMKwA8wXhhXOKYinCcqrPUk/8EMBHeMWKFTqrD1xrxo0bR5DO\nCGWPACYsj7K+HGJh/IdOGLraSAnuiXDbgAHlBx98oGPo3nDDDZr5og2h8BFQh48Qp5Ui48zEJvya\n5M5kQsCLAcPwKrt0hJ07d45obLEUYUXUUbk5oRBwOiJbQg0uCp2BvnfkyJHaAhr/33nnHbfBY6TN\nIS847C5AiBUAf+NoMN900wFj9WtI7OdIf55Jd38WBgxrRmQ2gd4Iq1+E60IADUTFipRiKcKKtK9y\nvyCQzAhUqlRJdx+GV5EaX8UDh3TTAevcv32fiAfU0mYQCCCtKfEkiUO/kVGsqPsOxe54asNGfWzA\ngC7EYEBe2ZAQCQTB3JGOEKIr+O5BxGSlI3S3GuaOJcKClSZEWEifBh9CuBhFYxYdZjflNkEgKRGA\nuL44G6nZbU76AFvgIP6zpQu2zjn1H+oHuDmlAylOasE5HskoVDAdhpuUY1Sc4EUd+4Rc4yfpePPu\nQbz/Aakly4h++pkISTRCJK8VsHWvlY4Qoj9Yoc6aNYuee+4563JE/z1FWBFVJDcLAoKAFwJ4bxFl\nDrFtoS+H3zwm0bCKjkauU8SYFoocAfUui58rekd6i7xWqSEiBP74k+CpY5H68CPKmDebFMebd82d\nTxllSutLyL5Gudj+gfkkIpiFSrYMGKJnRKiC7ija6QhD7bCUFwQEAXsEop2O0L7V6JxNJx2wFj8/\n+EB0gJRag0bA9fZqUtt3EmFVe+Qo/Vo0M52nroBjY2i6mDP2gdladENuMllyoXOQ9x1AGZNesK4E\n9d+WAe/Zs0eveH/88Ucd5AKWjwhD6VQoyqB6JoUEAUEgLASilY4wrM6EeVO66IDVzyy6hAi6eLEw\nkZLbwkFAcf5fFgt5Bz354kttCGf07E4GZwP0UouyZ5AO+PT1N2SwWtZNiEHPz85AzPpJU92ng92x\nZcBDhw6lp556SjvyW3oYuCYJCQKCQOIjEO10hLFAIF38gHXwjfLlgsp5HQvcU7kN5ApHEhdCxLGc\nOcl8ZqjXcM3Omdb9XifPHBj3tybXw5zt6+uvyZw6kWC1rljva7D42fUoG89ddikZXfzfb1cnztky\nYOiLEPnKCd9Bfw3LeUFAEIgOAr/++isNGTKEECcdoSihSnr99dd1wIzotCi1houADr5Rv264t8t9\nfhBQLL2l334nI38+dwn1zbesa69AxsM9yOAUhKGQec/dpO6qfjbrGqfntSLRm+XK6qqMMIwGbRkw\nQthhu+eee3SuRNQOsZYTrkihDFrKCgKCQOgIzJ49m0qWLKkDcSBUJAgrymSidNABK1jNHvyY6Jms\nSWaS6VklSl/V99+TWryU1L79RL8z84Uo2YMBmxFOdPylPA2H8VqY2TLgW2+9NYvVM6yXhQQBQSDx\nEYAEC0nG7dL8JX7vM3uYDjpgtX0HEee8Ns5MkpLl2SRCP7U+9osvyCsd6WefE12di8xB/cm4+eZE\n6GbAPtgyYLvUg4jjLCQICAKJj0CJEiWofv36tGrVKp1IBT2+6aabKJisY4kyunTQAWv9r0S/Cukn\nB0tl2r2X1O49ZJQuRcbA/u77DRYFY0smsmXA27dvp8cff1wnYcBMAynHEMhdrKCT6dFKX9MVgUsv\nvVTn8PYcv5dFp+cF2Y8LAnBboT17yej1aFzaT4ZG9SqXbRiMMwbACu4/zHypTCkyu3cJWY+biGO2\nZcDIQIO40DNnztQv8pgxY8huVZyIA5I+CQLpjgAMKH3Th8ZbgoXoenbBfBAN75ZbbsnyyFJeB8wr\nOGL/UYMjDwqdRUCdOsW+uCya37qdFE9QzIVziXUpugCw8lzxnr0refdsGfD/2OkYGVV2796t040h\nLOXUqVMJoSSFBAFBILERAPO6n/0Yv2AdGaygwXyRoAERseJFmMDbtd+jRw+yc3FMdR2wFj9L9Kss\nP0fXU+waxCGRjbJlyOzRlYwzzDdLwRQ5YcuAkfINIueGDRsSUgjmzZs3y4w6RcYvwxAEUg4BMDr4\nAsOToUCBAjqxCnJ6x5OsKF2+fYCVthY1+lxIZR0wAvurbdvJbN/WZ9Tpc4j0i2rLVqK8ecisVtU9\ncHPEcLfI2X0yQXbU/gOk3niLTA+9c6Rds2XAmH0WK1ZM5wQ+evQoYUOihnjSxx9/bJsqESKs6zkL\nhZAgIAhkIvDXX39RlSpVKEeOHLRp0yYaNGgQNWjQQE+qBaMEQIBDHRJ7lRjsS5pupNjtyjX0aeIg\nE2RUrkgGW4F7kqXv9TwXl33OAuhJ6t3N5HpxDnH2IM/TEe97MWBkKBo4cKAWPZcqVYqmTJmiG/j8\n88/jvgKGYUnRokWzDHj9+vUSMCQLKnIinRGA+ghqo4ULF+r/MMBKtqA6qawDTqfcv1jpGgULnH0d\n/y8HmWNGkcFJQhKZchw5Rr952iawusC8tQi5Bg5xtNteDBgMDmEox48fT927d3frZpCiME+ePI42\nHGpl8EO280V+9dVXbUVYodYv5QWBVEEA+t6RI0fSf/7zH/0fkbBGjBiRVMNLZR2w2ryVzOdGJtXz\nCKWzyByk1m0grBqNUreT0a+3+3aDDQQTibT6g0NUwvjLrHKnu2tVunammwsVch8j2IZyHzm348WA\nUS1Ez7B+tugPjtaCnL1CgoAgkBwIbNmyhXLlyqUDcdSsWVNHsENqQsR3TxZKVR0wsuxoIyPPgP7J\n8lCC7KeLkxIY7N9sTh7PsZJzBXlXbIshCplikbLauIlYh0lm105eHXDFKPeBFwOGvy+sEqE/atKk\nCd13331a/wtDDiT7TjYxlheiciAIpDgC0P126NCBDh48qCfNV57RMWISfdlll6X46JNjeFr8XLFC\ncnQ2QC8Rb1mteYeMWwqTUbKEu3TGlAnu/YTdOXqM6IrLyZw2iQxW0QRFnPHIuPeeoIoGW8iLAcPf\nFy4B9erVo0WLFnHCiJz06aef0uDBgwnxZbt06RJsvVJOEBAEYowAcncPHz5cT5avvvpqQkhZMGUw\n33irkEKFIlV1wDr3b+/HQ4UjocqrY8cIq1z69DMyqlYh8oi3nFAd5c6oP//MFIezxXXG6LNqGEwY\nPCcNwfQbKQeN2rWCKRp0GdOz5I4dO3S0K8SQfeutt6hFixb6csWKFfWs2rOs7AsCgkDiIbBy5Ur6\n7rvvqGXLlrRs2TJq2rSptoD+mtOoJRNBB3xzksTzDRZXhWdw4gQZhc/qFoO9N5HKKY65bDasT+ar\nL5P5yENkJKiK0jV5Krmat9bpB80WzRIJQndfvFbAMNr4ipND44cPPZKlC4Z19I033ui+SXYEAUEg\n8RDYtm0bLV26lBYvXqyDcMydO1enJNy5cyf1799fn0+8Xtv3KBV1wDC+MipVtB9wAp7VetK31+iM\nTeagJ909NO+q4d5PpB2EqvSMLGaw1bLxQFvCyjVRyWsF3K1bN3rwwQd12EmsfmF8BVekyZMna51w\nog5C+iUICAJEYLStWrWi3Llz60QMUCWdzx+fO+64IyoSrNPsKwkRt1BwCGQy4DuCKxznUq7nnidX\ny/uJWFdqtGoe5974bx7Wy66Vb9Lpbj1Jbd3mVdCoXCmhmS8668WAIYKG+9Fdd91FN7CV3sSJE/VL\n3bp1a53Q+ySCYQsJAoJAQiJgSbDQuTfeeIPq1s1M9P7hhx86IsGaMGECIaYzaNq0aTrKFlwXEfYS\n4WudJOiAEQAoVUj98gvRl18SlSiekENCdC4vuvkmMhfNI5NdiBI1tZ/WRTdtSWrvPh1VzKx1t9cQ\nkuFAi6CtUHDws7X2rc7XqVPH2nX7BbtPyI4gIAgkDAJguKNGjSJkM4NHw5133knwAUZYWSRYiZSg\nR4Yx159s2DJ9+nTav3+/lpINGTJES8kQ/MMpSgQ/4H/++YcQga9gwYJheYAAp+85SfyLL75IV2zb\nQcXMDCrJIUERoQw5m4OlU7zKw4ZgRNDvX3vttcHeGrCctmRe/joZnBiCPMTjZoN6Ae+NdQGIxL30\nzWyrZC54iYwQsIx1nwO1Z+KHjpkmZrHvv/++FimBEUNs1ahRI68NVpZCgoAgkJgIwGthz5499Oyz\nzxIixCH+MmjWrFlUu3ZtxzoNtybkHAYTMTlAAdwVf/jhB8fqR0XQAaPueNGkSZN0PG14hlSqVIme\nfprDJ4ZIcN0sXLgwwSL9/nz56ZNrriYsaOBREgphEoVJzq+//kpQE/ojuKAFS7AOdj09klwdOhNn\n6yDi3LqJSuqjg+QaMZpc97f36qKBcJ5JzHwxmHPw0kKshMwpcDn65JNPtLgZ/6HfgUEWknnjZWvf\n3hsALzTkQBAQBOKOAGK2I4ysRTVqOGcwA93yY489pr8J8DWGwSZExXBPhEg6VWjNmjUEA7Z9+/bp\n1SpWwuXKldOLkUJnoiN99NFHOkmN56IEKjpICawyR44c0akWe7BdzY+sT6317Agae++92i3siSee\n0KvZsmXLar29nZ82GO4xdvmBrh2EFTCS44CQ4WrXrl36uwx3M6yMV69erb/h+F7jOlQP//3vf6l4\n8eLaFuDbb7/V5Q8dOkSXfv0N5eVVr/nYw1pPevjwYb3K93RXw6QK9Ti54tadD+GPa9RzhMhaRv26\nZD7kf/IRQpUJVVRPkTHbBPDYqlWr5u4grJ8xi4NlJX4EwoDd0MiOIJB2CMA+BBsm6wcOHNCRtvCR\nBrMqUqSIo3h4+gHr7EFvvHW2fo5VYHoERAj6+vnnUTAWvKtWrdLumBAVg/AfkgV8JyHaR7Y4SAAg\nOUTAoo4dO+pVLXBAbmMw3ldeeUWXxz3HeKLS4vhnNJMlB2CIyC73IwexgKcJmDxSvS5fvtwr3v7G\njRs11vger1u3Ttvl/Pzzz9S8eXNtlwM7HYQcxbOA7v+ee+7RqgG4j3bt2lX3sXTp0gRpBVQSByZM\npCEL5tNhZujQ20NCAp/xejxhg+EexoXJG1brkKBgovUL662RzhKTgxdeeOEs/lHcUzzpMDyCxhiN\n2N2pT68othjfqjNlVDZ9gH6nWbNmOggHfkx4ME4SZpUQMdnlAnWyHalLEBAEnEUALomWW6Ldys2J\n1rx0wIqj8H7y6dlqc/h8toK9flFmYvezFdnvYdUJsbongZGC4GeN8J4I6wm9LJgcGDCYKJgmrM4h\nLn7ttde0kRoYLeIogKnBwwR6coi0wQCR5KZPnz5aLO2LI0KHzpgxQ3ukYB8TEovAFD/77DPCKrpK\nlSpaT41c7agDkQxPsK8x3M5q1apFR+fOo+oLFtLP8xcRZZg6z/uAAQN0/9auXasnA5hIYDUNmjNn\njm4Lx5gUgKCexEQLST2iRWrnLnK98hoZefOQwXGYLUq02NFWv5z67/NLPlstYkI/8MADWhfsFPOF\nOKNv37764aMlMGCEt8SsDj9Ea8Z5theyJwgIAomOwNixY7Xx5uOPOxfhCQzPYnpIUWc82tMvDJFe\n960Yq3kwJWSVsghqOoT23LBhg2bAOA9mi3zGkBTi24ZjUMmSJTWjxioVCwwENsIqFkzbMmrt16+f\nHh9SRb700ks0b948uvzyy/X9+PMlW0xbUgXkdoZY3CJ8N5csWaK9VDp37qyDroABW4TvKFbjo5jZ\n33re+aQw8XhmKBncvlUOLqZYBEFkDhG1Re3atdMW9Jg4wHgPhH5hshANBqx10Z1YtMwqTqNhPTJq\nnMXc6lMq/zf9DQ4/HPxIrJmuv3KhnLf0F9BBQMeMHzlEMNBfIHWakCAgCCQfAp06dSIwguwIDKgK\nr9Z8N4hMYSmcSNS4cWPN3H5ji2UQdLFQv4HBYvWLHMsgiGjBKKGDxfcSxyCshGF8BYIUEcwTPtqw\nSgeBiWPVDEYN4ziIgBH615MgJrZcvuAe6klYeWN1CqaN1TqMuiDatiYsaA/7G5AFa/O79BczWkuP\nbJWx6qtcubJWJ+AYkwis/KHvxqQB9c+fP5/y58+vfcuteyL9r7g/bmLRt9m/DyF+NNQDvv1zl0vR\nHb8r4GiM95tvvtE6E8+VLmaQcJ+wRCDRaFfqFAQEgeghEEy2NKwmPVeUVm+w+vN1fcQ1Tx2wVTZW\n/2HEBkkdVrBgumB4gwcPpjxsIwMPEdjFgFFBDIxogWAauA5JHsTDuAf6Vfhig/JxCj4wcEgIIFaG\nDhkeJz179tQ6Y9jY+FpGP/fcczqEKFay+EZCz2sR6gdmYN5YxSJOw7kcMCM/S+rxLcU9SD/ZhscA\n/2y0D4M5O8Kzw/3QIaNOTBjQFlbCEGFDQgmdtV0qWLv6sjun2MhXvcy68ftqE3GUKpDW93rofLO7\nPxWvGQw6P7bY0N69e7UZPdybYFEJOn78uJ5pYYYcjogDM0kMwQqbGZuRSCuCQPYIQCyLlYMlcsy+\ndHJcBVPA6s2OsIpD/OlQyWLA+OB7Et5pbPF0RUJ/YNmMfOi+BKYMoyXfFRt8f7F6DJagr83OJxgr\nW7RjR2C+/7Bh1rmT2QL9yFEyu3ehv8uUdvss//777zqhjt29vuew+gVZrmvYx2QCbUSaBQ9BSFyj\nxxAd+4SMpo3JaNyQkF83kSlW729MV8DQP0B0gpkh9CZ4wIi4FS7zTeQHKH0TBFINgTZt2mhVEVZy\nEJ96kpX60PNcJPtgbL7MLZL6wr3XjvmiLqxC7SgU5ov7s2O+uO6P+eIaJIkZHIaRit5KxsD+ZPDx\nubhwhuBiGix5Ml7rHstGxzoO+//Bj8moVoWMp1kPzaJ6obMIxJQBo1mIMrBqDZVgTg8/Nl/CLC+7\nH6lveTkWBASB8BDIxcnVoRMcOHCg1luGV4vc5SQCRptWZPhZITvZTih1uTZsJLNqFfctRsU7KNOG\n3H1Kds4gEHMGbId8MFaUCAkH/YkvwZDL04rP97ocCwKCgHMIwM8VbonRpnjqgKM9tnDrhw7VNW4i\nZYwf664ikZiva+07pOaxMe1llxJ5MGB3Z2UnCwIJwYBhRRmI4G+HzZcsHZLveTkWBASB5EXAyw84\neYfhSM91oJHpM0mtXUdGpw6O1Ol0Ja4x40ixPY/Z61EyihV1uvqUrS9uDBjKfegYYL4fjBVlyj4B\nGZggkKQIPPnkk9rdBla0TlOi6ICdHlc49an1bPj28y9kzmGLaxuDsHDqdPoeHbGKrcSFQkMgpqZo\nsLTr1auXjiWLeKnY4EMHk30wZCFBQBAQBAQBIs/0gEbxYmQ+2TdhmK/atZtO9x/o9ZgMYb5eeAR7\nENMVsGcgDssXGDFIEXcUgTjatm0bbL+9yiFMGiLDREoIXo6gIE6uyOEAj6gyTkUTs8YIv77rr7/e\nOnTkPwIPwBoynccP1yEkIImUoMNEXalMiNR03XXXRTxEu/cXwS+AIeIfR5MQBATibjsrYCfbRcSp\nYLHK9ROPma3Av7/ibGSsYPoSjffXs91L2BC26p4D9O+vv9GBO8rS1w6mn/RsB/twv4Lhraf/s28Z\nJ47x/OGX7WuNHqv3N6YMOBqBOCD+QiYWvLCR0u7du/VDd5Kx4YeEaF8VKlSItHte9yMaj2fiDK+L\nYR7AoA0W5ZaPdpjVeN2WbOOHf6dnSECvwYRwAObrZArAEJqOWdFw/H59O+fv/UWgio0cUQohcaNJ\niFAFKVyo7kOh9AnulohqVYUjgQUiw6XoB/Z/Ps1xm9ntI1Bxr+vReH89G/iex3GkwE20jn3Bq51m\nv+EQ++dZV6B9TLywyIi2gS0CQGHC7Ts5itn7y87uMSPOKKI4g4fipOGKV7x6wz6/AIpnIjHrh7+G\nxo8fr9jC09/lsM7zilpxdJmw7s3uJg5rl93lsK5NmDBBLVu2LKx7/d2E59q0aVN/l8M+H43xT5w4\nUXFUorD7JDc6h8DWrVsVJxRwrkI/NbHUTXGcYz9XnTnN0agUh7B0prJsaonG+2vXXDTePd92OIOT\n4mhkvqcdP+Z8B2xc/qnj9QZbYUx1wFYgDmTtQCCO9957T4s7JRBHoPmgXBcEBAFBQBBINQRiKoIG\neOEG4kg14GU8goAgIAgIAumNQExXwOkNtYxeEBAEBAFBQBA4i4Aw4LNYyJ4gIAgIAoKAIBAzBDI4\njdbgmLWW4A3B/Qb5jy+9lEOpOUQINIIYunk5pZeTBPP8AgUKOFml1sen+/iRHAQ2CkLxRQAZeK69\n9lq9RbMneNawgkXKv2gRgoogWUW03dKi8f2ywyQa3x7fdvA88Px9rZN9y0V6bD3/SDM+hduPmKYj\nDLeTcp8gIAgIAoKAIJBqCIgIOtWeqIxHEBAEBAFBICkQEAacFI9JOikICAKCgCCQaggIA061Jyrj\nEQQEAUFAEEgKBIQBJ8Vjkk4KAoKAICAIpBoCwoBT7YnKeAQBQUAQEASSAgFhwEnxmKSTgoAgIAgI\nAqmGQFozYGTcQLpAO0LuYmTysTa7MrE8h3zJ/lKzIaWj1U/sx4sCYYasMFY/8R/H8aRffvmF/OEV\naCzx7Hcqto1nkV1OcPxWkNYzUkL6OQ6Un20130aY5eevv/6ikydP+m0D7TuRvS0QZugD+hIJBYt7\npJhlNxYnvxuBnn9234RIcPR7b7BZG1KpHH9cVd26dXWWnpIlS6odO3ZkGV6XLl1UoUKF1G233aY3\nzk2ZpUwsTzz88MOqc+fOtk1yXlZ3PzlFnG2ZWJwMhNnixYsVp3p095VTKsaiW7ZtdOjQQdWpU0fd\ncccdatGiRVnKBBpLlhvkRNgItGnTRtWqVUtxsBq1ZcuWLPXg/eS0hIrT+akmTZpwrnpXljKBTnCu\nXFW2bFl17733Kk5x5zf72pQpUxSnkQxUnd/rkyZNUpx6VOGdHDduXJZyyLaGbEIYB75BPBHNUiaY\nE4EwGzBggK6/fPnyavLkycFUmaVMsLi/9tprqmDBglnuD/ZEoLE48d0I5vkH+iYEO55QymE2mHa0\nefNmNWLECD3uVatWqebNm2fBAD9cXnFmOR+PE2vWrNEfDTsG/Oeff6oSJUrEo1tZ2gyEGdKLOZ3u\nMUsngjixfv169zM/ceKEbdq7QGMJohkpEgQCb7/9tmrfvr0uyfls9YTI9zYwNCtlIOcPVngfQiX8\n9ubOnatvmzlzpu0zxwcYE7JwGTCvalXRokX1BIFX85oJ48PvSZ6/qyeeeELNnz/f83JQ+4EwQ5vW\nRJxXwXrSG1TFPoWCwZ1XvorzkofNgAONBV1y4rsR6PkH803wgceRw7QUQVesWJH4gdChQ4foxRdf\npKpVq3pJCCDyOH78OHF+YOrRo4dOnehVIIYHEDuPHj2a/EUMRVrH888/n7p3707Dhg0jiFjiQcFg\nduDAAdq9ezdxDlbiFy8e3dRt8sqbOC81DRo0iHj1S7xa8OpLMGPxukEOwkYAKUn5Q6/vz5cvH339\n9ddZ6sI7gBCpILy7e/fuzVIm0AnPdvzVwblhafr06YGq8nv9yJEjOoE8Qk+ec845xMyYPv74Y6/y\n27Zto8svv1yf4zy0lCNHDq/rwRx4jsUOs5w5c9KCBQvohx9+oOeff54qVaoUTLVZygSDe7du3Wjs\n2LFZ7g32RKCxoB4nvhue7dg9/0DfhGDHE2q5tGTAFkgrVqzQjBYMzJOgB8CPlsVEVL9+fb2dOnXK\ns0jM9jEBGDVqlGaydo1ysm8qV64c9e7dm6644grN3OzKRftcMJghzjKL3+jxxx/XEwoWcUW7W7b1\nf/fddzR79myNG/Y7duzoVS6YsXjdIAdhIwD8wTAsAkOCfYBFLKHQzMw6vvjii4lXeNZh0P892/FX\nB69+g67PrqBnG7jurx1ce+aZZ4ilV9S4cWMchkS+7fhiZlXGkj4Cw7/qqqsC6r2te6z/weA+YcIE\n4tUvsarOui3k/8GMxYnvhmc7ds8F17P7JoQ8sCBvSGsG3KdPH1q7di3hP4xuLEKw8YULFxLrcahG\njRqEF5NFFNblmP1n8Ti9//77tHz5cmLxmV49+q4cK1eurGegWCFgNopVPV6eWFMwmE2bNo1Y10es\nz6NOnToRi6Nj3U3dHpJtsNqBWNRIAwcO1B8pT2OsYMYSl46nYKOYNHr+XpG85LzzznOPFB9LX4aM\nIP2hkmc7aC+cOgK16dkGyvprBxIXrOLxXptm6J9g33Z8MbP62ahRI8I3ZN++ffrbYZ0P5n8g3DFJ\ntSRuQ4YMoZ9++olYfx5M1V5lghmLE98Nz3bsnkugb4JXpx08CP3pO9h4vKpipT71799fN49Z6NVX\nX+01y/7yyy8140UBFvQTxBelSpWKeXfBqJ599lm9UsMsE1mVLFGc1ZklS5bQk08+qQ+tWd4ll1xi\nXY7Z/0CYQayLiQxeVBA+QGwUE7P+eTaEdlnfqE9BzIa+eWbDCTQWz7pkPzIEoArYuHGjrgTiWl/G\nCHEu3s9PPvlEl0FZtnkIuVHPdsKtI1CjmLDjW4HJHCRTH330Ed10001et0HtAWvupUuXUrgZeDzH\nYocZfr9ssOZuF9+43Llzu4+D2QmEO6SGc+bMIdZpa3UOjiFyD5UCjcWp74ZnO3bPP9A3IdRxBV3e\nEU1yklXCL4e2QmTxsrrrrrvU6tWr9Qhg+cqzLb0PK0IYY8Bikmd4cR8hjBUsIywYPlxzzTW6T7Ci\nbNiwoapXr57idGfqzTffjFtf7TCDhXGLFi10n5YtW6YNNljnri00Wawfl76y65mCMQ+eL4xmVq5c\nqfuRyM8/LkDFqNFevXqpu+++W1s6MwPTrXr+bnbu3Klq1qypWNqj2NYhrF6xbYRq1qyZft9Rj+XV\nAE+Hw4cPu+tkphm2ERYqgaFX9erV1e23366YQel6rbHgvWXdsH5P0S62F154wd12KDt2mHn+fp96\n6ilt8Q3cWEcbStXusna4e357rIL4BkViBW03FgsztOHEdyPQ8/f3TbDGGK3/aZ2OEDPDCy+80O9k\nBTNZBj7smarfiqNwgT8odMEFF4Ql0nKyO8FgBv9EiLjiTegHMIMIz46CGYvdfXIudARgY+Fri+Fb\nSzBlfO/xPXaiDt86fY+hzsJ3IxwDK9+6sjsONBaswmEM5u/3nV3dntcCteNZNtz9YNpw4rsRqJ1A\n34Rwx+fvvrRmwP5AkfOCgCAgCAgCgkC0EUhLHXC0QZX6BQFBQBAQBASBQAgIAw6EkFwXBAQBQUAQ\nEASigIAw4CiAKlUKAoKAICAICAKBEBAGHAghuS4ICAKCgCAgCEQBAWHAUQBVqhQEBAFBQBAQBAIh\nIAw4EEJyXRAQBAQBQUAQiAICwoCjAKpUKQgIAoKAICAIBEJAGHAghOS6ICAICAKCgCAQBQSEAUcB\nVKlSEBAEBAFBQBAIhIAw4EAIyXVBQBAQBAQBQSAKCAgDjgKoUqUgIAgIAoKAIBAIAWHAgRCS64KA\nICAICAKCQBQQEAYcBVClSkFAEBAEBAFBIBACwoADISTXBQFBQBAQBASBKCBwThTqlCodROCHH34g\n5C32pNy5c9Pvv/+uc9kGyqHqeZ/nPvKVfvPNN3Tdddd5ng56/6effqKLLrqIzjvvvKDvkYKCgCBw\nFgFOZE8nTpygq6666uxJ2UsrBGQFnOCPu0uXLtS8eXPq3r27e/v555/p+eefp507d9L3339P/fv3\n16PYtGkTzZs3L6gR/fHHH1S7du2gytoV6tu3L23dutXukpwTBASBIBDYvHkzdevWLYiSUiRVERAG\nnARPdsSIEfTWW2+5t1y5clGPHj2oVKlStG/fPs2IsZpdvXo1HTx4kE6ePKlHhRn2oUOHvEb4v//9\nT5cHA/al7777zn0vrn366ad0+vRp+vfff+nAgQO0Y8cOOnXqlNdtWIn/+OOP+pzL5dL3WAXs2j9+\n/Djhw/Prr79axeS/ICAI+CDg++74ezdx29GjR+mvv/5y1/Dtt9/SL7/8ot9ZSLrwrm/fvp3ee+89\nwrFFX3zxBaFelMV7bJFvfdZ5+e88AiKCdh5Tx2vEywGRLwgiX4h+hw4dSnXq1KFt27bRV199pZnq\n3r179QuGYzDmxYsXU968efUL+uqrr2pxV40aNahq1aq0f//+LP1cs2YNffTRRzRq1Cj9QtarV0+/\nxChfunRprxfZunnlypV0+PBhGjZsmBaV454PPviAFixYkKX9d999V5erXr06de3alZYvX0758uWz\nqpL/goAgwAjYvTt27+bu3bupfv36+h0/duwYNWvWjNq2bUtPPfUUffjhh3TFFVfo961Dhw50zz33\n0K5du/T7NnnyZBo+fDitX7+eChQoQKinZ8+e+v4mTZpkqU8eSvQQEAYcPWwdqxkv1KWXXqrru+++\n+6h3797uuvHC4GVr0KABYXWJGW7hwoUJLx1e5IsvvpgmTZqkV89YHbdo0UKLrLEKxSrakxo3bkwj\nR44krLiXLl2qRd/QP0PEXatWLfrkk0+oWrVqQa1e0aZv+59//jnlz59ffyTuv/9+uuyyyzybl31B\nQBBgBOzeHbt3c9WqVVSwYEGCOghSKnwLwIBB+N+5c2c9+Z4xYwYVLVpUS54efvhh+vvvv+mFF14g\nrJTPOeccqlu3rr4nu/p0AfnjOALCgB2H1PkKx40bpxlfsDVDBA1mO3DgQPctefLkIYicsGoGlSxZ\n0n3N2rnggguoQoUKBF0ymOfcuXMpR44c+v/o0aP1SwwGD7G0HUEEDfLX/kMPPURjx46lpk2b6jqg\nr7788svtqpJzgkBaIuDv3bF7N8FEsap95JFHNFY33nijW4WE992iJ554Qr/HYMJ4dyFNQ1kwXxDO\ng2DTYVcfJvFC0UFAdMDRwTVmtWZkZLgZorWPF6ZIkSIEpjl//nzCqhkvXLFixQhiYBAMuOyoffv2\nmkmee+65BGtriL4Mw6ANGzbQ008/rcXMngwYVtiw1AZB9Azy1/6KFSuoUqVKtGfPHmrVqhUtWrRI\nl5c/goAgkImAv3cHV33fTaiTbr31Vv2OT506la655hq68MILdUWmmflph7gZoum3335bi6vx7l57\n7bX6mwEDTqyc161bp+/Jrj5dQP44joCsgB2HNLYVgkmC8UGnc+edd1Lr1q21WGrw4MFaDA0GCYMO\niJTLly+vRdUQJxcqVEgzVt/eYgUMIwyIvUGoEyJp1AsDLuhsoWO2CPrhIUOG0L333ktXXnml2y3J\nrn0YikE0DrcLiMtnz55tVSP/BYG0RAATXKiMLIJdhN27g+u+7yYY5muvvaZFyDC0ateuHVmM16qv\nYcOGhBXwli1b6P/+7/80wwXThZi7U6dO+hyYNr4TwdRn1Sv/nUHAYJHiWbM4Z+qUWmKMAES/mNlC\nXPzPP/8QVsLWiwjrSIivPAmWzKH6D8MQLGfOnJ7VeO37u27XPnwfL7nkEq/75UAQEAS8EbB7d7xL\nZB5hgg2JFSRVdoTvA+qC8aZFWDFDR4x7oF/u168f3X777fpyoPqsOuR/5AjICjhyDONeA5itxXDB\nhD3Jl/niWqjMF/dkx3yzu27XvjBfICYkCGSPgN27Y3dHoGA4+DZ4Ml/UASaLOABYf0E95WkTEqg+\nuz7IufAQkBVweLjJXYKAICAIJDUCkJphg2haKD4ICAOOD+7SqiAgCAgCgkCaIyBW0Gn+A5DhCwKC\ngCAgCMQHAWHA8cFdWhUEBAFBQBBIcwSEAaf5D0CGLwgIAoKAIBAfBIQBxwd3aVUQEAQEAUEgzREQ\nBpzmPwAZviAgCAgCgkB8EBAGHB/cpVVBQBAQBASBNEdAGHCa/wBk+IKAICAICALxQUAYcHxwl1YF\nAUFAEBAE0hwBYcBp/gOQ4QsCgoAgIAjEBwFhwPHBXVoVBAQBQUAQSHMEhAGn+Q9Ahi8ICAKCgCAQ\nHwT+H3+Bv8VJdwumAAAAAElFTkSuQmCC\n"
1101 }
1101 }
1102 ],
1102 ],
1103 "prompt_number": 8
1103 "prompt_number": 8
1104 },
1104 },
1105 {
1105 {
1106 "cell_type": "heading",
1106 "cell_type": "heading",
1107 "level": 1,
1107 "level": 1,
1108 "metadata": {},
1108 "metadata": {},
1109 "source": [
1109 "source": [
1110 "octavemagic: Octave inside IPython"
1110 "octavemagic: Octave inside IPython"
1111 ]
1111 ]
1112 },
1112 },
1113 {
1113 {
1114 "cell_type": "markdown",
1114 "cell_type": "markdown",
1115 "metadata": {},
1115 "metadata": {},
1116 "source": [
1116 "source": [
1117 "The `octavemagic` extension provides the ability to interact with Octave. It depends on the `oct2py` and `h5py` packages,\n",
1117 "The `octavemagic` extension provides the ability to interact with Octave. It depends on the `oct2py` and `h5py` packages,\n",
1118 "which may be installed using `easy_install`. It has been closely modeled after the R extension, so many of its names and usage patterns are the same.\n",
1118 "which may be installed using `easy_install`. It has been closely modeled after the R extension, so many of its names and usage patterns are the same.\n",
1119 "\n",
1119 "\n",
1120 "To enable the extension, load it as follows:"
1120 "To enable the extension, load it as follows:"
1121 ]
1121 ]
1122 },
1122 },
1123 {
1123 {
1124 "cell_type": "code",
1124 "cell_type": "code",
1125 "collapsed": false,
1125 "collapsed": false,
1126 "input": [
1126 "input": [
1127 "%load_ext octavemagic"
1127 "%load_ext octavemagic"
1128 ],
1128 ],
1129 "language": "python",
1129 "language": "python",
1130 "metadata": {},
1130 "metadata": {},
1131 "outputs": [],
1131 "outputs": [],
1132 "prompt_number": 109
1132 "prompt_number": 109
1133 },
1133 },
1134 {
1134 {
1135 "cell_type": "heading",
1135 "cell_type": "heading",
1136 "level": 2,
1136 "level": 2,
1137 "metadata": {},
1137 "metadata": {},
1138 "source": [
1138 "source": [
1139 "Overview"
1139 "Overview"
1140 ]
1140 ]
1141 },
1141 },
1142 {
1142 {
1143 "cell_type": "markdown",
1143 "cell_type": "markdown",
1144 "metadata": {},
1144 "metadata": {},
1145 "source": [
1145 "source": [
1146 "Loading the extension enables three magic functions: `%octave`, `%octave_push`, and `%octave_pull`.\n",
1146 "Loading the extension enables three magic functions: `%octave`, `%octave_push`, and `%octave_pull`.\n",
1147 "\n",
1147 "\n",
1148 "The first is for executing one or more lines of Octave, while the latter allow moving variables between the Octave and Python workspace.\n",
1148 "The first is for executing one or more lines of Octave, while the latter allow moving variables between the Octave and Python workspace.\n",
1149 "Here you see an example of how to execute a single line of Octave, and how to transfer the generated value back to Python:"
1149 "Here you see an example of how to execute a single line of Octave, and how to transfer the generated value back to Python:"
1150 ]
1150 ]
1151 },
1151 },
1152 {
1152 {
1153 "cell_type": "code",
1153 "cell_type": "code",
1154 "collapsed": false,
1154 "collapsed": false,
1155 "input": [
1155 "input": [
1156 "x = %octave [1 2; 3 4];\n",
1156 "x = %octave [1 2; 3 4];\n",
1157 "x"
1157 "x"
1158 ],
1158 ],
1159 "language": "python",
1159 "language": "python",
1160 "metadata": {},
1160 "metadata": {},
1161 "outputs": [
1161 "outputs": [
1162 {
1162 {
1163 "output_type": "pyout",
1163 "output_type": "pyout",
1164 "prompt_number": 110,
1164 "prompt_number": 110,
1165 "text": [
1165 "text": [
1166 "array([[ 1., 2.],\n",
1166 "array([[ 1., 2.],\n",
1167 " [ 3., 4.]])"
1167 " [ 3., 4.]])"
1168 ]
1168 ]
1169 }
1169 }
1170 ],
1170 ],
1171 "prompt_number": 110
1171 "prompt_number": 110
1172 },
1172 },
1173 {
1173 {
1174 "cell_type": "code",
1174 "cell_type": "code",
1175 "collapsed": false,
1175 "collapsed": false,
1176 "input": [
1176 "input": [
1177 "a = [1, 2, 3]\n",
1177 "a = [1, 2, 3]\n",
1178 "\n",
1178 "\n",
1179 "%octave_push a\n",
1179 "%octave_push a\n",
1180 "%octave a = a * 2;\n",
1180 "%octave a = a * 2;\n",
1181 "%octave_pull a\n",
1181 "%octave_pull a\n",
1182 "a"
1182 "a"
1183 ],
1183 ],
1184 "language": "python",
1184 "language": "python",
1185 "metadata": {},
1185 "metadata": {},
1186 "outputs": [
1186 "outputs": [
1187 {
1187 {
1188 "output_type": "pyout",
1188 "output_type": "pyout",
1189 "prompt_number": 111,
1189 "prompt_number": 111,
1190 "text": [
1190 "text": [
1191 "array([[2, 4, 6]])"
1191 "array([[2, 4, 6]])"
1192 ]
1192 ]
1193 }
1193 }
1194 ],
1194 ],
1195 "prompt_number": 111
1195 "prompt_number": 111
1196 },
1196 },
1197 {
1197 {
1198 "cell_type": "markdown",
1198 "cell_type": "markdown",
1199 "metadata": {},
1199 "metadata": {},
1200 "source": [
1200 "source": [
1201 "When using the cell magic, `%%octave` (note the double `%`), multiple lines of Octave can be executed together. Unlike\n",
1201 "When using the cell magic, `%%octave` (note the double `%`), multiple lines of Octave can be executed together. Unlike\n",
1202 "with the single cell magic, no value is returned, so we use the `-i` and `-o` flags to specify input and output variables."
1202 "with the single cell magic, no value is returned, so we use the `-i` and `-o` flags to specify input and output variables."
1203 ]
1203 ]
1204 },
1204 },
1205 {
1205 {
1206 "cell_type": "code",
1206 "cell_type": "code",
1207 "collapsed": false,
1207 "collapsed": false,
1208 "input": [
1208 "input": [
1209 "%%octave -i x -o y\n",
1209 "%%octave -i x -o y\n",
1210 "y = x + 3;"
1210 "y = x + 3;"
1211 ],
1211 ],
1212 "language": "python",
1212 "language": "python",
1213 "metadata": {},
1213 "metadata": {},
1214 "outputs": [],
1214 "outputs": [],
1215 "prompt_number": 116
1215 "prompt_number": 116
1216 },
1216 },
1217 {
1217 {
1218 "cell_type": "code",
1218 "cell_type": "code",
1219 "collapsed": false,
1219 "collapsed": false,
1220 "input": [
1220 "input": [
1221 "y"
1221 "y"
1222 ],
1222 ],
1223 "language": "python",
1223 "language": "python",
1224 "metadata": {},
1224 "metadata": {},
1225 "outputs": [
1225 "outputs": [
1226 {
1226 {
1227 "output_type": "pyout",
1227 "output_type": "pyout",
1228 "prompt_number": 117,
1228 "prompt_number": 117,
1229 "text": [
1229 "text": [
1230 "array([[ 4., 5.],\n",
1230 "array([[ 4., 5.],\n",
1231 " [ 6., 7.]])"
1231 " [ 6., 7.]])"
1232 ]
1232 ]
1233 }
1233 }
1234 ],
1234 ],
1235 "prompt_number": 117
1235 "prompt_number": 117
1236 },
1236 },
1237 {
1237 {
1238 "cell_type": "heading",
1238 "cell_type": "heading",
1239 "level": 2,
1239 "level": 2,
1240 "metadata": {},
1240 "metadata": {},
1241 "source": [
1241 "source": [
1242 "Plotting"
1242 "Plotting"
1243 ]
1243 ]
1244 },
1244 },
1245 {
1245 {
1246 "cell_type": "markdown",
1246 "cell_type": "markdown",
1247 "metadata": {},
1247 "metadata": {},
1248 "source": [
1248 "source": [
1249 "Plot output is automatically captured and displayed, and using the `-f` flag you may choose its format (currently, `png` and `svg` are supported)."
1249 "Plot output is automatically captured and displayed, and using the `-f` flag you may choose its format (currently, `png` and `svg` are supported)."
1250 ]
1250 ]
1251 },
1251 },
1252 {
1252 {
1253 "cell_type": "code",
1253 "cell_type": "code",
1254 "collapsed": false,
1254 "collapsed": false,
1255 "input": [
1255 "input": [
1256 "%%octave -f svg\n",
1256 "%%octave -f svg\n",
1257 "\n",
1257 "\n",
1258 "p = [12 -2.5 -8 -0.1 8];\n",
1258 "p = [12 -2.5 -8 -0.1 8];\n",
1259 "x = 0:0.01:1;\n",
1259 "x = 0:0.01:1;\n",
1260 "\n",
1260 "\n",
1261 "polyout(p, 'x')\n",
1261 "polyout(p, 'x')\n",
1262 "plot(x, polyval(p, x));"
1262 "plot(x, polyval(p, x));"
1263 ],
1263 ],
1264 "language": "python",
1264 "language": "python",
1265 "metadata": {},
1265 "metadata": {},
1266 "outputs": [
1266 "outputs": [
1267 {
1267 {
1268 "output_type": "display_data",
1268 "output_type": "display_data",
1269 "text": [
1269 "text": [
1270 "12*x^4 - 2.5*x^3 - 8*x^2 - 0.1*x^1 + 8"
1270 "12*x^4 - 2.5*x^3 - 8*x^2 - 0.1*x^1 + 8"
1271 ]
1271 ]
1272 },
1272 },
1273 {
1273 {
1274 "output_type": "display_data",
1274 "output_type": "display_data",
1275 "svg": [
1275 "svg": [
1276 "<svg height=\"240px\" viewBox=\"0 0 400 240\" width=\"400px\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
1276 "<svg height=\"240px\" viewBox=\"0 0 400 240\" width=\"400px\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
1277 "\n",
1277 "\n",
1278 "<desc>Produced by GNUPLOT 4.4 patchlevel 3 </desc>\n",
1278 "<desc>Produced by GNUPLOT 4.4 patchlevel 3 </desc>\n",
1279 "\n",
1279 "\n",
1280 "<defs>\n",
1280 "<defs>\n",
1281 "\n",
1281 "\n",
1282 "\t<circle id=\"gpDot\" r=\"0.5\" stroke-width=\"0.5\"/>\n",
1282 "\t<circle id=\"gpDot\" r=\"0.5\" stroke-width=\"0.5\"/>\n",
1283 "\t<path d=\"M-1,0 h2 M0,-1 v2\" id=\"gpPt0\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1283 "\t<path d=\"M-1,0 h2 M0,-1 v2\" id=\"gpPt0\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1284 "\t<path d=\"M-1,-1 L1,1 M1,-1 L-1,1\" id=\"gpPt1\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1284 "\t<path d=\"M-1,-1 L1,1 M1,-1 L-1,1\" id=\"gpPt1\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1285 "\t<path d=\"M-1,0 L1,0 M0,-1 L0,1 M-1,-1 L1,1 M-1,1 L1,-1\" id=\"gpPt2\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1285 "\t<path d=\"M-1,0 L1,0 M0,-1 L0,1 M-1,-1 L1,1 M-1,1 L1,-1\" id=\"gpPt2\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1286 "\t<rect height=\"2\" id=\"gpPt3\" stroke=\"currentColor\" stroke-width=\"0.222\" width=\"2\" x=\"-1\" y=\"-1\"/>\n",
1286 "\t<rect height=\"2\" id=\"gpPt3\" stroke=\"currentColor\" stroke-width=\"0.222\" width=\"2\" x=\"-1\" y=\"-1\"/>\n",
1287 "\t<rect fill=\"currentColor\" height=\"2\" id=\"gpPt4\" stroke=\"currentColor\" stroke-width=\"0.222\" width=\"2\" x=\"-1\" y=\"-1\"/>\n",
1287 "\t<rect fill=\"currentColor\" height=\"2\" id=\"gpPt4\" stroke=\"currentColor\" stroke-width=\"0.222\" width=\"2\" x=\"-1\" y=\"-1\"/>\n",
1288 "\t<circle cx=\"0\" cy=\"0\" id=\"gpPt5\" r=\"1\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1288 "\t<circle cx=\"0\" cy=\"0\" id=\"gpPt5\" r=\"1\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1289 "\t<use fill=\"currentColor\" id=\"gpPt6\" stroke=\"none\" xlink:href=\"#gpPt5\"/>\n",
1289 "\t<use fill=\"currentColor\" id=\"gpPt6\" stroke=\"none\" xlink:href=\"#gpPt5\"/>\n",
1290 "\t<path d=\"M0,-1.33 L-1.33,0.67 L1.33,0.67 z\" id=\"gpPt7\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1290 "\t<path d=\"M0,-1.33 L-1.33,0.67 L1.33,0.67 z\" id=\"gpPt7\" stroke=\"currentColor\" stroke-width=\"0.222\"/>\n",
1291 "\t<use fill=\"currentColor\" id=\"gpPt8\" stroke=\"none\" xlink:href=\"#gpPt7\"/>\n",
1291 "\t<use fill=\"currentColor\" id=\"gpPt8\" stroke=\"none\" xlink:href=\"#gpPt7\"/>\n",
1292 "\t<use id=\"gpPt9\" stroke=\"currentColor\" transform=\"rotate(180)\" xlink:href=\"#gpPt7\"/>\n",
1292 "\t<use id=\"gpPt9\" stroke=\"currentColor\" transform=\"rotate(180)\" xlink:href=\"#gpPt7\"/>\n",
1293 "\t<use fill=\"currentColor\" id=\"gpPt10\" stroke=\"none\" xlink:href=\"#gpPt9\"/>\n",
1293 "\t<use fill=\"currentColor\" id=\"gpPt10\" stroke=\"none\" xlink:href=\"#gpPt9\"/>\n",
1294 "\t<use id=\"gpPt11\" stroke=\"currentColor\" transform=\"rotate(45)\" xlink:href=\"#gpPt3\"/>\n",
1294 "\t<use id=\"gpPt11\" stroke=\"currentColor\" transform=\"rotate(45)\" xlink:href=\"#gpPt3\"/>\n",
1295 "\t<use fill=\"currentColor\" id=\"gpPt12\" stroke=\"none\" xlink:href=\"#gpPt11\"/>\n",
1295 "\t<use fill=\"currentColor\" id=\"gpPt12\" stroke=\"none\" xlink:href=\"#gpPt11\"/>\n",
1296 "</defs>\n",
1296 "</defs>\n",
1297 "<g style=\"fill:none; color:white; stroke:currentColor; stroke-width:1.00; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1297 "<g style=\"fill:none; color:white; stroke:currentColor; stroke-width:1.00; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1298 "</g>\n",
1298 "</g>\n",
1299 "<g style=\"fill:none; color:white; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1299 "<g style=\"fill:none; color:white; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1300 "</g>\n",
1300 "</g>\n",
1301 "<g style=\"fill:none; color:black; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1301 "<g style=\"fill:none; color:black; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1302 "\t<path d=\"M52.0,213.6 L64.5,213.6 M361.9,213.6 L349.4,213.6 \"/>\n",
1302 "\t<path d=\"M52.0,213.6 L64.5,213.6 M361.9,213.6 L349.4,213.6 \"/>\n",
1303 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,218.1)\">\n",
1303 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,218.1)\">\n",
1304 "\t\t<text><tspan>6</tspan>\n",
1304 "\t\t<text><tspan>6</tspan>\n",
1305 "\t\t</text>\n",
1305 "\t\t</text>\n",
1306 "\t</g>\n",
1306 "\t</g>\n",
1307 "\t<path d=\"M52.0,185.7 L64.5,185.7 M361.9,185.7 L349.4,185.7 \"/>\n",
1307 "\t<path d=\"M52.0,185.7 L64.5,185.7 M361.9,185.7 L349.4,185.7 \"/>\n",
1308 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,190.2)\">\n",
1308 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,190.2)\">\n",
1309 "\t\t<text><tspan>6.5</tspan>\n",
1309 "\t\t<text><tspan>6.5</tspan>\n",
1310 "\t\t</text>\n",
1310 "\t\t</text>\n",
1311 "\t</g>\n",
1311 "\t</g>\n",
1312 "\t<path d=\"M52.0,157.7 L64.5,157.7 M361.9,157.7 L349.4,157.7 \"/>\n",
1312 "\t<path d=\"M52.0,157.7 L64.5,157.7 M361.9,157.7 L349.4,157.7 \"/>\n",
1313 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,162.2)\">\n",
1313 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,162.2)\">\n",
1314 "\t\t<text><tspan>7</tspan>\n",
1314 "\t\t<text><tspan>7</tspan>\n",
1315 "\t\t</text>\n",
1315 "\t\t</text>\n",
1316 "\t</g>\n",
1316 "\t</g>\n",
1317 "\t<path d=\"M52.0,129.8 L64.5,129.8 M361.9,129.8 L349.4,129.8 \"/>\n",
1317 "\t<path d=\"M52.0,129.8 L64.5,129.8 M361.9,129.8 L349.4,129.8 \"/>\n",
1318 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,134.3)\">\n",
1318 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,134.3)\">\n",
1319 "\t\t<text><tspan>7.5</tspan>\n",
1319 "\t\t<text><tspan>7.5</tspan>\n",
1320 "\t\t</text>\n",
1320 "\t\t</text>\n",
1321 "\t</g>\n",
1321 "\t</g>\n",
1322 "\t<path d=\"M52.0,101.9 L64.5,101.9 M361.9,101.9 L349.4,101.9 \"/>\n",
1322 "\t<path d=\"M52.0,101.9 L64.5,101.9 M361.9,101.9 L349.4,101.9 \"/>\n",
1323 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,106.4)\">\n",
1323 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,106.4)\">\n",
1324 "\t\t<text><tspan>8</tspan>\n",
1324 "\t\t<text><tspan>8</tspan>\n",
1325 "\t\t</text>\n",
1325 "\t\t</text>\n",
1326 "\t</g>\n",
1326 "\t</g>\n",
1327 "\t<path d=\"M52.0,74.0 L64.5,74.0 M361.9,74.0 L349.4,74.0 \"/>\n",
1327 "\t<path d=\"M52.0,74.0 L64.5,74.0 M361.9,74.0 L349.4,74.0 \"/>\n",
1328 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,78.5)\">\n",
1328 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,78.5)\">\n",
1329 "\t\t<text><tspan>8.5</tspan>\n",
1329 "\t\t<text><tspan>8.5</tspan>\n",
1330 "\t\t</text>\n",
1330 "\t\t</text>\n",
1331 "\t</g>\n",
1331 "\t</g>\n",
1332 "\t<path d=\"M52.0,46.0 L64.5,46.0 M361.9,46.0 L349.4,46.0 \"/>\n",
1332 "\t<path d=\"M52.0,46.0 L64.5,46.0 M361.9,46.0 L349.4,46.0 \"/>\n",
1333 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,50.5)\">\n",
1333 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,50.5)\">\n",
1334 "\t\t<text><tspan>9</tspan>\n",
1334 "\t\t<text><tspan>9</tspan>\n",
1335 "\t\t</text>\n",
1335 "\t\t</text>\n",
1336 "\t</g>\n",
1336 "\t</g>\n",
1337 "\t<path d=\"M52.0,18.1 L64.5,18.1 M361.9,18.1 L349.4,18.1 \"/>\n",
1337 "\t<path d=\"M52.0,18.1 L64.5,18.1 M361.9,18.1 L349.4,18.1 \"/>\n",
1338 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,22.6)\">\n",
1338 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:end\" transform=\"translate(43.7,22.6)\">\n",
1339 "\t\t<text><tspan>9.5</tspan>\n",
1339 "\t\t<text><tspan>9.5</tspan>\n",
1340 "\t\t</text>\n",
1340 "\t\t</text>\n",
1341 "\t</g>\n",
1341 "\t</g>\n",
1342 "\t<path d=\"M52.0,213.6 L52.0,201.1 M52.0,18.1 L52.0,30.6 \"/>\n",
1342 "\t<path d=\"M52.0,213.6 L52.0,201.1 M52.0,18.1 L52.0,30.6 \"/>\n",
1343 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(52.0,236.1)\">\n",
1343 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(52.0,236.1)\">\n",
1344 "\t\t<text><tspan>0</tspan>\n",
1344 "\t\t<text><tspan>0</tspan>\n",
1345 "\t\t</text>\n",
1345 "\t\t</text>\n",
1346 "\t</g>\n",
1346 "\t</g>\n",
1347 "\t<path d=\"M114.0,213.6 L114.0,201.1 M114.0,18.1 L114.0,30.6 \"/>\n",
1347 "\t<path d=\"M114.0,213.6 L114.0,201.1 M114.0,18.1 L114.0,30.6 \"/>\n",
1348 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(114.0,236.1)\">\n",
1348 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(114.0,236.1)\">\n",
1349 "\t\t<text><tspan>0.2</tspan>\n",
1349 "\t\t<text><tspan>0.2</tspan>\n",
1350 "\t\t</text>\n",
1350 "\t\t</text>\n",
1351 "\t</g>\n",
1351 "\t</g>\n",
1352 "\t<path d=\"M176.0,213.6 L176.0,201.1 M176.0,18.1 L176.0,30.6 \"/>\n",
1352 "\t<path d=\"M176.0,213.6 L176.0,201.1 M176.0,18.1 L176.0,30.6 \"/>\n",
1353 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(176.0,236.1)\">\n",
1353 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(176.0,236.1)\">\n",
1354 "\t\t<text><tspan>0.4</tspan>\n",
1354 "\t\t<text><tspan>0.4</tspan>\n",
1355 "\t\t</text>\n",
1355 "\t\t</text>\n",
1356 "\t</g>\n",
1356 "\t</g>\n",
1357 "\t<path d=\"M237.9,213.6 L237.9,201.1 M237.9,18.1 L237.9,30.6 \"/>\n",
1357 "\t<path d=\"M237.9,213.6 L237.9,201.1 M237.9,18.1 L237.9,30.6 \"/>\n",
1358 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(237.9,236.1)\">\n",
1358 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(237.9,236.1)\">\n",
1359 "\t\t<text><tspan>0.6</tspan>\n",
1359 "\t\t<text><tspan>0.6</tspan>\n",
1360 "\t\t</text>\n",
1360 "\t\t</text>\n",
1361 "\t</g>\n",
1361 "\t</g>\n",
1362 "\t<path d=\"M299.9,213.6 L299.9,201.1 M299.9,18.1 L299.9,30.6 \"/>\n",
1362 "\t<path d=\"M299.9,213.6 L299.9,201.1 M299.9,18.1 L299.9,30.6 \"/>\n",
1363 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(299.9,236.1)\">\n",
1363 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(299.9,236.1)\">\n",
1364 "\t\t<text><tspan>0.8</tspan>\n",
1364 "\t\t<text><tspan>0.8</tspan>\n",
1365 "\t\t</text>\n",
1365 "\t\t</text>\n",
1366 "\t</g>\n",
1366 "\t</g>\n",
1367 "\t<path d=\"M361.9,213.6 L361.9,201.1 M361.9,18.1 L361.9,30.6 \"/>\n",
1367 "\t<path d=\"M361.9,213.6 L361.9,201.1 M361.9,18.1 L361.9,30.6 \"/>\n",
1368 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(361.9,236.1)\">\n",
1368 "\t<g style=\"stroke:none; fill:rgb(0,0,0); font-family:Arial; font-size:12.00pt; text-anchor:middle\" transform=\"translate(361.9,236.1)\">\n",
1369 "\t\t<text><tspan>1</tspan>\n",
1369 "\t\t<text><tspan>1</tspan>\n",
1370 "\t\t</text>\n",
1370 "\t\t</text>\n",
1371 "\t</g>\n",
1371 "\t</g>\n",
1372 "\t<path d=\"M52.0,18.1 L52.0,213.6 L361.9,213.6 L361.9,18.1 L52.0,18.1 Z \"/>\n",
1372 "\t<path d=\"M52.0,18.1 L52.0,213.6 L361.9,213.6 L361.9,18.1 L52.0,18.1 Z \"/>\n",
1373 "</g>\n",
1373 "</g>\n",
1374 "\t<a xlink:title=\"Plot #1\">\n",
1374 "\t<a xlink:title=\"Plot #1\">\n",
1375 "<g style=\"fill:none; color:red; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1375 "<g style=\"fill:none; color:red; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1376 "\t<path d=\"M52.0,101.9 L55.1,102.0 L58.2,102.2 L61.3,102.5 L64.4,102.8 L67.5,103.3 L70.6,103.9 L73.7,104.5 L76.8,105.2 L79.9,106.1 L83.0,107.0 L86.1,108.0 L89.2,109.1 L92.3,110.3 L95.4,111.6 L98.5,112.9 L101.6,114.4 L104.7,115.9 L107.8,117.5 L110.9,119.2 L114.0,120.9 L117.1,122.8 L120.2,124.7 L123.3,126.6 L126.4,128.7 L129.5,130.8 L132.6,132.9 L135.7,135.2 L138.8,137.4 L141.9,139.8 L145.0,142.1 L148.1,144.5 L151.2,147.0 L154.3,149.5 L157.4,152.0 L160.5,154.5 L163.6,157.1 L166.7,159.6 L169.8,162.2 L172.9,164.8 L176.0,167.4 L179.1,170.0 L182.2,172.5 L185.3,175.1 L188.4,177.6 L191.5,180.1 L194.6,182.6 L197.7,185.0 L200.8,187.4 L203.9,189.7 L207.0,192.0 L210.0,194.1 L213.1,196.2 L216.2,198.3 L219.3,200.2 L222.4,202.0 L225.5,203.8 L228.6,205.4 L231.7,206.8 L234.8,208.2 L237.9,209.4 L241.0,210.5 L244.1,211.4 L247.2,212.1 L250.3,212.6 L253.4,213.0 L256.5,213.2 L259.6,213.2 L262.7,212.9 L265.8,212.4 L268.9,211.7 L272.0,210.8 L275.1,209.5 L278.2,208.1 L281.3,206.3 L284.4,204.3 L287.5,201.9 L290.6,199.3 L293.7,196.3 L296.8,193.0 L299.9,189.3 L303.0,185.3 L306.1,180.9 L309.2,176.1 L312.3,170.9 L315.4,165.4 L318.5,159.4 L321.6,152.9 L324.7,146.0 L327.8,138.7 L330.9,130.9 L334.0,122.6 L337.1,113.8 L340.2,104.5 L343.3,94.6 L346.4,84.3 L349.5,73.3 L352.6,61.8 L355.7,49.7 L358.8,37.0 L361.9,23.7 \" stroke=\"rgb( 0, 0, 255)\"/>\n",
1376 "\t<path d=\"M52.0,101.9 L55.1,102.0 L58.2,102.2 L61.3,102.5 L64.4,102.8 L67.5,103.3 L70.6,103.9 L73.7,104.5 L76.8,105.2 L79.9,106.1 L83.0,107.0 L86.1,108.0 L89.2,109.1 L92.3,110.3 L95.4,111.6 L98.5,112.9 L101.6,114.4 L104.7,115.9 L107.8,117.5 L110.9,119.2 L114.0,120.9 L117.1,122.8 L120.2,124.7 L123.3,126.6 L126.4,128.7 L129.5,130.8 L132.6,132.9 L135.7,135.2 L138.8,137.4 L141.9,139.8 L145.0,142.1 L148.1,144.5 L151.2,147.0 L154.3,149.5 L157.4,152.0 L160.5,154.5 L163.6,157.1 L166.7,159.6 L169.8,162.2 L172.9,164.8 L176.0,167.4 L179.1,170.0 L182.2,172.5 L185.3,175.1 L188.4,177.6 L191.5,180.1 L194.6,182.6 L197.7,185.0 L200.8,187.4 L203.9,189.7 L207.0,192.0 L210.0,194.1 L213.1,196.2 L216.2,198.3 L219.3,200.2 L222.4,202.0 L225.5,203.8 L228.6,205.4 L231.7,206.8 L234.8,208.2 L237.9,209.4 L241.0,210.5 L244.1,211.4 L247.2,212.1 L250.3,212.6 L253.4,213.0 L256.5,213.2 L259.6,213.2 L262.7,212.9 L265.8,212.4 L268.9,211.7 L272.0,210.8 L275.1,209.5 L278.2,208.1 L281.3,206.3 L284.4,204.3 L287.5,201.9 L290.6,199.3 L293.7,196.3 L296.8,193.0 L299.9,189.3 L303.0,185.3 L306.1,180.9 L309.2,176.1 L312.3,170.9 L315.4,165.4 L318.5,159.4 L321.6,152.9 L324.7,146.0 L327.8,138.7 L330.9,130.9 L334.0,122.6 L337.1,113.8 L340.2,104.5 L343.3,94.6 L346.4,84.3 L349.5,73.3 L352.6,61.8 L355.7,49.7 L358.8,37.0 L361.9,23.7 \" stroke=\"rgb( 0, 0, 255)\"/>\n",
1377 "</g>\n",
1377 "</g>\n",
1378 "\t</a>\n",
1378 "\t</a>\n",
1379 "<g style=\"fill:none; color:black; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1379 "<g style=\"fill:none; color:black; stroke:currentColor; stroke-width:0.50; stroke-linecap:butt; stroke-linejoin:miter\">\n",
1380 "</g>\n",
1380 "</g>\n",
1381 "</svg>"
1381 "</svg>"
1382 ]
1382 ]
1383 }
1383 }
1384 ],
1384 ],
1385 "prompt_number": 118
1385 "prompt_number": 118
1386 },
1386 },
1387 {
1387 {
1388 "cell_type": "markdown",
1388 "cell_type": "markdown",
1389 "metadata": {},
1389 "metadata": {},
1390 "source": [
1390 "source": [
1391 "The plot size is adjusted using the `-s` flag:"
1391 "The plot size is adjusted using the `-s` flag:"
1392 ]
1392 ]
1393 },
1393 },
1394 {
1394 {
1395 "cell_type": "code",
1395 "cell_type": "code",
1396 "collapsed": false,
1396 "collapsed": false,
1397 "input": [
1397 "input": [
1398 "%%octave -s 500,500\n",
1398 "%%octave -s 500,500\n",
1399 "\n",
1399 "\n",
1400 "# butterworth filter, order 2, cutoff pi/2 radians\n",
1400 "# butterworth filter, order 2, cutoff pi/2 radians\n",
1401 "b = [0.292893218813452 0.585786437626905 0.292893218813452];\n",
1401 "b = [0.292893218813452 0.585786437626905 0.292893218813452];\n",
1402 "a = [1 0 0.171572875253810];\n",
1402 "a = [1 0 0.171572875253810];\n",
1403 "freqz(b, a, 32);"
1403 "freqz(b, a, 32);"
1404 ],
1404 ],
1405 "language": "python",
1405 "language": "python",
1406 "metadata": {},
1406 "metadata": {},
1407 "outputs": [
1407 "outputs": [
1408 {
1408 {
1409 "output_type": "display_data",
1409 "output_type": "display_data",
1410 "png": "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\nFaCsDL6+YG8PPJfzQBBeyMN3p7W1VSLekZa1Hb2iZtw4CAqCsLDa6GhoboavvoKICOC8GCVqRs7n\nLFmv2JCH4F5WViYR70jL2o5esXnpdJg/H7Zvh7g40NSEHTsgMhJSUoDFEq1XhK2jV+zgmDuCyAAE\nATduwB9/QEcH6OvD3Lkwbpyk+4S8irQFIhxzRxAZgEL5Z2i+qQny8uD4cejshGnTwMMDZ80jbwCD\nO4LIGFpasGQJAACbDSUlsHs3NDWBvj4sXgxjx0q6c4jUIA9j7vn5+RLxjrSs7eiVNq+CAtjaQmQk\nxMWBlxf8+it89RXEx0NJiWi9wmWkecWGPIy5R0ZG7ty5U/xeucnajl558ra1QU4OkJMM3nsP3NzA\nwEAcXoGRGy+OuQsfOp0uEe9Iy9qOXpnwqqnB4sWweDEAAIsFRUVQUQHt7TB+PPj4/PMerNC9AjPS\nvGJDHoI7giBvREcHlix5MUBfVQVZWVBVBQQB06aBlxcMtiIfItvIw5j7oAu+i4hz586hF72y4jUx\ngaAgiIuDmBjQ0oLvvoOYGNi9G27cgP5+EXoHZaR5xYY83Ll3dHRIxDvSsrajVz68NBq4uoKrKwBA\nRwdcugTffAP9/XDz5hgGA2bOBCUlkfoHIq+fs8SRhweq0vYcA0FkkefP4fJl+OsvaG8HbW2YMwem\nTMHFbYaAtAUiIf/T1dfXr1u3zs7OTkVFhUKh1NTUcNfm5uZSXmXAMw0Wi7VixQotLS0Gg+Hl5VVZ\nWSnc7iEI8jZUVcHNDb78EuLiIDAQbt+GrVshJgYOHYI7dyTdOWToCHlYpqqqKj09ffr06XZ2dgUF\nBW88JiEhwfDlqqbKXK/W9fb2enh4sFis+Ph4BoMRGxvr7OxcVlamq6sr3E4iCMIbfX0IDHyx/ewZ\n/Pe/kJEBfX1ApcKMGTBrFqioSLR/CD8IN/cHm80mNxITEwGgurqauzYnJwcAbt68+cZzU1NTASA/\nP58sPnr0iEqlbtiwYVCpra3tsDotKHKTtR296OXT295O5OQQ27YRGzcSGzcSP/9MPHkiDq8oELpX\n2jIxiWrM/dtvvw0NDa2urjY2NubszM3NdXd3v3nzpomJCTluw32Kn5/flStX6urqOHvmzZt39+7d\nQSfDSNtQF4KMBNrb4dIluHwZWlpAWRlsbMDeHoyMJN0tySFtgUgCs2UcHBxaW1vpdLqnp+euXbtM\n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\n3r33339fXV3dxsampKREQ0PD2NgYAFpaWkpLS52cnMjDioqKrK2tyUuoqalpaWmxsbEhqzIzMxcs\nWEBuD2ghIyNDWVl5OC0I1oeKigrSK5Sr4L8FgiBIr9A/Sd4t1NTUkF6hf5K8WygsLFRWVhb1v+br\nLWRnZysrK4vzG0W2kJ2d3dnZKc5vFNlCdnZ2ZWWlOL9RZAvZ2dnnzp0bUgslJSUPHz58PcKQ25Ja\nmP6tEIJy+fLlt7XT1dXl6emprq7+999/c+8fP368p6cn956IiAgKhdLR0TFoLYIgCMI/gt+5W1hY\nFBcXv76/p6fnww8/vHjx4h9//DFlypQBp1y9epV7T3l5uYmJiYqKyqC1CIIgCP8IPuaupqbmwAW5\ns6+vb9myZXl5eVlZWXZ2dgNO8fX1raurKyoqIot1dXV5eXmcn0W8axEEQRD+EfJ67p988smBAweC\ngoLc3d05O83MzMhBrt7eXltb26dPn27fvl1VVTU2NrahoaG0tFRPT2/QWgRBEGQICHeUZ8BcRpLg\n4GDOAY8fPw4ICNDQ0KDT6R4eHhUVFdyn865FEARB+EQeMjEhCIIgA8BVIREEQeQQDO4IgiByCAZ3\nBEEQOQSDO4IgiByCwR1BEEQOweCOIAgih8hwcBdDTj7+FfX19evWrbOzs1NRUaFQKDU1NeLxDprX\nUETeixcv+vj4jB07lkaj6enp+fr6Dlg6QkRebvz8/CgUyscffywGb25uLuVVhrNK1FCv9+zZs46O\njgwGQ11d3c7OjvMWt+i8CxcupLzGjBkzRO0FgKKiIldX13feeWf06NHTp08/fvy4YNKheouLi52c\nnOh0uqam5rJlyzhZKGQYSU+0F5Cenh5ra2s9Pb0DBw6kp6dbWVnp6Og8fvxYUori4mIdHR1vb28y\n2Uh1dbV4vE5OTjY2Nlu3bk1NTY2MjKTT6e+9996zZ89E7T169OiHH364c+fO1NTUuLg4ExMTKpU6\nYJ04UXg5ZGZmamlpUanUjz76SADpUL05OTkAkJCQkPGS06dPi8FLEMS+ffsAwN3dPTExMTk5OTg4\n+MSJE6L2Xrp0KYOLuLg4AIiKihK19+rVq1Qqddq0aWlpaSdPniRXC09LSxO196+//lJSUpoxY8ax\nY8d+/PFHQ0NDMzOztrY2AbzSg6wG99TUVADIz88ni48ePaJSqRs2bJCUgs1mkxuJiYnDDO5D8t6+\n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\nY2RHRMr/A5YdmP24XbLsAAAAAElFTkSuQmCC\n"
1410 "png": "iVBORw0KGgoAAAANSUhEUgAAAfQAAAH0CAIAAABEtEjdAAAABmJLR0QA/wD/AP+gvaeTAAAgAElE\nQVR4nOzdeVxUZfcA8DNsw76obLKDCMhqvMYiigkIKlLugktpby6JYqBCWIkFmomYu1D5KxN9RV/N\nXg0UN1wSUwtcMkVkUQFRttjX+/vj6jQiDgPMXebe8/30x8xdnuccJo7DnTvPERAEAQghhLhFgekA\nEEIIyR4Wd4QQ4iAs7gghxEFY3BFCiIOwuCOEEAdhcUcIIQ7C4o4QQhyExR0hhDgIiztCCHEQFneE\nEOIgLO4IIcRBWNwRQoiDsLgjhBAHYXFHCCEOwuKOEEIchMUdIYQ4CIs7QghxEBZ3hBDiICzuCCHE\nQVjcEUKIg7C4I4QQB2FxRwghDsLijhBCHITFHSGEOAiLO0IIcRAWd4QQ4iAs7gghxEFY3BFCiIOw\nuCOEEAdhcUcIIQ7C4o4QQhzEruJeXl4+e/bsfv36aWpqBgUF3blzh+mIEEJILgkIgmA6hudaW1uH\nDRtWXl4eHx+vqamZkJBQVlZ248YNQ0NDpkNDCCE5o8R0AP/Yt29fbm7umTNn3nrrLQDw9va2sbHZ\nsGFDYmIi06EhhJCcYdE798mTJ1+5cuXRo0eiLePGjbt37979+/cZjAohhOQRi665375929HRUXyL\nk5PTgwcPmpqamAoJIYTkFIsuy1RWVrq5uYlv0dPTIwiiqqrK2NhYwoklJTBwIMXBAQBAYyO87h8a\nLS1QYtHPEiHEd1woSLa2GzQ1BygpKQFAc3NzW1ubhoYGuauqqkpPT08oFBoaGj558kRVVVVHRwcA\nmpqaysvLzc3NycOKi4sNDAxUVVUBoKampqWlVl/fVEGhTSAg/vrrvpOTRUuLqopKU2lpibZ2R//+\n/QGgsbHx0aNHtra2LS2qHR2CgoICY2NjRUXtjg6lmpqapqYm0efAeXl5tra25OMuYyAIUFFpfvjw\nlpVVPz09RaGwqaLiQVNTmZublVDYpKDQcfTo0bfffpscIScnp6Kiws/PDwCqq6tzc3N9fX3JXVlZ\nWa6urrq6ugBQWFhYXV0t+sey0wi6urqWlpbyMgIAkIPIdRbSj5CTk+Pm5ibvWUg/Qk5ODgDIRRY5\nOTnFxcWv++3W0dHJyMgA1mDRNXc7OzsrKyvxn87KlSsTExPr6+vV1NQknGhhYVFUVER9gBSqrYW/\n/4aaGqipef6guhqqq+Hvv6G1FQBAIACBABQVQVkZUlO/SkpaaWICxsZgaAgCAdPRU2zkyJHnz59n\nOgr6xMXFxcXFMR0FfTiTL9sSYdE7d0dHx6tXr4pvuXXrlrW1teTKDgCmpqZUxkUHLS3Q0gITk+6P\nbGmBsrJWfX14+BB++w2ePQOCAAUFEAiAIGDAAHBwAAcHGDCA+qDp4unpyXQItLp+/TrTIdCKb/nS\nhkXFPSQk5MiRI1lZWeRfQ48ePTp9+nR4eHi3JyorK1MfHVuoqIChYauHR9d7m5vh/n04exbu34fm\nZlBTA4IAGxuwtgZHR1BVpTdWGVFXV2c6BFrp6+szHQKt+JYvbVhU3GfOnJmUlBQWFhYfH6+hoZGQ\nkKCjo7N8+XKm45InQiE4OoL4PUf19fDXX/DXX3DiBABAezsYGICvL9jbMxUj6obooyCe4Fu+tGFR\ncVdWVs7MzIyMjIyMjGxpafHx8dm/f7/k+2RIlZWVNITHHj268V9DA9zdwd39ny21tXDlChw6BG1t\noKMDw4bBm2+Ciors45QV/KIDQr3AouIOAIaGhqmpqT09q5X8zJE3Ghoa+nK6lhb4+4O/PwBAfT1c\nvgxbtkB7O3R0wLBhMGIECIWyiVNW+piv3KmpqWE6BFrxLV/asKu49w7fFp9xcXGR1VAaGv8U+upq\nuHABNmyAjg4wMIBp06BfP1nN0ycyzFcu3Lhxg+kQaMW3fGnDheKOZEJXFyZMgAkTAABKS2HfPigq\nAmdnmDwZXnxtANFhxIgRTIdAK77lSxss7qgLxsZA3qZ0+zZs3gyVlRAUBH5+3L+nHiHO4EJxl/dv\nMPVUVlYWbXOR9960tMCJE7B8Oairw5w58OIbeTShM182sLa2ZjoEWvEtX9qwaOGwXnv33XeZDoFW\nZ8+epXlGFRWYMAE2boSPPoKzZ2H+fNi8GZ49o2l2GvLdtm2b4AUtLa2hQ4fu2rWrvb2d6nmXL19u\nZGTUaeOcOXOomMvf3z84OFjCAcuWLRs7dqw0p4v/uBQVFU1NTUNDQ8Vvalq/fr27u7uU336nKF9E\neXGXvrnSqVOnBC8bwKXvWXJCv34wfz6kpMCwYfD115CcDC0tTMckOzt37vzf//63a9cuExOTRYsW\nrVq1iumI6JOXl7djx47PP/9c+lPIH9fhw4cjIiJOnz7t7+9fW1tL7goPDy8uLt67dy81wSKpUHtZ\nprW1dcyYMeXl5YmJiWRzpVGjRklurpSUlGRmZkY+FrLtpjz0grc3eHvD48fw5Zdgagpz5nBhUcxR\no0bZ29sDQGhoqJub2/bt2xMSEhQVFZmOiw5JSUkuLi7Dhg2T/hTRjwsAjI2NZ8+enZ2dHRAQAAAa\nGhqzZs3asGHD7NmzKQkXSYHad+5kc6XU1NR58+ZNmzbt+PHj1dXVGzZskHBKQEDAlBcmkLdudIdv\na1OkpKQwHcJzJibw2WcwfDisWQOHDgFFa9DRn6+CgoKnp2ddXV1FRcWtW7dCQ0MtLCxUVVVtbGyW\nLFkifl92UVHRjBkzjIyMhEKhiYnJO++8Q757fd32LmVnZ3t4eKiqqpqbmyclJYm2S56avKRz4cIF\nT09PNTW1QYMGbdmyRXzYgwcPOjg4qKqqDhky5NChQxLybWxsTE1NDQsL693pANCvXz94+RsnoaGh\nN2/ezM7Olnwiog61b7d+/vlnExMTsm0eAJiamvr5+f3000+SO+c1NDSoqakJpL4zg29rUzg4ODAd\nwkvs7OCLL+DKFYiOhsBA8POT8fiM5FtQUKCkpKStrX316lUrK6upU6f279+/oKBg3bp1f/zxx8WL\nF8nDpkyZ0tzcvH37dmNj49LS0hMnTrS0tEjY/qq6urrp06dHR0fb2dkdOXIkKipKXV194cKFAFBU\nVCRhagCorq5eunTppk2b7O3tDxw4EBERYWtrS143P3v27PTp0ydMmLBp06anT59GRka2tbW98cYb\nXcbw66+/1tbWit+SKM3pDQ0NdXV17e3t9+7dW716tYmJiWiNXABwd3dXV1fPyMjg27pvLEJQyc7O\nbsyYMeJbVqxYIRAIGhsbXz04MzMTAMi1ztXV1SdOnHj//n1pZlm9erVMokV9l5lJREURV68yHUcP\nbd26FQCuX79eW1v7+PHj9evXA8A777zz6pF//PEHANy4cYMgiJaWFoFA8N1333U65nXbXxUVFQUA\nqampoi3Tpk0zMjJqbW2VPLXo3N9++010gKur6+zZs8nHI0eOdHBwaG9vJ59evnwZAMaPH99lGAkJ\nCQDQ1NQk2iL5dPLHJc7KykoUmIiHh0dgYGC3PwTOYFshovade4+aK2lra4eHh48YMUJDQ+PatWtJ\nSUne3t45OTnSLC+DWMLfH0aPhsOH4eBBeP99GDyY6YB6wv3FEjwCgWD69Onbtm0DgNbW1q1bt6am\nphYXF4surdy9e9fZ2VlZWdnV1fXzzz+vq6sbPXq0k5MTufd127skEAgmT54sejpt2rS0tLTCwsJB\ngwZJmJp8rK6uLn6V3MbGpri4GAAIgrhy5Up0dLSCwvPrrp6enlZWVq+LobS0VFNTU/QRl5Snp6am\nmpubEwTx+PHjzZs3BwYGnj9/ftCgQaIDBgwY8PDhQwm5k1JS4MGDbo+iibU1zJ/PdBCyIqt/Jdra\n2qrEkBv19fWnT58uftjatWsBoKSkpNsBybubo6Ojuz3SwsJiwYIF0dHR0dHR06dPDwwMjH7B3t4+\nOjo6OTmZIIjk5OTMzEzylPz8fPGRo6Oj8/PzyceZmZnk8aSpU6eKHrNkhL179zIeQ7cj1NUR//73\nvfHjr1dX9zWGwsJCySP0HflWNDU19cKFCzk5OTU1NaJdy5YtU1NT+/rrr69cufLnn39euHABAH78\n8Udy76NHj/7973+TNwiYmppu3LhR8vZOoqKidHV1xbeQ4587d67bqaOiogwNDcXPnT59uoeHB0EQ\nz549A4Bdu3aJ7x0+fPjr3rkvWLCAfNdF6vZ08sd1584d0d6qqio1NbU5c+aIn/LOO+/Y29t3OaOc\nCgwMlFBqgoODmQ7wJTIr7uQfbp3+zRg8eHCnv8vIyzINDQ3SjGlubj569OhuD5PmGC6Jj49nOgRp\nPX1KfPIJkZPTp0FoyPfVaiUyYMAA8X97yH4yogorcvPmzY8++ggA0tLSpNlOioqKEggE4tdDyI8u\n8/Lyup1aQnHv6OgQCoXr1q0T3+vg4PC64v7JJ58oKCiILsJ0e3qXPy5bW1s3NzfxLSNHjhwxYkSX\nM3IS2y7LyOxuGUdHxwtiRBtv374tfpiUzZVIbW1t0nysyre1KeTo/usBA+CLL+DPP2Hr1t7fS8Ng\nvgRBNDQ0kO03SWlpaV0e6eTktHHjRqFQeOvWLWm2i09x8OBB0dP//Oc/xsbGlpaW0k/9KoFA4OHh\ncfLkSdGWwsLCe/fuve54Z2fnjo6O/Pz83p0OAE+fPi0uLu50a8Pdu3f5tugbq8jsmruWlpaPj0+n\njT1qrtTW1qYkdrP08ePHS0pK5s6dK6sIEVNCQ+HOHfjkE1i+HPT0mI6mJwQCQUBAwDfffBMSEmJu\nbn7gwIE9e/aI9hYVFYWFhYWGhg4ePFhBQSEtLa21tdXf3/9127ucQkNDIzY2trKy0t7e/vDhw4cO\nHdq1axf5iyBh6m7FxcX5+fklJCSEh4eXl5fPnTtX9fWNuHx9fQUCwZUrV0S9nqU5/dy5c+QtDyUl\nJTt27GhpaRH/1S4sLHzy5ImfzO+dQtKj9O+ClpYWZ2fngQMH7t69+8CBAy4uLvr6+qIL7idOnFBU\nVBTdKhAYGDh37tyvv/76u++++/DDD1VUVMzMzMrLy7udhW1/DaEu1dYS0dHE5ctMx9EVCZdlysrK\npk6dqqurq6WlNXbsWPJORPLaSHV19bx58+zs7NTV1XV0dLy9vY8ePSph+6vISyvZ2dlvvvmmUCg0\nNTVNTEyUZmpC4mUZ0oEDB+zs7FRUVGxsbHbu3Onn5/e6yzIEQQQFBU2cOFF8i4TTO90tY2Bg4O/v\nf+rUKfHTN27cOGDAAPErTpzHtkJEbXEnCKKsrCwsLExXV1ddXX3MmDG3b98W7UpPTxf/nzUxMdHd\n3V1XV1dJScnMzGz+/PmlpaXSTMGr63oEQcTGxjIdQu/t20ds3kx0dPTgFLnOV15kZGSoqKiUlZXJ\nakAXF5ePP/5YVqPJBd4VdxqsWLGC6RBo9fTpU6ZD6JPffyeioojKSmmPl/d85YW/v/+yZctkMtSR\nI0cGDBhQLbpTih/YVtzlf0EQAHV1daZDoJW8r6c2dCjY2MAXX8DkySDNtxflPV958f333//1118y\nGcrS0vL06dPkFxIRU7hQ3JHc0daGDRvghx/gjz9g0SKmo0EAAGBiYmJiYiKToTp9dRExggvruYsv\nJM0HGRkZTIcgG+++C8OGQWQkVFdLOowz+UoJ80UywYXi3tDQwHQItHpGW5sM6v3rXxAdDatWQVXV\na4/hUr7SwHyRTHChuPPtixKzZs1iOgRZMjSEDRsgLg4qKro+gGP5dgvzRTLBouJeUlKydOlSLy8v\ncr3fwsJCpiNCNFFXh7VrYc0aqKxkOhSEuIJFxf3BgwcHDhzo37+/l5cX07EgumlowBdfwOrV8Pff\nTIeCECewqLh7e3s/efLk2LFjISEhPTrx2LFjFIXETgsWLGA6BEro6MAXX8CqVdCpZxFX830dzBfJ\nBIuKu2jx6J6S3NOde5KTk5kOgSq6uvDZZ7BiBdTV/bORw/l2CfNFMsGi4o4QAOjrw+efQ2wsNDYy\nHQpC8gyLO2IdAwNYuRIiI6GpielQEJJbzBT39vb2ajF9HG3Hjh0LFy6MiYmJiYmZMWNGUFBQzAsO\nDg4xMTEpKSkAkJKScurUKfKUBw8exMTEiEaIiYl58KLT16lTp8jjSdOmTRM9ZskIZPMHec9C8gim\nphAbC9OmPdqx4zvRIHKXRe9GIA+W9yykHyElJYXxGKQcISUlpcsKQ7p+/TqwCiMr2nTZtklk06ZN\nAFBQUCDlaHPnzpVxfOx2/vx5pkOgyf37RHg4cebMBaYDoRV/Xl8SZ/LFhcMAXrRtktVo5ubmshpK\nLvCn85SNDSxdClu2+IwYAUq8WQaJP68viW/50oaZ35gu2zYh9CpbWwgPh8hI2LQJFBWZjgYh+cGi\nD1QJgjh06NChQ4dyc3MBID09/dChQ5cuXer2xJqaGuqjY5GioiKmQ6CVqmrRv/8NK1dCRwfTodCC\nb68v3/KlDYuKe3t7+9SpU6dOnfr9998DwIcffjh16tR169Z1e+KNGzcoD45N9u7dy3QItNq7d6+L\nC0yeDLt2MR0KLXj4+jIdAjcJiF43pWeNuLi4uLg4pqNAlNu9GxwcABenQOzEtkLEonfuCEk2bx78\n9JOkxYERQiJY3JE8+fhjWLuW6SAQkgdcKO5nzpxhOgRarVq1iukQaCWer64uTJ0KP/7IYDiU4/Pr\ni2SIC8XdU5ouyxwi+oYqT3TK98034dkzuHOHqXAox/PXF8kKtcW9R/03Tp06JXiZlG3v1dXVZROu\nnJDyx8IZr+YbEQHJyZxdWQxfXyQT1H6Jiey/MWzYMC8vr7Nnz0pzSlJSkpmZGflYKBRSGR2SVwoK\nsGIFfPUVrF7NdCgIsRW179x70X8jICBgygsTJkyQ5pT79+/3IUb5w7du8V3ma2ICHh5w9Cj94VAO\nX18kE9QW997132hoaOjR3fcNDQ29mEV+8a1b/OvyDQqCP/6A4mKaw6Ecvr5IJlj3gaqPj4+Ghoam\npuakSZPy8/OlOcXFxYXqqFiFb93iJeT78ceQlATt7XSGQzl8fZFMsGipPW1t7fDw8BEjRmhoaFy7\ndi0pKcnb2zsnJ8fY2Jjp0BBLCYUQHg5btgDecIFQJzJ75973/htvvvnm1q1bp02bNn78+NWrV//v\nf/8rLy/fvHlztyfu3buXV806cATxEQYNgo6Op2Fh38h1FjiCXIzA02Ydsu2/QTI3Nx89enS3h7m7\nu/doWHk3f/58pkOglTT5xsQQz57REAsd8PWVU5xt1iHb/huktrY2gUDQ7WHBwcGynZfl+NYtXpp8\nV62C+Hj48ksawqEcvr5IJmRW3Pvef6OtrU1JrN3O8ePHS0pK5s6d2+fQEPdpasKUKfDdd/D++0yH\nghA7UPuBKkEQ//3vfwFA1H9DX1/f2Nh4+PDhAHDy5Mlx48bt2bMnLCwMAIKDgwcOHOjq6qqlpXX9\n+vVvv/3WzMwsIiKC0ggRZ/zrX3D5MuTmgqsr06EgxAaUXvRpbW19dcbx48eTe9PT0wHgxx9/JJ8m\nJia6u7vr6uoqKSmZmZnNnz+/tLRUmlmCg4OpSoCVkpOTmQ6BVtLn295OLFlCtLVRGg7l8PWVU5y9\n5t4lJSUl4vVfRwoKChLfGxUVFRUV1YtZ9PX1exOc3HJwcGA6BFpJn6+CArz/Pnz7LSxYQGlE1MLX\nF8kE677E1Avm5uZMh0ArvnWL71G+rq5QWAi9uheXLfD1RTLBheKOkLiPPoJt25gOAiGmcaG419TU\nMB0CrfjWLb6n+RoYgFAIeXkUhUM5fH2RTHChuN+4cYPpEGjFt27xvch3yRKQ35un8fVFMiGQ8IGn\nvGBb03HEBvv3g4kJjBzJdByIN9hWiFj0zv3s2bNz5861tbVVV1e3sbFZvHhxeXk500EheTVjBhw8\nCB0dTMeBEENYtCrkmjVrampq5syZY25u/ueff27bti09PT03N1dLS4vp0JD8EQhg5kxITYXZs5kO\nBSEmsOide3Jy8h9//PHpp5++++6769ev/+abbwoKCg4ePNjtiWfOnKEhPPbgW7f4Xufr6Qm5uVBf\nL9twKIevL5IJFhV3Ozs78aejRo0CgMePH3d7oqenJ0UhsRPfusX3Jd+ICNixQ4ax0AFfXyQTLCru\nnVy6dAkAnJ2duz1SXV2d+nBYhG/d4vuSr5kZNDXBw4cyDIdy+PoimWBpca+srFyxYsXQoUOl7JGN\n0OssWyZ/b94R6jtmirvktk2NjY2TJk2qr69PS0tTVFTsdrSUlBRedWJat24d4zHQOUJGRkZfRti/\nP8XGBq5dk5ufA5kvO18LKkbIyMhgPAYpR+BpJ6YekdC2qampKTAwUEdH5/fff5dytIkTJ1IQI3uJ\n1tHkib7n29ZGLFxIdHTIJBzK4esrp/i1KuTrvK5tU0tLy5QpUy5dunTy5MmhQ4dKOZqLi4tMo2M7\nvnWL73u+ioowdSocOQKTJskkImrh64tkgpni3mXbpra2thkzZpw+fTo9Pd3Ly4uRwBBXjR4NEREw\nfjwIhUyHghAtWPQlpoULFx45cmT+/PlPnz49dOgQuXHQoEFubm7MBoa44cMPITkZli5lOg6EaMGi\nu2Wys7MBICUlZaqYb7/9ttsTjx07Rn10LLJArltR9Jys8rWzg2fP4NkzmQxGIXx9kUzgwmGIR6qq\n4OuvYc0apuNAXMS2QsSid+4IUU1PD/r3h9u3mY4DIephcUf8smgRSHGpDyG5x4XizrrvDlBM/FsY\nfCDbfJWVYfhwOH9ehkPKGL6+SCa4UNz19fWZDoFWfOsWL/N8p0yBX36R7ZCyhK8vkgkuFHdzc3Om\nQ6AV37rFU5GvvT3k5sp8VNnA1xfJBLXFvUfNlU6dOiV4GS4XhygSFgZpaUwHgRCVqP0SUy+aKyUl\nJZmZmZGPhdJ9m7CmpkY24cqJoqIiCwsLpqOgDxX5qqhAv35QWgrGxrIdWAbw9UWyQenKNX/99Zf4\n09TUVAD47rvvujw4MzMTAG7evNnTWUaPHt3L+ORTfHw80yHQiqJ8KyuJtWupGLiv8PWVU2xbOIza\nyzK9a67U0NBA9OSrVXy7Zse3tmQU5aunBw0NUFdHxdh9gq8vkglaP1CVprmSj4+PhoaGpqbmpEmT\n8vPz6QoN8dG8ebB3L9NBIEQN+hYO67a5kra2dnh4+IgRIzQ0NK5du5aUlOTt7Z2Tk2PMwsuiiBOs\nrCAvD9rbQYqWMAjJG1ld32lra6sS02lvQ0ODr6/vgAED8vLypBwwKysLAKKjo7s9Uk9Pb8GCBdHR\n0dHR0dOnTw8MDIx+wd7ePjo6Ojk5mSCI5OTkzMxM8pT8/HzxkaOjo/Pz88nHmZmZ5PGkqVOnih6z\nZITQ0FDGY6BzhNjYWOpiuHiROHyYXT8HMl92vhZUjBAbG8t4DFKOkJyc3GWFIQUHBxNsIrPiLtvm\nSiRzc3NpPixdsWJFz2KVc0+fPmU6BFpRnW9UFKXD9xi+vnKKbR+oyuyyjGybK5Ha2toEAkG3h6mr\nq/doWHnHt9v/qc7XwwMuXwb2tIfB1xfJhMyKe9+bK7W1tSkp/RPP8ePHS0pK5s6dK6sIEerSpEmw\nahWLijtCMkHt3TJkc6XZs2eTzZVIOTk55N6TJ08qKSnt27ePfBocHDxv3rzNmzfv3r178eLFkyZN\nMjMzi4iI6HaW+/fvU5gD+2RkZDAdAq2ozldREUxNgT13ZuHri2SC2rtlRM2VxBd+W7x48bZt2wCg\no6Ojvb29o6OD3B4QELB///4jR47U1dUZGxu/9957a9askWZRsIaGBmrCZ6ln7G8mJFM05Pvuu5CY\nyJYmHvj6IpnATkwIAQDExcGSJdC/P9NxILnFtkLEhVUhEeq7Dz6AH35gOgiEZIcLxR2bdXAbPfma\nmEBZGbS00DBVN/D1RTKBxV3+8O2XgbZ8Z82C//yHnqkkwdcXyQQXivvgwYOZDoFWwcHBTIdAK9ry\ndXGB69eB8Q+h8PVFMsGF4o6QrIwZA6dOMR0EQrLAouJ+6dKl4OBgU1NTVVVVY2PjkJCQq1evMh0U\n4pdx4yA9nekgEJIF+laF7FZhYaGamlpERISBgUFZWVlKSoqPj092dna3ixaUlpbSEyFL8O0zBjrz\nFQjAwQFyc8HVlbY5O8PXF8kEi4r7zJkzZ86cKXo6Y8YMS0vLH3/8sdvizre1ZaT5YheX0JzvnDmw\nZg2TxR1fXyQTLLos04mRkZGSkpKiFCtt6+jo0BAPe5ibmzMdAq1ozlcoBG1tYPCvQXx9kUywrrg3\nNjbW1tbevXv3gw8+UFdXf//995mOCPHO++/Dd98xHQRCfcOiyzKkgIAAshufkZHRiRMn7O3tuz2l\nubmZ+rhYpKamhukQaEV/vvr6UFcHdXWgqUnzzAD4+iIZYaa4t7e319bWip7q6uqKHu/cubOqqqq4\nuHj79u3jxo07ceLEsGHDJI928+bNoUOHqqqqAkBNTU1TU5OhoSG5Ky8vz9bWVkdHx83NLScnR1dX\n19LSEgCqq6tzc3N9fX3Jw7KyslxdXckwCgsLq6ur3dzcyF1Hjx59++23yccsGeH27dtCoVDes5B+\nhMLCQjJfOmMwNx87ZYqTm9tv9P8c0tPThUIhO18LKkZIT0+/c+eOXGSRk5NTXFz8aoUhH7NtYXpm\nFg7Lzs4WX969yxgaGxsHDx5sb2+fmZlJY2gIPVdRgeuIITnGzDv317VtEqempjZkyJC7d+/SExJC\nnWBlR3KNRUv+tre3i98b8+TJkyFDhgwdOvQUfmUQIYR6iEUfqI4dO9bc3NzFxUVHR6egoGD37t11\ndXWffvop03EhhJD8YdE79507d6ampv711191dXWmpqaenp4xMTFOTk5Mx4UQQvKHRcUdIYSQrLDu\nS0wIIYT6Dos7QghxEBZ3hBDiICzuCCHEQVjcEUKIg7C4I4QQB2FxRwghDsLijhBCHITFHSGEOAiL\nO0IIcRAWd4QQ4iAs7gghxEFY3BFCiIOwuCOEEAdhcUcIIQ7C4o4QQhyExUSagjEAACAASURBVB0h\nhDgIiztCCHEQFneEEOIgLO4IIcRBWNwRQoiDsLgjhBAHYXFHCCEOwuKOEEIchMUdIYQ4CIs7Qghx\nEBZ3hBDiICzuCCHEQVjcEUKIg9hV3MvLy2fPnt2vXz9NTc2goKA7d+4wHRFCCMklAUEQTMfwXGtr\n67Bhw8rLy+Pj4zU1NRMSEsrKym7cuGFoaMh0aAghJGeUmA7gH/v27cvNzT1z5sxbb70FAN7e3jY2\nNhs2bEhMTGQ6NIQQkjMseuc+efLkK1euPHr0SLRl3Lhx9+7du3//PoNRIYSQPGLRNffbt287OjqK\nb3Fycnrw4EFTUxNTISGEkJxiUXGvrKzU09MT36Knp0cQRFVVFVMhIYSQnGLRNfdeU1ffoqWlpaSk\nBADNzc1tbW0aGhrkrqqqKj09PaFQaGho+OTJE1VVVR0dHQBoamoqLy83NzcnDysuLjYwMFBVVQWA\nmpqapqYm0ae4eXl5tra25GPmRvjL3n5QSckzE5P+ZWWlGhoKRkZqKiqtzc1VDx/++a9/2SkodADA\n77//bmtrq6WlBQClpaW1tbWDBw8mR7hwISMgwJd8fPfuH3p66uS89fVPb9267uv7fFdWVparq6uu\nri4AFBYWVldXu7m5kbuOHj369ttvk49zcnJ0dXUtLS0BoLq6Ojc3V7YjqKioeHl5MRsDDSPk5OQA\ngLxnIc0IhYWFbm5u8p6Frq5uTk5OcXHx6367a2trb926BazBomvudnZ2VlZWGRkZoi0rV65MTEys\nr69XU1OTcOLIkYHnz5+gPkCGxcXFxcXFAcDff0NrK9TUQFMTNDZCbS20tb10ZF0dtLa+tKW+Hlpa\nXtrS0ADNza+dq7ERmppAVRXU1J7PIk5FBVpaQEUFBAIgCFBVhaYm0NCA5mYQCkFZGTQ1QV0dhELQ\n1gZlZdDRARUV0NAADQ1QUQFdXRAIpMqU23iSJvAm01GjRp07d47pKP7Bonfujo6OV69eFd9y69Yt\na2tryZUdAIqK/qIyLrY4c+YM+RuirQ0A0L8/s+G8Vmsr1NU9/8eD/Heoqgqam6Gh4fm/MdXVQL6j\naG+Hjg7o6Hhe69vbobUVBAJITTXV1QUNDejfH/r1++c/dXVmM0NIkoKCAqZDeAmLintISMiRI0ey\nsrLIv4YePXp0+vTp8PDwbk80NTWlPjrmeXp6Mh2CVJSVQU8PXv70pGcaGgpCQ6G2FiorobISbt58\n/qChoYuDDQzAwACMjcHI6PljeXH9+nWmQ6AJTzJlWyFiUXGfOXNmUlJSWFhYfHy8hoZGQkKCjo7O\n8uXLuz1RWVmZhvAYp86bN67a2sqGhiDld9fKy6G8HEpL4Y8/4MkTePoUAIAgnl8yEgrBwABMTMDU\nFMzMwNiY0sB7Rl9fn+kQaMKTTNlWiFhU3JWVlTMzMyMjIyMjI1taWnx8fPbv32/Mql9HxD7ku3Un\np673trRAeTk8fgyPHkF2NpSXg4ICEAQoKICSEhgYgJkZWFiAmdnzi110En2Wznn8yZRVWFTcAcDQ\n0DA1NbWnZ1VWVlIRDNvw58tcMsxURQVMTaHLP5cJAp48gcePIT8fzp6F2tp/dhkYwKBBYGMDJibd\nfPaLkAjbChG7invvtHa6NYSjGrq85MxF9GQqEICRERgZgbt7511Pnjyv+I8ePb/CAwDa2jBoEDg4\ngKzehtbU1MhmINbjSaZsK0RcKO48WVnMxcWF6RBownim5BV/b++XNv79N+TlQVYWPHz4vOKrqoKD\nAzg4gIVFb97g37hxQ1YBsxxPMmVbIeJCcUeIBtra4O7+0tv8pia4cwd+/RX27QOA57f829uDmxuY\nmHQ/4IgRI6iKlWX4kymrYHFHqJdUVWHoUBg69J8tzc1w5w6cPAmPHwMAKCiArS0MHQo2NnjtHtGN\nRWvL9FpRURHTIdAhKyuL6RBoQn+m6enpb731lqGhobq6urW19ZQpU06dOkXuOnPmzJdffinlOEIh\nuLnB3LnwySfwyScQGwvDh8OdO7BpE6xfD+vXw5YtcPHi8xv2ra2tly9fbmRkRFFSnfj7+wcHB0s4\nYNmyZWPHjpXm9G3btgleUFRUNDU1DQ0NFf8YfP369e7u7qJvv1tbW8siA7ZjWyGitbiXlJQsXbrU\ny8tLTU1NIBAUFhZ2OqB3nZjeffdd2cfKPmfPnmU6BJrQnOnu3bvHjRtHEER8fPz333+/YMGCioqK\nX375hdzbo+L+qoEDYcIEiIyE6GiIjoaJE6GyErZsgfh4KC6e89dfbu3tZjLKo0/y8vJ27Njx+eef\nS3/Kzp07//e//x0+fDgiIuL06dP+/v61L245Cg8PLy4u3rt3L/l0zpw5so+YfdhWiGi9LPPgwYMD\nBw4MGzbMy8vr1V/g1tbWMWPGlJeXJyYmkp2YRo0ahZ2YENWSkpKcnJxOnz6tqKhIbomOjm7ptBaP\njJiZgZkZhIQ8f7pw4YNLlxw2boS2NmhsBEdHGDlS2m9vyVZSUpKLi8uwYcOkP2XUqFH29vbkY2Nj\n49mzZ2dnZwcEBACAhobGrFmzNmzYMHv2bErCRVKg9Z27t7f3kydPjh07FiL6v1sM2YkpNTV13rx5\n06ZNO378eHV19YYNG+iMEPFQdXW1hYWFqLKTVFRUAGDZsmUJCQk1NTXkJQjR98tPnjzp7e2tpqam\no6MzYcKEP//8U3QieaXll19+cXNzU1VVNTc3T0pKet3Umpp/C4Unhw/PPnzY48svdZYseWfRorPx\n8fDFF7BzJ/z00/3Q0DALCwtVVVUbG5slS5aI31NITnThwgVPT081NbVBgwZt2bJFfPCDBw86ODio\nqqoOGTLk0KFDEn4CjY2NqampYWFhvTsdAPr16wcv3wsYGhp68+bN7OxsySciChFM2LRpEwAUFBSI\nb5w0aZKJiYn4lrFjx9rY2HQ7WnBwsGzDY6fk5GSmQ6AJzZlOmTJFSUkpMTHx4cOHnXZVVFSEh4dr\naWkVFBQUFBSQB5w8eVJRUdHPz+/o0aP79u2ztbXV1dUtLCwkT4mKilJRUbGzs7t8+XJ1dfW3336r\noqKyc+fOLqeOiorS0NAwNzffvn37qVOnFi9eDADkweXlRGzstZEjM6dP/zM8PG/16v/Z2joMHz5c\n/FyhUOjm5nb27NnS0tKvv/4aAH755Rdy75kzZwQCQUhISHp6+p49e8zMzIyNjcePH99lGOQHDL/9\n9ptoi+TTt27dCgDXr1+vra2trq7+7bff/vWvf5mYmNTV1YlGaGtrU1dXX716dQ9eCTnHtkLEouJu\nZ2c3ZswY8S0rVqwQCASNjY2SR5s7d67MI2Sh8+fPMx0CTWjO9NGjR6J79UxNTd99990zZ86I9q5a\ntUpHR0f8eA8PD2tr69bWVvJpUVGRsrLyokWLyKdRUVEAkJGRITp+0aJFRkZGouPFkQenpqaKtkyb\nNu3Vg+vriQsXiMjIxwBxS5eW/fwzUV39/Fzxiuzq6jp79mzy8ciRIx0cHNrb28mnly9fBoDXFfeE\nhAQAaGpqEm2RfDpZ3MVZWVnduHGj07AeHh6BgYFdzshJbCtELLoVsrKyUrSIPknUiUnyCjM8WbmC\nPzcL05ypiYnJ+fPnc3NzT5w48euvv/73v//94Ycf1q5d+/HHH796cFNT09WrV1euXEk2hwEAc3Pz\nkSNHit/ho6Cg4OfnJ3oaGBi4c+fOwsLCQYMGvTqgQCCYPHmy6Om0adPS0tLIg1tbW7du3Zqamlpc\nXPzis8rmN9900dCYuGsXXL48RllZvb5+GLmMPgDY2NgUFxcDAEEQV65ciY6OVlB4ft3V09PTysrq\ndT+B0tJSTU1NITmK1Kenpqaam5sTBPH48ePNmzcHBgaeP39ePMcBAwY8fPjwdZOKpKTAgwfdHkUT\na2uYP7+X57KtEFFV3Nvb22vFVusg26BQZO/evWVlZRI6rVhbW8+fPz8lJcXa2trf3x8AHjx4kJKS\nIroLIiYmZv78+eQNW6dOnXrw4MH8F68w+ctGPsYR2DmCTLi6urq6ugJARUVFUFDQZ599Nn/+/P6v\nrJpfXV3d0dHR6f5FIyOj27dvi55qa2uLSj8AkIM8fvy4y+Kuo6Mjqqrw4luO5MErV65MTk5et26d\nl5eXlpZWRUXFiBEjCKJ+9GgYPRqePj15//4BgeDzpCRoaQFtbairs21qKgWAysrK5ubmgQMHik/U\n6am41tZW8RUNpTz9jTfeEH2gGhQUNHDgwC+++OKHH34QHaCsrCzN59K9Lqb0CwoKsrS0fF2p6fL1\nZRJFfxGQf8e9bpYuL8sMHjy40x9x5GWZhoYGyXMtW7ZMFiGzneiqLucxnin5yeSlS5eIVy7LNDY2\nKigoxMTEiB/v5+c3ZMgQ8jF5taS+vl609z//+Q8A5OXlvTpRVFSUQCAQvx5CfnRJHjxgwIDo6GjR\nLrKVzY8//ig619DQULS3oYEYNSre1DQ5OppYv75DRcVr7dp14nM5ODi87rLMJ598oqCgILoI09HR\nIRQK16177enkZZk7d+6IH2Bra+vm5ia+ZeTIkSNGjOhyRk5iWyGi6m4ZR0fHC2KkPEX87Q9I3YmJ\nJytXiO4a5jyaM311EUqyuyn59lwoFDY1NYl2qaqqvvnmmwcPHmx70duwuLj4/Pnzo0aNEh+BLOik\nffv2GRsbk805X0UQxMGDB8VPJA8mCKKhoUH8T17RXy1dUlMDQ8ObJia7v/wSZs8WWFmNT0kxjouD\nAwegogIKCwvv3bv3unOdnZ07Ojry8/PJpwKBwMPD4+TJk6IDJJ8OAE+fPi0uLu60bvvdu3cZXyaI\nTmwrRFRdltHS0vLx8enRKb3uxMSTi9GrVq1iOgSa0Jzp6NGjbW1tx40bZ2VlVVtbe/LkyX379pFX\n8wDA0dGxubl58+bNXl5eqqqqLi4un3/+eVBQUGBgYHh4eH19/Zo1azQ0NFauXCkaUENDY/Xq1X//\n/beDg8OhQ4d+/vnnXbt2iV+oEaehoREbG1tZWWlvb3/48OFDhw6JDg4ICPjmm29CQkLMzc0PHDiw\nZ88eKTMyNoadO739/PyUlR9ZWy/dtKlpz56zioora2u7Xp3R19dXIBBcuXJF1Os5Li7Oz88vISEh\nPDy8vLx87ty5ZOt2cefOnbt//z5BECUlJTt27GhpaRH/bS0sLHzy5In4Zw+cx7pCROefCR0dHQcP\nHjx48OB7770HADt27Dh48ODFixfJvS0tLc7OzgMHDty9e/eBAwdcXFz09fVLSkq6HZZXt1shmTtw\n4MD06dOtra1VVVXV1NScnZ2/+OIL0T1abW1t5MV3gUAgulX3xIkTZK3X0tIKDg6+ffu2aDTyakl2\ndvabb74pFApNTU0TExNfN7Xkg8vKyqZOnaqrq6ulpTV27NiLFy/C6y/LEAQxffp0Dw8P8bzs7OxU\nVFRsbGx27tz51lvjPDxWffEFsWoVkZZGVFe/FElQUNDEiRM7/VjET/fz83vd3TIGBgb+/v6nTp0S\nP33jxo0DBgwQv+LEeWwrRLQW9y7XOxa/DlhWVhYWFqarq6uurj5mzBjx3xkJ2PYzRXz2as1loVu3\niMREYvVqIjGRIK+cZ2RkqKiolJWVyWoKFxeXjz/+WFajyQW2FSIB8WJxH/k1cuTI8+fPMx0F5Vat\nWkXej8x5cp3p8uXLydu3mA5EKsXFkJ4Ojx+Dpib89NO/PTy0yJsd+uinn3764IMP7t+/r6Oj0/fR\n5AXbChGL7nPvNU9PT6ZDoMNHH33EdAg04U+mjDM3hwULAACamsDAYP2pU39/9hmMGQPDh/dpjWJL\nS8vTp0/zqrID+woRF965x8XFxcXFMR0FQlzQ1ASZmfDbbyAQyKDK8wrbChEX3rkjhGRFVRUmTIAJ\nE6C5GU6ehE8/BUVFCAjAKi9/uNCs49X7lDkpIyOD6RBowpNMWZ6mUAgTJkB8PERHQ1kZfPoprF0L\nEm92fy2WZyorbCtEXHjn3kA2tuG6Z8+eMR0CTXiSqbykqa4OU6bAlCnPr9js2wfa2hAWBtK3kJKX\nTPuIbYWI1nfuZ8+enTt3rq2trbq6uo2NzeLFi8vLy8UP6F0nJp58C27WrFlMh0ATnmQqd2mSV2zi\n4iA0FA4dguho2LMHpClocpdp77CtENH6zn3NmjU1NTVz5swxNzf/888/t23blp6enpubq6WlBdiJ\nCSE5YWwM5HdRb9+GzZuhqgrGjAE/P7wozy60Fvfk5GQ7OzvRU1dX15kzZx48eHDevHnwohPTmTNn\n3nrrLQDw9va2sbHZsGFDYmIinUEihKTk6AiOjtDUBD//DLGxYGgI06eDxPW5EX1ovSwjXtkBgFxr\n6fHjx+TTn3/+2cTEhKzsAGBqaurn5/fTTz91O+yxY8dkHCgrLSBvSOYBnmTKmTRVVWHaNFi3DkJD\nYf9+iI6GTl/l4UymkrGtEDF5t8ylS5cAwNnZmXx6+/ZtR0dH8QOcnJwePHggviZfl4KDgymKkFWS\nk5OZDoEmPMmUe2kaGkJkJKxfDwoKEBsLGzdCRQUAFzPtEtsKEWN3y1RWVq5YsWLo0KETJkwQbeld\nJyaEEKv4+ICPD5SUwDffwLNnMGsWvPybjehA1Tv39vb2ajGd9jY2Nk6aNKm+vj4tLa1T1/le2Lt3\n78KFC2NiYmJiYmbMmBEUFBTzgoODQ0xMTEpKCgCkpKSQjYAB4MGDBzExMaIRYmJiHrzo9HXq1Cny\neNK0adNEj3EEHAFHkH6EgQOhujrmgw8K8vIgJgY++ujO9u3fyV0W4iOkpKR0WWFI169fB1ahaEEy\nCZ2YmpqaAgMDdXR0fv/9d/Htve7ExLam4xRJTk5mOgSa8CRTnqRJvMj0wgVi5UoiMZF48oTpgKjB\ntkJE1WUZshPTq9tbWlqmTJly6dKlkydPDh06tNMpZCMxESk7MXXq/8JVDg4OTIdAE55kypM04UWm\n5LWasjL45htobYUFC7h2Xw3rChGd/5K0trZOnDhRTU3t3Llzr+79v//7PwAQ7Xr48KGKikpkZGS3\nw7JtGWWEkGS1tcSOHcTKlURXnWXlFdsKEa0fqC5cuPDIkSPz589/+vQp2QgYAAYNGkR+jjpz5syk\npKSwsLD4+HgNDY2EhAQdHZ3ly5fTGSFCiAaamrBoEdTXww8/wHffwbx58KLBH5IdOv8l6XSnI2nx\n4sWiA3rXiYltTccpUlhYyHQINOFJpjxJk+gu0+ZmYvduIjaWuHuXtogowbZCROt97rdu3Xo1gm3b\ntokOMDQ0TE1Nraqqqq+vP3HixJAhQ6QZlm1Nxymyd+9epkOgCU8y5Uma0F2mKiowdy6sXg1Xr0Js\nLNy9S1tcMsa2QoTNOhBCbNHUBHv2QHk5zJoFlpZMR9NDbCtEXFjyFyHEDaqqMH8+tLTAd99BbS2E\nh4O6OtMxyS0s7gghdlFRgUWLoKoKtmwBc3MIDcX1JnuDC52Yzpw5w3QIdFi1ahXTIdCEJ5nyJE3o\nbaZ6ehATAw4OEBkJv/0m86Bkj22FSJFVF4l6586dOwEBAUxHQTlXV1d1fvyNypNMeZIm9C1TY2MI\nDIRz52DvXhg6lNVXadhWiGh9537p0qXg4GBTU1NVVVVjY+OQkJBOX0ntXScmnvyGDBgwgOkQaMKT\nTHmSJvQ5U4EAZs2C2FjYvh22b4f2dlnFJWNsK0S0XnMvLCxUU1OLiIgwMDAoKytLSUnx8fHJzs4m\n1yHATkwIodfR1YXVq+Gvv2DVKnj7bfDyYjog9qP9zvp/FBYWAsBHH31EPv3+++8B4MyZM+RTcvmB\nqKiobseZOXMmhVGyRnp6OtMh0IQnmfIkTYKCTI8dI1atYt0CZGwrREx+oGpkZKSkpCRa8rfXnZjY\n1nScIjxpIQ+8yZQnaQIFmY4fD1FRsGkTvFijlxXYVogYKO6NjY21tbV379794IMP1NXV33//fXJ7\nrzsxsa3pOEV40kIeeJMpT9IEajLV04N166C+HuLioKVF5sP3BtsKEQPFPSAgQFtb297ePjMz88SJ\nE/b29uT2yspKPT098SNFnZjoDxIhxH5vvw1z50JUFBQUMB0K+zDQiWnnzp1ZWVk//vijpaXluHHj\nOt0w0wvYiQlHwBF4O4KFBSQmwrJl19auzaE6BuzERBASOzGJNDQ0mJqa+vv7k0973YnJ3d1dJjGz\n3Pz585kOgSY8yZQnaRJ0ZXrkCLF6NdHSQsNUXWNbIaK7E5M4NTW1IUOG3H2xClyvOzGxrek4RXjS\nQh54kylP0gS6Mn3nHXBzg8hIiIpiZtExthUiqi7LaGlp+YghN7a//PWDJ0+eXLt2bdCgQeTTkJCQ\nR48eZWVlkU8fPXp0+vTpt99+m6IIEUIcY2kJiYnw44+Qns50KCxA65eYxo4da25u7uLioqOjU1BQ\nsHv37rq6uk8//ZTci52YEEJ9JBTCp5/CkSOwejV88gkoKzMdEIPovAa0Y8eO4cOH9+/fXygU2tjY\nzJw58+bNm+IH9K4TE9uajlOEbCHPBzzJlCdpEgxleu8esWQJ8egRfTOyrRDR+s590aJFixYtknAA\n2Ympp8Oyruk4NcgW8nzAk0x5kiYwlKmtLaxbB6tWQUQEWFnRMSPbChEXlvw1NzdnOgQ6jBgxgukQ\naMKTTHmSJjCXqYYGbNwI27dDYSEd07GtEHGhuCOEUJcUFWHdOvj6aygtZToU2nGhuNfU1DAdAh2K\nioqYDoEmPMmUJ2kC05kqK8O6dbB2LVRWUjsR2woRF4o725qOU0RyC3ku4UmmPEkTWJCpmhokJMBn\nn0FtLYWzsK0QCQiCYDqGvmJb03GEEAtVVEBcHHz1FXT3tcheYlshYuyd++TJkwUCwXvvvSe+sXed\nmBBCqFv9+8Onn0JMDDQ3Mx0KLZgp7j///PO5c+dUVFTEN5KdmE6fPp2YmLh79+7S0tJRo0Y9efKE\nkQgRQtxjYADLl8PHH0NbG9OhUI+B4l5XVxceHr5+/Xrll789tm/fvtzc3NTU1Hnz5k2bNu348ePV\n1dUbNmzodkC2NR2nSO9ayMsjnmTKkzSBZZmamcGiRfDJJyDzC9JsK0QMFPdPPvnEzMxM1KNDpNed\nmDw9PWUfJft89NFHTIdAE55kypM0gX2Z2trCzJmwZo2Mh2VbIaK7uF+7dm3Xrl07d+4UCASddvW6\nExPbmo5TpI8t5OUITzLlSZrAykydnWHsWEhMlOWYbCtEtBb39vb2+fPnf/jhh132o8JOTAgh2nh4\nwBtvwNatTMdBGVo7MW3atKm8vHyNrP8cSklJ4UMnpoyMDMZjoGeE77//nvEYaBghIyOD8RjoGYH8\nX5eFWezaNc3SEnbvlnYEyZ2YyDRZhKIFyV7txFRSUqKurv7tt99WvaChoREaGlpVVdXa2kr0oRPT\nxIkTKcqCVX788UemQ6AJTzLlSZoE6zPdupW4fl0G47CtEFH1Jaba2trc3FzRUx8fn+zsbC8vry4P\nTk9PDwoKmjRp0tWrVx8+fCjaPm7cuHv37t2/f1/yXGz77gBCSI50dMDSpbB1K7zyOWDPsK0QUbXk\nL9mJSXzLkCFDzp49K75l7Nixvr6+MTEx5CX4kJCQI0eOZGVl+fr6wotOTOHh4RRFiBBCAKCgAJMn\nw5EjMGkS06HIFH3ruWtra48aNUp8i6KiopGRkWgjdmJCCDHirbdg6VIYPx6EQqZDkR0WLRymrKyc\nmZk5atSoyMjIuXPnGhkZnTt3ztjYuNsTjx07RkN4jFuwYAHTIdCEJ5nyJE2Qk0w//BC+/bZPI7Ct\nEOHCYQghBAAQGwvLl0O/fr08nW2FiEXv3BFCiEHLlsG2bUwHITtY3BFCCADAwADU1KC7u/PkBheK\n+/Xr15kOgQ7iX77gNp5kypM0Qa4yDQ+H5ORensu2QsSF4s62puMUYaSFPCN4kilP0gS5ylRNDVxc\n4NKl3pzLtkLEheLOtqbjFGGqhTz9eJIpT9IEect05kzYv783CwKzrRDRWtxPnToleFmn5eKwExNC\niFkKCjB1Khw6xHQcfUbfl5hEkpKSzMzMyMdCse8MkJ2YysvLExMTNTU1ExISRo0adePGDUNDQ8kD\nsq3pOEWKioosLCyYjoIOPMmUJ2mCHGbq6wvLlkFISM++08S2QsTAZZmAgIApL0yYMEG0vdedmNjW\ndJwijLeQpw1PMuVJmiCfmS5aBD39GJhthYiZa+7kQo+dNva6E5N8XdHrNVb1KqMUTzLlSZogn5na\n2cGTJ1BR0YNT2FaIGCjuPj4+GhoampqakyZNys/PF23vdScmhBCSuYgI+W7lQWtx19bWDg8PT0lJ\nOXbs2MqVK0+fPu3t7V1aWkruxU5MCCH20NcHbW3Iy2M6jl6jaJ34tra2KjFdHpOVlQUA0dHR5FN9\nff3p06eLH7B27VoAKCkpkTyXnp7eggULoqOjo6Ojp0+fHhgYGP2Cvb19dHR0cnIyQRDJycmZmZnk\nKfn5+aJ5CYKIjo7Oz88nH2dmZpLHk6ZOnSp6zOwIsbGxjMdAzwgffvgh4zHQMEJsbCzjMdAzAvm/\nrjxm0dhIREb+M0JycnKXFYY0aNAggk3o68TUJXNz89GjR5OPe92JacWKFX0PmP2ePn3KdAg04Umm\nPEmTkPNMU1OJCxekOpJthYiqWyEdHR0vXLjQ7WFtbW2CF+1PHB0dr169Kr731q1b1tbWampqkgdh\nW9NxirCwhTxFeJIpT9IEOc80NBSWLIHhw7vv08S2QkTVNXeyE5MIubGtrU38mOPHj5eUlHh6epJP\nQ0JCHj16RF6rgRedmN5++22KIkQIoW4JBDBtGqSlMR1Hz9H6gWpwcPC8efM2b968e/fuxYsXT5o0\nyczMLCIigtw7c+ZMZ2fnsLCw//u//0tLSxs/fryUnZi6bbLKDazrrU4ZnmTKkzRB/jMdORIuX4aW\nlm4OY1shovUbqgEBAfv37z9y5EhdXZ2xsfF77723Zs0a0Wo7ZCemdxP4wQAAIABJREFUyMjIyMjI\nlpYWHx+f/fv3S9OJqaGhgeLAWeHZs2dMh0ATnmTKkzSBE5muWtX9ZRm2FSLsxIQQQjLAtkLEhVUh\nEUIIdcKF4s62NfIpIkcdD/qIJ5nyJE3gTaZsK0RY3OUGT35DgDeZ8iRN4E2mbCtEXCjugwcPZjoE\nOgQHBzMdAk14kilP0gTeZMq2QsSF4o4QQqgTBor7L7/8MnLkSE1NTR0dHS8vL9G3lgA7MSGEkIzQ\n3YkpOTl54cKFAQEB8fHx6urqN27cKCsrI3f1uhOTaF1JbmPbFT3q8CRTnqQJvMmUbYWI1uJeWFi4\nbNmyiIiIr7/++tW9ZCemM2fOkP06vL29bWxsNmzYkJiYKHlYti3pQBG29VanDk8y5UmawJtM2VaI\naL0ss3v37o6ODvI+/46Ojk57e92JSUdHR9aRshHbeqtThyeZ8iRN4E2mbCtEtBb3ixcvuri4pKam\nmpmZKSoqWlpaJiUlib4ii52YEEJIVmgt7iUlJXfv3o2Li/v0009PnDgxevToqKioL7/8ktzb605M\nzc3NVEXMJmzrrU4dnmTKkzSBN5myrRBRdc29vb29trZW9FRXVxcAOjo6amtr9+zZ88477wDAmDFj\nCgsLv/rqq5UrVyoqKvZ6rps3bw4dOlRVVRUAampqmpqaRJ/B5uXl2dra6ujouLm55eTk6OrqWlpa\nAkB1dXVubq6vry95WFZWlqurKxlkYWFhdXW1m5sbuevo0aOiZYeZHSE9PV0oFMp7FtKMUF5eLhQK\n5T2LbkdIT0+/c+eOvGchzQjnzp0TCoXynoWurm5OTk5xcfGrFYZ8XFRUBGxC1cJh2dnZXl5eoqfk\nLF5eXtnZ2bW1tZqamuT2devWxcbG5ufnW1tb29nZWVlZia8OunLlysTExPr6+m77dSCEEBJHaycm\nR0fH7Oxs8X9OyMcKCgrQh05MCCGEOqG1E9PEiRMBID09XXTYL7/8YmBgQH6Yjp2YEEJIVmhdz50g\nCD8/v99//3316tUWFhYHDhxIS0vbuXPnwoULAaC1tdXd3b2ioiI+Pl5DQyMhIaG0tDQ3N1eafh0I\nIYTE0d2s4++//46NjT106FBVVdXgwYNXrFgxZ84c0d4nT55ERkb+8ssvZCemTZs2DRkyhM7wEEKI\nG7jQiQkhhFAnuCokQghxEBZ3hBDiICzuCCHEQVjcEUKIg7C4I4QQB2FxRwghDsLijhBCHITFHSGE\nOAiLO0IIcRAWd4QQ4iAs7gghxEFY3BFCiIOwuCOEEAdhcUcIIQ7C4o4QQhyExR0hhDgIiztCCHEQ\nFneEEOIgLO4IIcRBWNwRQoiDsLgjhBAHYXFHCCEOwuKOEEIchMUdIYQ4CIs7QghxEBZ3hBDiICzu\nCCHEQVjcEUKIg7C4I4QQB7GruJeXl8+ePbtfv36amppBQUF37txhOiKEEJJLAoIgmI7hudbW1mHD\nhpWXl8fHx2tqaiYkJJSVld24ccPQ0JDp0BBCSM4oMR3AP/bt25ebm3vmzJm33noLALy9vW1sbDZs\n2JCYmMh0aAghJGdY9M598uTJV65cefTokWjLuHHj7t27d//+fQajQgghecSia+63b992dHQU3+Lk\n5PTgwYOmpiamQkIIITnFouJeWVmpp6cnvkVPT48giKqqKqZCQgghOcWia+69pq29WFd3oLZ2sZra\ng/r6x01NTaLPYPPy8mxtbXV0dNzc3HJycnR1dS0tLQGguro6NzfX19eXPCwrK8vV1VVXVxcACgsL\nq6ur3dzcyF1Hjx59++23ycedRjh58uS0adP6MkLvYqioqPDz85NVFtKPYGFhQT6V+U9S8ggAQA4i\n85+k5BEKCwvd3NyofjVfHSEnJ8fNzY3O/6PIEXJyciwtLen8P4ocIScnBwDo/D9K9L9xUVFRj0bI\nyckpLi5+tcKQj3V0dDIyMoA9CNYYPHhwYGCg+JYVK1YIBIKGhgbJJ/r6+jY3E7duET/8QKxbR6xe\nTaxeTWzeTGRmEmVlFAa8evVqCkfHeXFenFeu5mUqkddh0Tt3R0fHq1evim+5deuWtbW1mpqa5BML\nCgpUVMDREcSv2JeUwO3bsH8/NDQAQYBAAJaWMGQIODiAUCibgM+cORMXFyebsXBehJBMsai4h4SE\nHDlyJCsri/xr6NGjR6dPnw4PD+/2RFNT01c3DhwIAwdCQMDzpwQBhYVw+zacPg1NTSAQgIIC2NiA\nkxPY2oJSr34Mnp6evTmtz/g27/Xr13FenJcz89KGRcV95syZSUlJYWFh8fHxGhoaCQkJOjo6y5cv\n7/ZEZWXlbo8RCMDKCqysIDj4+Zb2dsjPh1u34Oefob0dCAKEQhg8GJydwcpKqoDV1dWlOk7W+Dav\nvr4+zovzcmZe2rCouCsrK2dmZkZGRkZGRra0tPj4+Ozfv9/Y2Jii6RQVYfBgGDz4ny0tLXD3Lvz6\nK+zfD+Td//r64OICTk6gqUlRFKh75ubmOC/Oy5l5acOi4g4AhoaGqampPT2rsrJSJrOrqICzMzg7\n/7Olthbu3YPDh6G0FACgpQUsLMDREZycQCgEpr5dxbd5EUK9wK7i3jutra0UjaylBe7u4O7+z5aS\nErh+HbKyoLUVcnICN2wAe3sYNgyMjCgKoQsNDQ30TcaCeWtqanBenJcz89KGC8WdzpXFyM9pSY2N\n+RERkJcHJ0/CgwcAAIqKL721p4iLiwtVQ7Ny3hs3buC8OC9n5qUNF4o7gzrdgtnWBvfuwY0bcOIE\ndHQAABgYgKsrODsDQx9GcsGIESNwXpyXM/PSBou7LCkpwZAhMGTIP1vIq/aHDj2/at/cDJaW4O4O\nDg6gwKKlHxBCXMOF4l5UVMTIvFlZWd0e0+mqfVMT3L4Nly/DkSMAAAoKYG0N7u4waBAIBLKclwpM\nzWttbd2X07dt27ZkyRLysaam5qBBgxYsWPDBBx8oKioCwPLly/fu3VtWVibzeXtk2bJld+/eTU9P\n73Jef39/VVXVY8eOURqDDPNdv359WlratWvXBFL8b03nz5kN89KGC8X93XffZWTes2fP9vQUVdWX\naj1BwP37cO0a7N8P7e0gEICtLbzxBtjZSXpf34t5ZYKpeefMmdP3QXbu3GlqalpTU7N///5FixYV\nFhZ++eWXNMwrjby8vB07dly6dInmeTuR4bzh4eGJiYl79+6dPXs2nfP2CFPz0oYLxV1+kdX8xbpD\nAC/uxjl8GGprobUVzM2f/2PQ3RIMqBujRo2yt7cHgNDQUDc3t+3btyckJJBv3hmXlJTk4uIybNgw\nmudtbm4WUvO5v4aGxqxZszZs2CBNcUcUweu+7DJwIEyYAKtWwZdfwldfgZ8f5OdDXBxERUFMDOzb\nB3l5wJr2KnJJQUHB09Ozrq6uoqJCtPHmzZu+vr7q6uqDBg3asmWLaPutW7dCQ0MtLCxUVVVtbGyW\nLFkifv9cUVHRjBkzjIyMhEKhiYnJO++8U1tbS+66ceNGSEiIrq6umpra8OHDL1y48Lp4GhsbU1NT\nw8LCxDcePHjQwcFBVVV1yJAhhw4d6nSK5MHT0tLIc52cnI4cOeLv7x/84mvZy5cvNzIyOn36tIeH\nh5qaWlRUlDQDStgr4ScQGhp68+bN7Ozs1yWOqMaFd+5MrRGRkpIyf/586sZXVAQnJ3By+mfLgwdw\n8SJEROS4uLgBwJAh4O4OQ4b04Hp9X1CdL20KCgqUlJS0tbXJp/X19ZMnT16wYMGKFSv++9//RkRE\n2Nrajh07FgCKioqsrKymTp3av3//goKCdevW/fHHHxcvXiRPnDJlSnNz8/bt242NjUtLS0+cONHS\n0gIAubm5w4cPd3R0TElJ0dLSSklJ8ff3//XXX93FvzHxwq+//lpbWyt+58bZs2enT58+YcKETZs2\nPX36NDIysq2t7Y033iD3Sh787NmzM2bMmDx58ubNm589e7ZixYqGhgbRuQBQXV29ePFi8m+F5ubm\nbgeUvPd1PwEAcHd3V1dXz8jIYGpJIsSiJX97be7cuYzMe/78eQbnra0lzp8nNm4kIiOJyEgiPp7I\nzCT+/pvyeeXO1q1bAeD69eu1tbWPHz9ev349ALzzzjvkXvLd6/Hjx8mnHR0dNjY2s2fP7nKoP/74\nAwBu3LhBEERLS4tAIPjuu+9ePWzMmDEWFhZ1dXXk0/b2dhcXF9GMnSQkJABAU1OTaMvIkSMdHBza\n29vJp5cvXwaA8ePHSzP4iBEj3NzcREPl5uaKn0sme/r0aemjlbBXwk+A5OHh0WkRb27DJX9lj6k1\nIpi9P1dTE0aMAFEIFRVw5Qps2gS1taCoCEOGgKfnSyvnyGpeOSV61ywQCKZPn75t2zbRLqFQGBQU\nJNrr7OxcXFxMPm1tbd26dWtqampxcbHogsPdu3ednZ2VlZVdXV0///zzurq60aNHO734C6ulpeXs\n2bNLlizR0NAgtygoKAQHB6ekpHQZWGlpqaampujaN0EQV65ciY6OVnjxkbqnp6fVi6XsJA9OEMRv\nv/22atUq0eAuLi624h/pACgpKY0aNUr0VPKAkve+7icgMmDAgIcPH3aZtbiUlOffAWQDa2vgxF+n\nANy4LIMAoH9/GDcOxo17/pT8YDYtDerqnt+i4+UFAwYwGiKjUlNTzc3NtbS0rKysRBdkSLq6ugpi\nNycJhUJR296VK1cmJyevW7fOy8tLS0uroqJixIgRor3Hjh2Li4tbu3ZtRESEqanpRx99FBkZWVVV\n1draumXLlu3bt4vGbG9vb29v7zKw1tZW8WVNKysrm5ubB4q+Bg0AAKKnkgcnzzUwMBA/t9P3t/v3\n7y+erOQBu82ly5+A6EhlZWXRVRoJOFNM2YYLxZ2pNSKKioosLCzYOS+5TMKECQAAdXVw9Srs3g2N\njaCgALa24OMDXa2BL4N5WeuNN94g75bpkb179y5dujQiIoJ8eu3aNfG9JiYm33zzDQDcunVr9+7d\nUVFRZmZmEyZMUFRUXLRo0YcffijNFPr6+jU1NR0dHWTN7devn1Ao7NQ3uLKykuwSp6OjI2FwPT09\noVBYXl4uvvHJkyc6Ojqvm13ygJL3wmt+AlOnThWFzfllddmMC3fLMLVGxN69e+ViXk1NeOstWLkS\nVq+GTz8FX1+4fBnWroW4ONiwAS5eBCneXfVmXnlHEERDQwNZVUlpaWldHunk5LRx40ahUHjr1i1V\nVdVRo0adO3fOysrK/mVdnuvs7NzR0ZGfn08+FQgEHh4eJ0+eFB1QWFh479498rHkwRUUFN58883D\nhw+Lzr1582ZeXp6EHCUPKH0u4j8B0ca7d+8ytR4RAprfuZ86dSpA1BsJAAD69+//7Nkz0dPy8vKo\nqKjjx4+T67lv2rTJwcGh22GZuhYsfnFTjuY1NoYXb62grg6ys2HzZqivB4EA3ngDRowAsWomy3nl\njkAgCAgI+Oabb0JCQszNzQ8cOLBnzx7R3qKiorCwsNDQ0MGDBysoKKSlpbW2tvr7+wPAxo0bfXx8\nfHx8Fi9ebGZmVlFRQb7l/+qrr16dxdfXVyAQXLny/+2daVgT1/rA3wiEEIJsFQoIUqAqgoDiUhBZ\nZFUQFyr6gN5WbblaqD4gYKq1gMotKoVaWxTqQlVUSm1FqWjZi0u9agUEcWVRLkj8yyLIHub/YTSN\nqCGE7Ly/T3PmzJzfmRhfJmfOnPcKZ3A8Ojra1dU1NjY2JCSExWKtXLmSRqNxjufdeExMjKurq7+/\n/yeffPL06dMtW7a8++67o3iudMG7QR61PD4BAKipqWlsbCQzuSOSQZxPb3NycgAgISEh4yWnT5/m\n1Pb09FhbW+vp6R04cCA9Pd3KykpHR+cxHymupe0htYzS3k7k5RFxcURMDBEbS+TkEINlJpcNyNky\nlZWVb6zdsGGDrq4u956lS5fOnDmT3H78+PGSJUs0NDTU1NTmzp1LToI8cuQIQRAtLS2rVq2aMGEC\nnU5XV1e3t7fPzMzkNFJZWbl06dIxY8ZQqVQDA4MFCxacP3/+bT308vJatGgR95709PQJEyZQqVRT\nU9O9e/e6urpyZrwM2viJEyfIc83NzTMyMqZNm7Z8+fK3XSw/Db6tlvcn8M0337zzzjvcs4DkHmkL\nRBII7jdv3nxjbWpqKgDk5+eTxUePHlGp1A0bNgzarLR9pnIAm02UlxP79xNxccRXXxE//0y0tEi6\nT/LLuXPnqFQqP/cxQ6W+vp5OpyckJAi95UGxsrL64osvxO+VINIWiCQz5t7R0UG89p7l6dOnDQwM\nXFxcyOLYsWNdXV1PnTo1aGv5+fnC7yIfyOiwDD+MGgUWFrB6NWzcCF99BSYmsH8/ODrm/+c/kJsL\nL2eLIMLB09PT0dFx0LVu+KG9vf3zzz/PzMy8ePHi0aNHPTw8GAyG+BdROXXqVH19/caNG8XsRbiR\nwGwZBweH1tZWOp3u6em5a9cuU1NTcn9FRYUFZ2V0AACwtLQ8d+5cV1cX95jj60jqFbjQ0NCR4FVQ\neLG+zUcfWdFocOECxMcDmw0aGuDiApMni+n9WPkmNTX19u3bw29HUVHx0aNHa9asefr0KYPBcHZ2\n/uWXX7S1tYff8pAwNjbOy8vjMUsHEQNiDe6jR48OCQmZPXu2qqrqtWvXEhIS7O3tS0pKyCzYTU1N\nNjY23MdramoSBNHc3Mw7TTZdQokw3pHQvHHJer28gHzjp6UF8vKAnJphZgZubmLNNShnGBgYGBgY\nDL8dGo3Gz49dUTPgPzIiEUQ1LMNms1u4IHfOmDFjz549/v7+3t7eUVFRZ86cYbFYu3fvHqbr6NGj\na9asYTKZTCZz2bJlXl5ezJeYm5szmUzyhbqUlJTc3FzylKqqKiaTyWmByWRWvXxJLjc3l/tlQn9/\nf842tsDdgoYG+PnBv/5V1dXFdHeH4mLYsQNmz875/vtG8h9cJq4CW8AW+G8hJSXljRGGRFKLXL0V\nEY3lkwtiDGoxMjKaM2cOuT1+/PgBK1FERERQKJSOwSZtBAYGDr/DApCdnY3eAfT2EhcvEnFxRFQU\nkZBA3LhB9PeLwysK0IveISFtD1RFNSxjYWHBY5lTDn19fZxcLRYWFlevXuWuLS8vNzExURlsLfOO\njg6B+zkcuGfoo5dEURHs7cHeHgCgtRXy81/knLK0BHf3t86gH75XFKAXvbKNOP+S9Pb2chfJtGGb\nN28mi4cOHQKAwsJCskhOhQwLCxu0WWn7g4m8zoMHRHIyERVFbNtG5OQQr34REEQekLZAJNYHqj4+\nPvr6+tbW1mpqatevX9+/f7+hoSFn4Y7AwMCEhISAgIDt27erqqrGxsaqq6uHh4eLs4eIiOAsttfZ\nCRcvQmIitLeDgQH4+uJjWAQRCWIN7u7u7sePH//tt9/a29v19PQ+/vjjmJgYztJCSkpKOTk5YWFh\nYWFh5PIDx48f5z1PBpE5VFTAzQ3c3IAgoKQEjh6FtjbQ1ARvb3h1bVoEQYaHpH86CAFbW1uJeIOC\ngtArFJ4+JQ4fJrZsIbZvJ/76i3iZpkLkXt6gF71DQtqGZSiE7GfkjI6Ojo6OlnQvECHAZsPly3Dp\nEjx7BuPHw8KF8OrS6wgivUhbIJKH9dwRuUFBARwcwMEBAKCiAg4dguZm0NYGPz94NX0FgiCDgMEd\nkVIsLIBcjeLuXThxAlpaQEcHFiwAQ0NJ9wxBZAF5SNYhqRfD3pYVE73CpbAwJSwMtm6FwEAoKAAm\nE6Ki4MIFEPWA4kj7nNErZ8jDnbukUnnxk0gEvUL0amoCub5hRwfk5UFUFPT3g5cX2NsDz3QUw/WK\nGfTKt1ds4ANVRIbp7ITcXCgshJ4e8PAAT0+gUiXdJ2SkIm2BSB7u3JERi4oKzJ8P8+dDezv8/juE\nh4OyMsybB46OoKAg6c4hiESRhzH31tZWiXhra2vRKyVeBgOWLoXvvoO4OFBSgk2bYN06OHOG39zf\nAntFAXrl2ys25CG4l5WVScR79OhR9Eqbl5xMuWMH7NoFABARAZ9/DmfOQG+vaL1CBL3y7RUbOOaO\nyDnd3fDHH5CXB3194OkJXl6gpCTpPiHyiLQFIhxzR+QcZeUX4/JtbXDmDISGgpoa+PrCBx9ggkBE\nnsHgjowU1NQgIAACAqCtDQoL4csvgU4HX1+YPFnSPUMQESAPY+75+fkS8W7evBm9suhVU4P58yE2\nFsLDoaYGtmyBzZvh779F7uUT9Mq3V2zIw5h7ZGTkzp07xe/9v//7P4nkqkav0CHny1+/DlQq+PuD\nmZmYvG8EvTLqlbYxdyHfudfX169bt87Ozk5FRYVCodTU1Aw4gMVirVixQktLi8FgeHl5VVZW8l/7\nNuh0urD6PyQk8o1Erygg58tHR8PKlZCdDZs2wYEDoKAgt9eLXgl6xYaQx9yrqqrS09OnT59uZ2dX\nUFAwoLa3t9fDw4PFYsXHxzMYjNjYWGdn57KyMl1d3UFrEUQM6OnB558DAFRVwYED0NwM5ubg64sr\nDyMyiHCXh2e/zLOQmJgIANXV1dy1qampAJCfn08WySypGzZs4KeWB4GBgcLq/5CQm6zt6OXhra0l\n9uwhNm4kkpOJlhbxecUPeoeJtCXrEPKwzCieCzidPn3awMDAxcWFLI4dO9bV1fXUqVP81PKgo6Nj\neL0WkJGWtX1keo2MICQE4uLAwwNOnIDoaDh8GNraRO4VP+iVM8Q6FbKiosKCXKL7JZaWlufOnevq\n6qLRaLxreTRrZWUlku4OxvLly9E7crzGxvDvfwMAVFRAUhI8eQJWVuDnB6qqovWKDfTKGWIN7k1N\nTTY2Ntx7NDU1CYJobm7W09PjXSvOfiIID8gsIgQBFy/Crl3Q3w+zZ4OLCyjiSyOINCH4sAybzW7h\nQoh9GipHjx5ds2YNk8lkMpnLli3z8vJivsTc3JzJZJKr8qekpOTm5pKnVFVVMZlMTgtMJrOqqorc\nzs3N5V7F39/fn7ONLWALnBYoFLh1K8XBIXfrVtDXhy1bmuzsCs6cge5uWboKbGFILaSkpLwxwpBI\nKmvQWxF4tP7y5cs82nnjA9Xx48d7enpy74mIiKBQKB0dHYPW8sDW1lbgqxgOcpO1Hb3C8paXE4mJ\nRHQ0cfo00d0tPq9QQO8wkbYHqoK/xNTW1lZaWsopOpBZjV/y7bffhoaGVldXGxsbc3YuXrz46tWr\njx494uyZN2/e3bt379+/P2gtD6Tt3QEEqaiAM2egtRXs7TGFyEhB2gKR4MOEampqAwL6oPj6+v72\n229FRUVOTk4AUFdXl5eXFxISwk8tgsgQ5Lh8Xx8UFMD27TBqFDg5YQoRRKwoCPdPDUEQJ0+evHXr\nVnFxcUlJyYQJE2pra5ubm42MjADAwsLi1KlTR48e1dLSunfv3po1a3p7e48cOaKmpjZoLQ8KCwud\nnZ2FeBUIIhRGjQJTU3BxAUdHaG6GY8fg5ElobAQTE1BWlnTnEGEjdYFIuKM8vW/KieDt7c054PHj\nxwEBARoaGnQ63cPDo6Kigvt03rVvw8fHR7hXwSfJycnoRe9QKS8n4uKI8HAiOZlobBSfd1DQO0yk\nbcxdyLO3FBUVCZ6D+Lq6umlpaYLVvo0xY8YM9RShMNKytqNXKJAjNgBQUQHJyVBXB5MmwZIloK8v\nWu+goFfOkIdVIaXtOQaCDIm//4bMTHj69MU6NoaGku4QIhDSFojwvQsEkTBTp8LUqQAAtbWQnQ0V\nFaCsDL6+YG8PPJfzQBBeyMN3p7W1VSLekZa1Hb2iZtw4CAqCsLDa6GhoboavvoKICOC8GCVqRs7n\nLFmv2JCH4F5WViYR70jL2o5esXnpdJg/H7Zvh7g40NSEHTsgMhJSUoDFEq1XhK2jV+zgmDuCyAAE\nATduwB9/QEcH6OvD3Lkwbpyk+4S8irQFIhxzRxAZgEL5Z2i+qQny8uD4cejshGnTwMMDZ80jbwCD\nO4LIGFpasGQJAACbDSUlsHs3NDWBvj4sXgxjx0q6c4jUIA9j7vn5+RLxjrSs7eiVNq+CAtjaQmQk\nxMWBlxf8+it89RXEx0NJiWi9wmWkecWGPIy5R0ZG7ty5U/xeucnajl558ra1QU4OkJMM3nsP3NzA\nwEAcXoGRGy+OuQsfOp0uEe9Iy9qOXpnwqqnB4sWweDEAAIsFRUVQUQHt7TB+PPj4/PMerNC9AjPS\nvGJDHoI7giBvREcHlix5MUBfVQVZWVBVBQQB06aBlxcMtiIfItvIw5j7oAu+i4hz586hF72y4jUx\ngaAgiIuDmBjQ0oLvvoOYGNi9G27cgP5+EXoHZaR5xYY83Ll3dHRIxDvSsrajVz68NBq4uoKrKwBA\nRwdcugTffAP9/XDz5hgGA2bOBCUlkfoHIq+fs8SRhweq0vYcA0FkkefP4fJl+OsvaG8HbW2YMwem\nTMHFbYaAtAUiIf/T1dfXr1u3zs7OTkVFhUKh1NTUcNfm5uZSXmXAMw0Wi7VixQotLS0Gg+Hl5VVZ\nWSnc7iEI8jZUVcHNDb78EuLiIDAQbt+GrVshJgYOHYI7dyTdOWToCHlYpqqqKj09ffr06XZ2dgUF\nBW88JiEhwfDlqqbKXK/W9fb2enh4sFis+Ph4BoMRGxvr7OxcVlamq6sr3E4iCMIbfX0IDHyx/ewZ\n/Pe/kJEBfX1ApcKMGTBrFqioSLR/CD8IN/cHm80mNxITEwGgurqauzYnJwcAbt68+cZzU1NTASA/\nP58sPnr0iEqlbtiwYVCpra3tsDotKHKTtR296OXT295O5OQQ27YRGzcSGzcSP/9MPHkiDq8oELpX\n2jIxiWrM/dtvvw0NDa2urjY2NubszM3NdXd3v3nzpomJCTluw32Kn5/flStX6urqOHvmzZt39+7d\nQSfDSNtQF4KMBNrb4dIluHwZWlpAWRlsbMDeHoyMJN0tySFtgUgCs2UcHBxaW1vpdLqnp+euXbtM\n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\n3r33339fXV3dxsampKREQ0PD2NgYAFpaWkpLS52cnMjDioqKrK2tyUuoqalpaWmxsbEhqzIzMxcs\nWEBuD2ghIyNDWVl5OC0I1oeKigrSK5Sr4L8FgiBIr9A/Sd4t1NTUkF6hf5K8WygsLFRWVhb1v+br\nLWRnZysrK4vzG0W2kJ2d3dnZKc5vFNlCdnZ2ZWWlOL9RZAvZ2dnnzp0bUgslJSUPHz58PcKQ25Ja\nmP6tEIJy+fLlt7XT1dXl6emprq7+999/c+8fP368p6cn956IiAgKhdLR0TFoLYIgCMI/gt+5W1hY\nFBcXv76/p6fnww8/vHjx4h9//DFlypQBp1y9epV7T3l5uYmJiYqKyqC1CIIgCP8IPuaupqbmwAW5\ns6+vb9myZXl5eVlZWXZ2dgNO8fX1raurKyoqIot1dXV5eXmcn0W8axEEQRD+EfJ67p988smBAweC\ngoLc3d05O83MzMhBrt7eXltb26dPn27fvl1VVTU2NrahoaG0tFRPT2/QWgRBEGQICHeUZ8BcRpLg\n4GDOAY8fPw4ICNDQ0KDT6R4eHhUVFdyn865FEARB+EQeMjEhCIIgA8BVIREEQeQQDO4IgiByCAZ3\nBEEQOQSDO4IgiByCwR1BEEQOweCOIAgih8hwcBdDTj7+FfX19evWrbOzs1NRUaFQKDU1NeLxDprX\nUETeixcv+vj4jB07lkaj6enp+fr6Dlg6QkRebvz8/CgUyscffywGb25uLuVVhrNK1FCv9+zZs46O\njgwGQ11d3c7OjvMWt+i8CxcupLzGjBkzRO0FgKKiIldX13feeWf06NHTp08/fvy4YNKheouLi52c\nnOh0uqam5rJlyzhZKGQYSU+0F5Cenh5ra2s9Pb0DBw6kp6dbWVnp6Og8fvxYUori4mIdHR1vb28y\n2Uh1dbV4vE5OTjY2Nlu3bk1NTY2MjKTT6e+9996zZ89E7T169OiHH364c+fO1NTUuLg4ExMTKpU6\nYJ04UXg5ZGZmamlpUanUjz76SADpUL05OTkAkJCQkPGS06dPi8FLEMS+ffsAwN3dPTExMTk5OTg4\n+MSJE6L2Xrp0KYOLuLg4AIiKihK19+rVq1Qqddq0aWlpaSdPniRXC09LSxO196+//lJSUpoxY8ax\nY8d+/PFHQ0NDMzOztrY2AbzSg6wG99TUVADIz88ni48ePaJSqRs2bJCUgs1mkxuJiYnDDO5D8t6+\n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\nY2RHRMr/A5YdmP24XbLsAAAAAElFTkSuQmCC\n"
1411 }
1411 }
1412 ],
1412 ],
1413 "prompt_number": 119
1413 "prompt_number": 119
1414 },
1414 },
1415 {
1415 {
1416 "cell_type": "code",
1416 "cell_type": "code",
1417 "collapsed": false,
1417 "collapsed": false,
1418 "input": [
1418 "input": [
1419 "%%octave -s 600,200 -f png\n",
1419 "%%octave -s 600,200 -f png\n",
1420 "\n",
1420 "\n",
1421 "subplot(121);\n",
1421 "subplot(121);\n",
1422 "[x, y] = meshgrid(0:0.1:3);\n",
1422 "[x, y] = meshgrid(0:0.1:3);\n",
1423 "r = sin(x - 0.5).^2 + cos(y - 0.5).^2;\n",
1423 "r = sin(x - 0.5).^2 + cos(y - 0.5).^2;\n",
1424 "surf(x, y, r);\n",
1424 "surf(x, y, r);\n",
1425 "\n",
1425 "\n",
1426 "subplot(122);\n",
1426 "subplot(122);\n",
1427 "sombrero()"
1427 "sombrero()"
1428 ],
1428 ],
1429 "language": "python",
1429 "language": "python",
1430 "metadata": {},
1430 "metadata": {},
1431 "outputs": [
1431 "outputs": [
1432 {
1432 {
1433 "output_type": "display_data",
1433 "output_type": "display_data",
1434 "png": "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\nFhMTs2bNmrCwsIiIiA0bzCthiQAAEHhJREFUNtTI10Z1R5jaCNLWKKjuP4gavvI3b94cNGhQYGDg\nj08zWz7+9ebNmwcOHPjBDajAkydPvLy8pk+fXkHmPjExcdu2bWFhYatWrQoPD9fguqIaWkK/Or8N\nYa1QxRBWoPIcQigUxsXFBQYGfnMULJVKk5KSJkyYoGKnlEql4eHh5etU2xBKJBI/P7/yM7DHjx+r\n7iauOm/evFmwYMGECRPkLrUBAQE+Pj7qrfBUprrMzLUUpFUjqO4/hXpBYzKZ7ObNm0FBQX/99ZcG\n1c6qJCIi4psi7IWFhT9mXbRKcnNzw8LCvL29g4OD58yZM2fOnGHDhml8MFol/4Vlj99eoz+a7t27\nm5mZ3bp1a9q0aUlJSampqQKB4N27d2vWrLl165ajo2PXrl0XLlxYPiHfhw8fVqxYUa9ePQqF0rZt\n29DQUCMjI1WuRaFQ/P395a9Jkrx7926NmvrmzZuTJ0/OmjULAJVK3bhxY/lPbWxsFOkeCwsL5Qsp\ntUEikcTHx9+6dSszM7O4uNjc3DwgIKCWdVbg9u3bAFq2bFnhuiNGjLhy5UpsbGznzp2/2Uga7f/f\nNefPn//06dP48eM1285/GXp6egUFBeWP5OfnEwShPLUnQRBdu3bt2rXrmzdvfHx86HR6eHi4np6e\nplq1dOnSOXPmMBgMANOmTftm+ZcvX757927YsGGaaoDq3L9/Pz4+vrCw8P3795aWljNmzPiR6R7l\nj6ykpKQfdsUfz78nMe8/wvr16/39/d+9e9ewYUPVzzIxMTEyMsrIyOjQoQOfz7927Vr5GlJTUw8d\nOsTj8QwNDbOzsyUSiaGhobGxceV4xBohlUqPHj368uVL5Yl579279/XrVzc3txpVvmrVqvj4+LCw\nsFatWtW0YRkZGbGxsRcuXDAxMRk4cKCFhcX69evLDxGU/LbynLHljxgYGFQX+FFdZmZvb+9du3b5\n+PiUr6pJkyatW7cGcOnSJRcXl/37948aNQpA3759jY2NbW1teTze/fv3d+7caWhoeP/+/RqFE/zX\nGDJkSFJSUkZGhuKIi4vLy5cvX79+rXolmZmZe/fuLS0t9fPzMzY2VqMZBQUFt2/fdnV1lb/Ny8tT\nhE/UlOzsbB6PVyH/s2bJz8+/fPnyqVOnhELhiBEjevXqVV1C4Ozs7MDAwPPnzyvSLKudhro6TExM\n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\n"
1434 "png": "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\nFhMTs2bNmrCwsIiIiA0bzCthiQAAEHhJREFUNtTI10Z1R5jaCNLWKKjuP4gavvI3b94cNGhQYGDg\nj08zWz7+9ebNmwcOHPjBDajAkydPvLy8pk+fXkHmPjExcdu2bWFhYatWrQoPD9fguqIaWkK/Or8N\nYa1QxRBWoPIcQigUxsXFBQYGfnMULJVKk5KSJkyYoGKnlEql4eHh5etU2xBKJBI/P7/yM7DHjx+r\n7iauOm/evFmwYMGECRPkLrUBAQE+Pj7qrfBUprrMzLUUpFUjqO4/hXpBYzKZ7ObNm0FBQX/99ZcG\n1c6qJCIi4psi7IWFhT9mXbRKcnNzw8LCvL29g4OD58yZM2fOnGHDhml8MFol/4Vlj99eoz+a7t27\nm5mZ3bp1a9q0aUlJSampqQKB4N27d2vWrLl165ajo2PXrl0XLlxYPiHfhw8fVqxYUa9ePQqF0rZt\n29DQUCMjI1WuRaFQ/P395a9Jkrx7926NmvrmzZuTJ0/OmjULAJVK3bhxY/lPbWxsFOkeCwsL5Qsp\ntUEikcTHx9+6dSszM7O4uNjc3DwgIKCWdVbg9u3bAFq2bFnhuiNGjLhy5UpsbGznzp2/2Uga7f/f\nNefPn//06dP48eM1285/GXp6egUFBeWP5OfnEwShPLUnQRBdu3bt2rXrmzdvfHx86HR6eHi4np6e\nplq1dOnSOXPmMBgMANOmTftm+ZcvX757927YsGGaaoDq3L9/Pz4+vrCw8P3795aWljNmzPiR6R7l\nj6ykpKQfdsUfz78nMe8/wvr16/39/d+9e9ewYUPVzzIxMTEyMsrIyOjQoQOfz7927Vr5GlJTUw8d\nOsTj8QwNDbOzsyUSiaGhobGxceV4xBohlUqPHj368uVL5Yl579279/XrVzc3txpVvmrVqvj4+LCw\nsFatWtW0YRkZGbGxsRcuXDAxMRk4cKCFhcX69evLDxGU/LbynLHljxgYGFQX+FFdZmZvb+9du3b5\n+PiUr6pJkyatW7cGcOnSJRcXl/37948aNQpA3759jY2NbW1teTze/fv3d+7caWhoeP/+/RqFE/zX\nGDJkSFJSUkZGhuKIi4vLy5cvX79+rXolmZmZe/fuLS0t9fPzMzY2VqMZBQUFt2/fdnV1lb/Ny8tT\nhE/UlOzsbB6PVyH/s2bJz8+/fPnyqVOnhELhiBEjevXqVV1C4Ozs7MDAwPPnzyvSLKudhro6TExM\n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\n"
1435 }
1435 }
1436 ],
1436 ],
1437 "prompt_number": 120
1437 "prompt_number": 120
1438 }
1438 }
1439 ],
1439 ],
1440 "metadata": {}
1440 "metadata": {}
1441 }
1441 }
1442 ]
1442 ]
1443 } No newline at end of file
1443 }
@@ -1,439 +1,461 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": ""
3 "name": ""
4 },
4 },
5 "nbformat": 3,
5 "nbformat": 3,
6 "nbformat_minor": 0,
6 "nbformat_minor": 0,
7 "worksheets": [
7 "worksheets": [
8 {
8 {
9 "cells": [
9 "cells": [
10 {
10 {
11 "cell_type": "heading",
11 "cell_type": "heading",
12 "level": 1,
12 "level": 1,
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "Running Code in the IPython Notebook"
15 "Running Code in the IPython Notebook"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "markdown",
19 "cell_type": "markdown",
20 "metadata": {},
20 "metadata": {},
21 "source": [
21 "source": [
22 "First and foremost, the IPython Notebook is an interactive environment for writing and running Python code."
22 "First and foremost, the IPython Notebook is an interactive environment for writing and running Python code."
23 ]
23 ]
24 },
24 },
25 {
25 {
26 "cell_type": "heading",
26 "cell_type": "heading",
27 "level": 2,
27 "level": 2,
28 "metadata": {},
28 "metadata": {},
29 "source": [
29 "source": [
30 "Code cells allow you to enter and run Python code"
30 "Code cells allow you to enter and run Python code"
31 ]
31 ]
32 },
32 },
33 {
33 {
34 "cell_type": "markdown",
34 "cell_type": "markdown",
35 "metadata": {},
35 "metadata": {},
36 "source": [
36 "source": [
37 "Run a code cell using `Shift-Enter` or pressing the \"Play\" button in the toolbar above:"
37 "Run a code cell using `Shift-Enter` or pressing the \"Play\" button in the toolbar above:"
38 ]
38 ]
39 },
39 },
40 {
40 {
41 "cell_type": "code",
41 "cell_type": "code",
42 "collapsed": false,
42 "collapsed": false,
43 "input": [
43 "input": [
44 "a = 10"
44 "a = 10"
45 ],
45 ],
46 "language": "python",
46 "language": "python",
47 "metadata": {},
47 "metadata": {},
48 "outputs": [],
48 "outputs": [],
49 "prompt_number": 10
49 "prompt_number": 10
50 },
50 },
51 {
51 {
52 "cell_type": "code",
52 "cell_type": "code",
53 "collapsed": false,
53 "collapsed": false,
54 "input": [
54 "input": [
55 "print(a)"
55 "print(a)"
56 ],
56 ],
57 "language": "python",
57 "language": "python",
58 "metadata": {},
58 "metadata": {},
59 "outputs": [
59 "outputs": [
60 {
60 {
61 "output_type": "stream",
61 "output_type": "stream",
62 "stream": "stdout",
62 "stream": "stdout",
63 "text": [
63 "text": [
64 "10\n"
64 "10\n"
65 ]
65 ]
66 }
66 }
67 ],
67 ],
68 "prompt_number": 11
68 "prompt_number": 11
69 },
69 },
70 {
70 {
71 "cell_type": "heading",
71 "cell_type": "heading",
72 "level": 2,
72 "level": 2,
73 "metadata": {},
73 "metadata": {},
74 "source": [
74 "source": [
75 "Managing the IPython Kernel"
75 "Managing the IPython Kernel"
76 ]
76 ]
77 },
77 },
78 {
78 {
79 "cell_type": "markdown",
79 "cell_type": "markdown",
80 "metadata": {},
80 "metadata": {},
81 "source": [
81 "source": [
82 "Code is run in a separate process called the IPython Kernel. The Kernel can be interrupted or restarted. Try running the following cell and then hit the \"Stop\" button in the toolbar above."
82 "Code is run in a separate process called the IPython Kernel. The Kernel can be interrupted or restarted. Try running the following cell and then hit the \"Stop\" button in the toolbar above."
83 ]
83 ]
84 },
84 },
85 {
85 {
86 "cell_type": "code",
86 "cell_type": "code",
87 "collapsed": false,
87 "collapsed": false,
88 "input": [
88 "input": [
89 "import time\n",
89 "import time\n",
90 "time.sleep(10)"
90 "time.sleep(10)"
91 ],
91 ],
92 "language": "python",
92 "language": "python",
93 "metadata": {},
93 "metadata": {},
94 "outputs": [
94 "outputs": [
95 {
95 {
96 "ename": "KeyboardInterrupt",
96 "ename": "KeyboardInterrupt",
97 "evalue": "",
97 "evalue": "",
98 "output_type": "pyerr",
98 "output_type": "pyerr",
99 "traceback": [
99 "traceback": [
100 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
100 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
101 "\u001b[0;32m<ipython-input-16-d7b436e260d5>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
101 "\u001b[0;32m<ipython-input-16-d7b436e260d5>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mtime\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mtime\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
102 "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
102 "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
103 ]
103 ]
104 }
104 }
105 ],
105 ],
106 "prompt_number": 16
106 "prompt_number": 16
107 },
107 },
108 {
108 {
109 "cell_type": "markdown",
109 "cell_type": "markdown",
110 "metadata": {},
110 "metadata": {},
111 "source": [
111 "source": [
112 "If the Kernel dies you will be prompted to restart it. Here we call the low-level system libc.time routine with the wrong argument via\n",
112 "If the Kernel dies you will be prompted to restart it. Here we call the low-level system libc.time routine with the wrong argument via\n",
113 "ctypes to segfault the Python interpreter:"
113 "ctypes to segfault the Python interpreter:"
114 ]
114 ]
115 },
115 },
116 {
116 {
117 "cell_type": "code",
117 "cell_type": "code",
118 "collapsed": false,
118 "collapsed": false,
119 "input": [
119 "input": [
120 "import sys\n",
120 "import sys\n",
121 "from ctypes import CDLL\n",
121 "from ctypes import CDLL\n",
122 "# This will crash a Linux or Mac system; equivalent calls can be made on Windows\n",
122 "# This will crash a Linux or Mac system; equivalent calls can be made on Windows\n",
123 "dll = 'dylib' if sys.platform == 'darwin' else 'so.6'\n",
123 "dll = 'dylib' if sys.platform == 'darwin' else 'so.6'\n",
124 "libc = CDLL(\"libc.%s\" % dll) \n",
124 "libc = CDLL(\"libc.%s\" % dll) \n",
125 "libc.time(-1) # BOOM!!"
125 "libc.time(-1) # BOOM!!"
126 ],
126 ],
127 "language": "python",
127 "language": "python",
128 "metadata": {},
128 "metadata": {},
129 "outputs": [],
129 "outputs": []
130 "prompt_number": "*"
131 },
130 },
132 {
131 {
133 "cell_type": "heading",
132 "cell_type": "heading",
134 "level": 2,
133 "level": 2,
135 "metadata": {},
134 "metadata": {},
136 "source": [
135 "source": [
137 "All of the goodness of IPython works"
136 "All of the goodness of IPython works"
138 ]
137 ]
139 },
138 },
140 {
139 {
141 "cell_type": "markdown",
140 "cell_type": "markdown",
142 "metadata": {},
141 "metadata": {},
143 "source": [
142 "source": [
144 "Here are two system aliases:"
143 "Here are two system aliases:"
145 ]
144 ]
146 },
145 },
147 {
146 {
148 "cell_type": "code",
147 "cell_type": "code",
149 "collapsed": false,
148 "collapsed": false,
150 "input": [
149 "input": [
151 "pwd"
150 "pwd"
152 ],
151 ],
153 "language": "python",
152 "language": "python",
154 "metadata": {},
153 "metadata": {},
155 "outputs": [
154 "outputs": [
156 {
155 {
156 "metadata": {},
157 "output_type": "pyout",
157 "output_type": "pyout",
158 "prompt_number": 4,
158 "prompt_number": 4,
159 "text": [
159 "text": [
160 "u'/Users/bgranger/Documents/Computation/IPython/code/ipython/examples/notebooks'"
160 "u'/Users/bgranger/Documents/Computation/IPython/code/ipython/examples/notebooks'"
161 ]
161 ]
162 }
162 }
163 ],
163 ],
164 "prompt_number": 4
164 "prompt_number": 4
165 },
165 },
166 {
166 {
167 "cell_type": "code",
167 "cell_type": "code",
168 "collapsed": false,
168 "collapsed": false,
169 "input": [
169 "input": [
170 "ls"
170 "ls"
171 ],
171 ],
172 "language": "python",
172 "language": "python",
173 "metadata": {},
173 "metadata": {},
174 "outputs": [
174 "outputs": [
175 {
175 {
176 "output_type": "stream",
176 "output_type": "stream",
177 "stream": "stdout",
177 "stream": "stdout",
178 "text": [
178 "text": [
179 "01_notebook_introduction.ipynb Octave Magic.ipynb\r\n",
179 "01_notebook_introduction.ipynb Octave Magic.ipynb\r\n",
180 "Animations Using clear_output.ipynb PyLab and Matplotlib.ipynb\r\n",
180 "Animations Using clear_output.ipynb PyLab and Matplotlib.ipynb\r\n",
181 "Basic Output.ipynb R Magics.ipynb\r\n",
181 "Basic Output.ipynb R Magics.ipynb\r\n",
182 "Custom Display Logic.ipynb Running Code.ipynb\r\n",
182 "Custom Display Logic.ipynb Running Code.ipynb\r\n",
183 "Cython Magics.ipynb Script Magics.ipynb\r\n",
183 "Cython Magics.ipynb Script Magics.ipynb\r\n",
184 "Data Publication API.ipynb SymPy Examples.ipynb\r\n",
184 "Data Publication API.ipynb SymPy Examples.ipynb\r\n",
185 "Display System.ipynb Trapezoid Rule.ipynb\r\n",
185 "Display System.ipynb Trapezoid Rule.ipynb\r\n",
186 "JS Progress Bar.ipynb Typesetting Math Using MathJax.ipynb\r\n",
186 "JS Progress Bar.ipynb Typesetting Math Using MathJax.ipynb\r\n",
187 "Local Files.ipynb animation.m4v\r\n",
187 "Local Files.ipynb animation.m4v\r\n",
188 "Markdown Cells.ipynb python-logo.svg\r\n",
188 "Markdown Cells.ipynb python-logo.svg\r\n",
189 "Notebook Tour.ipynb\r\n"
189 "Notebook Tour.ipynb\r\n"
190 ]
190 ]
191 }
191 }
192 ],
192 ],
193 "prompt_number": 2
193 "prompt_number": 2
194 },
194 },
195 {
195 {
196 "cell_type": "markdown",
196 "cell_type": "markdown",
197 "metadata": {},
197 "metadata": {},
198 "source": [
198 "source": [
199 "Any command line program can be run using `!` with string interpolation from Python variables:"
199 "Any command line program can be run using `!` with string interpolation from Python variables:"
200 ]
200 ]
201 },
201 },
202 {
202 {
203 "cell_type": "code",
203 "cell_type": "code",
204 "collapsed": false,
204 "collapsed": false,
205 "input": [
205 "input": [
206 "message = 'The IPython notebook is great!'\n",
206 "message = 'The IPython notebook is great!'\n",
207 "# note: the echo command does not run on Windows, it's a unix command.\n",
207 "# note: the echo command does not run on Windows, it's a unix command.\n",
208 "!echo $message"
208 "!echo $message"
209 ],
209 ],
210 "language": "python",
210 "language": "python",
211 "metadata": {},
211 "metadata": {},
212 "outputs": []
212 "outputs": []
213 },
213 },
214 {
214 {
215 "cell_type": "markdown",
215 "cell_type": "markdown",
216 "metadata": {},
216 "metadata": {},
217 "source": [
217 "source": [
218 "Tab completion works:"
218 "Tab completion works:"
219 ]
219 ]
220 },
220 },
221 {
221 {
222 "cell_type": "code",
222 "cell_type": "code",
223 "collapsed": false,
223 "collapsed": false,
224 "input": [
224 "input": [
225 "import numpy\n",
225 "import numpy\n",
226 "numpy.random."
226 "numpy.random."
227 ],
227 ],
228 "language": "python",
228 "language": "python",
229 "metadata": {},
229 "metadata": {},
230 "outputs": [],
230 "outputs": [],
231 "prompt_number": 9
231 "prompt_number": 9
232 },
232 },
233 {
233 {
234 "cell_type": "markdown",
234 "cell_type": "markdown",
235 "metadata": {},
235 "metadata": {},
236 "source": [
236 "source": [
237 "Shift-Tab on selection, or after `(` brings up a tooltip with the docstring:"
237 "Shift-Tab on selection, or after `(` brings up a tooltip with the docstring:"
238 ]
238 ]
239 },
239 },
240 {
240 {
241 "cell_type": "code",
241 "cell_type": "code",
242 "collapsed": false,
242 "collapsed": false,
243 "input": [
243 "input": [
244 "numpy.random.rand("
244 "numpy.random.rand("
245 ],
245 ],
246 "language": "python",
246 "language": "python",
247 "metadata": {},
247 "metadata": {},
248 "outputs": []
248 "outputs": []
249 },
249 },
250 {
250 {
251 "cell_type": "markdown",
251 "cell_type": "markdown",
252 "metadata": {},
252 "metadata": {},
253 "source": [
253 "source": [
254 "Adding `?` opens the docstring in the pager below:"
254 "Adding `?` opens the docstring in the pager below:"
255 ]
255 ]
256 },
256 },
257 {
257 {
258 "cell_type": "code",
258 "cell_type": "code",
259 "collapsed": false,
259 "collapsed": false,
260 "input": [
260 "input": [
261 "magic?"
261 "magic?"
262 ],
262 ],
263 "language": "python",
263 "language": "python",
264 "metadata": {},
264 "metadata": {},
265 "outputs": [],
265 "outputs": [],
266 "prompt_number": 8
266 "prompt_number": 8
267 },
267 },
268 {
268 {
269 "cell_type": "markdown",
269 "cell_type": "markdown",
270 "metadata": {},
270 "metadata": {},
271 "source": [
271 "source": [
272 "Exceptions are formatted nicely:"
272 "Exceptions are formatted nicely:"
273 ]
273 ]
274 },
274 },
275 {
275 {
276 "cell_type": "code",
276 "cell_type": "code",
277 "collapsed": false,
277 "collapsed": false,
278 "input": [
278 "input": [
279 "x = 1\n",
279 "x = 1\n",
280 "y = 4\n",
280 "y = 4\n",
281 "z = y/(1-x)"
281 "z = y/(1-x)"
282 ],
282 ],
283 "language": "python",
283 "language": "python",
284 "metadata": {},
284 "metadata": {},
285 "outputs": [
285 "outputs": [
286 {
286 {
287 "ename": "ZeroDivisionError",
287 "ename": "ZeroDivisionError",
288 "evalue": "integer division or modulo by zero",
288 "evalue": "integer division or modulo by zero",
289 "output_type": "pyerr",
289 "output_type": "pyerr",
290 "traceback": [
290 "traceback": [
291 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
291 "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)",
292 "\u001b[0;32m<ipython-input-15-dc39888fd1d2>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mz\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
292 "\u001b[0;32m<ipython-input-15-dc39888fd1d2>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mz\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
293 "\u001b[0;31mZeroDivisionError\u001b[0m: integer division or modulo by zero"
293 "\u001b[0;31mZeroDivisionError\u001b[0m: integer division or modulo by zero"
294 ]
294 ]
295 }
295 }
296 ],
296 ],
297 "prompt_number": 15
297 "prompt_number": 15
298 },
298 },
299 {
299 {
300 "cell_type": "heading",
300 "cell_type": "heading",
301 "level": 2,
301 "level": 2,
302 "metadata": {},
302 "metadata": {},
303 "source": [
303 "source": [
304 "Working with external code"
304 "Working with external code"
305 ]
305 ]
306 },
306 },
307 {
307 {
308 "cell_type": "markdown",
308 "cell_type": "markdown",
309 "metadata": {},
309 "metadata": {},
310 "source": [
310 "source": [
311 "There are a number of ways of getting external code into code cells."
311 "There are a number of ways of getting external code into code cells."
312 ]
312 ]
313 },
313 },
314 {
314 {
315 "cell_type": "markdown",
315 "cell_type": "markdown",
316 "metadata": {},
316 "metadata": {},
317 "source": [
317 "source": [
318 "Pasting code with `>>>` prompts works as expected:"
318 "Pasting code with `>>>` prompts works as expected:"
319 ]
319 ]
320 },
320 },
321 {
321 {
322 "cell_type": "code",
322 "cell_type": "code",
323 "collapsed": false,
323 "collapsed": false,
324 "input": [
324 "input": [
325 ">>> the_world_is_flat = 1\n",
325 ">>> the_world_is_flat = 1\n",
326 ">>> if the_world_is_flat:\n",
326 ">>> if the_world_is_flat:\n",
327 "... print(\"Be careful not to fall off!\")"
327 "... print(\"Be careful not to fall off!\")"
328 ],
328 ],
329 "language": "python",
329 "language": "python",
330 "metadata": {},
330 "metadata": {},
331 "outputs": [
331 "outputs": [
332 {
332 {
333 "output_type": "stream",
333 "output_type": "stream",
334 "stream": "stdout",
334 "stream": "stdout",
335 "text": [
335 "text": [
336 "Be careful not to fall off!\n"
336 "Be careful not to fall off!\n"
337 ]
337 ]
338 }
338 }
339 ],
339 ],
340 "prompt_number": 1
340 "prompt_number": 1
341 },
341 },
342 {
342 {
343 "cell_type": "markdown",
343 "cell_type": "markdown",
344 "metadata": {},
344 "metadata": {},
345 "source": [
345 "source": [
346 "The `%load` magic lets you load code from URLs or local files:"
346 "The `%load` magic lets you load code from URLs or local files:"
347 ]
347 ]
348 },
348 },
349 {
349 {
350 "cell_type": "code",
350 "cell_type": "code",
351 "collapsed": false,
351 "collapsed": false,
352 "input": [
352 "input": [
353 "%load?"
353 "%load?"
354 ],
354 ],
355 "language": "python",
355 "language": "python",
356 "metadata": {},
356 "metadata": {},
357 "outputs": [],
357 "outputs": [],
358 "prompt_number": 14
358 "prompt_number": 14
359 },
359 },
360 {
360 {
361 "cell_type": "code",
361 "cell_type": "code",
362 "collapsed": false,
362 "collapsed": false,
363 "input": [
363 "input": [
364 "%matplotlib inline"
364 "%matplotlib inline"
365 ],
365 ],
366 "language": "python",
366 "language": "python",
367 "metadata": {},
367 "metadata": {},
368 "outputs": [],
368 "outputs": [],
369 "prompt_number": 1
369 "prompt_number": 1
370 },
370 },
371 {
371 {
372 "cell_type": "code",
372 "cell_type": "code",
373 "collapsed": false,
373 "collapsed": false,
374 "input": [
374 "input": [
375 "%load http://matplotlib.sourceforge.net/mpl_examples/pylab_examples/integral_demo.py"
375 "%load http://matplotlib.org/mpl_examples/showcase/integral_demo.py"
376 ],
376 ],
377 "language": "python",
377 "language": "python",
378 "metadata": {},
378 "metadata": {},
379 "outputs": [],
379 "outputs": [],
380 "prompt_number": 2
380 "prompt_number": 2
381 },
381 },
382 {
382 {
383 "cell_type": "code",
383 "cell_type": "code",
384 "collapsed": false,
384 "collapsed": false,
385 "input": [
385 "input": [
386 "#!/usr/bin/env python\n",
386 "\"\"\"\n",
387 "Plot demonstrating the integral as the area under a curve.\n",
387 "\n",
388 "\n",
388 "# implement the example graphs/integral from pyx\n",
389 "Although this is a simple example, it demonstrates some important tweaks:\n",
389 "from pylab import *\n",
390 "\n",
391 " * A simple line plot with custom color and line width.\n",
392 " * A shaded region created using a Polygon patch.\n",
393 " * A text label with mathtext rendering.\n",
394 " * figtext calls to label the x- and y-axes.\n",
395 " * Use of axis spines to hide the top and right spines.\n",
396 " * Custom tick placement and labels.\n",
397 "\"\"\"\n",
398 "import numpy as np\n",
399 "import matplotlib.pyplot as plt\n",
390 "from matplotlib.patches import Polygon\n",
400 "from matplotlib.patches import Polygon\n",
391 "\n",
401 "\n",
402 "\n",
392 "def func(x):\n",
403 "def func(x):\n",
393 " return (x-3)*(x-5)*(x-7)+85\n",
404 " return (x - 3) * (x - 5) * (x - 7) + 85\n",
394 "\n",
405 "\n",
395 "ax = subplot(111)\n",
396 "\n",
406 "\n",
397 "a, b = 2, 9 # integral area\n",
407 "a, b = 2, 9 # integral limits\n",
398 "x = arange(0, 10, 0.01)\n",
408 "x = np.linspace(0, 10)\n",
399 "y = func(x)\n",
409 "y = func(x)\n",
400 "plot(x, y, linewidth=1)\n",
401 "\n",
410 "\n",
402 "# make the shaded region\n",
411 "fig, ax = plt.subplots()\n",
403 "ix = arange(a, b, 0.01)\n",
412 "plt.plot(x, y, 'r', linewidth=2)\n",
413 "plt.ylim(ymin=0)\n",
414 "\n",
415 "# Make the shaded region\n",
416 "ix = np.linspace(a, b)\n",
404 "iy = func(ix)\n",
417 "iy = func(ix)\n",
405 "verts = [(a,0)] + list(zip(ix,iy)) + [(b,0)]\n",
418 "verts = [(a, 0)] + list(zip(ix, iy)) + [(b, 0)]\n",
406 "poly = Polygon(verts, facecolor='0.8', edgecolor='k')\n",
419 "poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')\n",
407 "ax.add_patch(poly)\n",
420 "ax.add_patch(poly)\n",
408 "\n",
421 "\n",
409 "text(0.5 * (a + b), 30,\n",
422 "plt.text(0.5 * (a + b), 30, r\"$\\int_a^b f(x)\\mathrm{d}x$\",\n",
410 " r\"$\\int_a^b f(x)\\mathrm{d}x$\", horizontalalignment='center',\n",
423 " horizontalalignment='center', fontsize=20)\n",
411 " fontsize=20)\n",
424 "\n",
425 "plt.figtext(0.9, 0.05, '$x$')\n",
426 "plt.figtext(0.1, 0.9, '$y$')\n",
427 "\n",
428 "ax.spines['right'].set_visible(False)\n",
429 "ax.spines['top'].set_visible(False)\n",
430 "ax.xaxis.set_ticks_position('bottom')\n",
412 "\n",
431 "\n",
413 "axis([0,10, 0, 180])\n",
432 "ax.set_xticks((a, b))\n",
414 "figtext(0.9, 0.05, 'x')\n",
433 "ax.set_xticklabels(('$a$', '$b$'))\n",
415 "figtext(0.1, 0.9, 'y')\n",
416 "ax.set_xticks((a,b))\n",
417 "ax.set_xticklabels(('a','b'))\n",
418 "ax.set_yticks([])\n",
434 "ax.set_yticks([])\n",
419 "show()\n"
435 "\n",
436 "plt.show()\n"
420 ],
437 ],
421 "language": "python",
438 "language": "python",
422 "metadata": {},
439 "metadata": {},
423 "outputs": [
440 "outputs": [
424 {
441 {
425 "metadata": {},
442 "metadata": {
443 "png": {
444 "height": 401,
445 "width": 596
446 }
447 },
426 "output_type": "display_data",
448 "output_type": "display_data",
427 "png": "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\nAAAAQvD/AKh2fy0Nfo/2AAAAAElFTkSuQmCC\n",
449 "png": "iVBORw0KGgoAAAANSUhEUgAABKkAAAMiCAYAAAClk5ArAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzs3XmUXHWZN/DnVlV3Vy8JYQuEfVEUiTLqATcc9QUcZXTg\n5YhsoiIoiEAIgkpQNiEECZuKhE3UDKOCggKuMKMgCjgCI0Ec4UVQiATI2kl6rar7/tGkySUJZOnu\nW931+ZxTp+r33FtV34Qm3fnm3lsRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsuB0i4qsRcVtE\nHPqSbZ+JiNtHOhAAAAAAjefyiChFxJSI+ONLtt0XEf8x4okAAAAAGFUKG/j8d0TEbyKiEhHvi4i/\nrLStPSLeGBF3buB7AAAAAMDL2iIimiNi6xgoqvZfadu+EVGLiF1zyAUAAABAA5oaEYsiomml2TkR\n8Ww+cQAAAAAYTTb0dL8V/iUifhUR/SvN/jkGTgUEAAAAgJc1VCXVdpG9HlVLROwZEXcN0esDAAAA\nMIYNVUn1t4jYdKX1jIgoh4umAwAAALAWkiF6nddExDUR8T8R0RURb4+I3SJikyF6/Zd1xx13pBER\n++yzz1D9egAAAAAYQaUhep2/RMQ7X3icRMQzEXHLEL32Wlu4cGE60u8JAAAAMFZtsskmI3ZA0FCc\n7vfdiPjjSusDImLjiDh/CF4bAAAAgAYwFCXV3hHx6xcebxURMyPi45G9kDoAAAAArNFQnO53bETs\nEREXRsSWEXFIRPz3ELwuAAAAAA1iKEqqm164AQAAAMB6GYrT/QAAAABggyipAAAAAMidkgoAAACA\n3CmpAAAAAMidkgoAAACA3CmpAAAAAMidkgoAAACA3CmpAAAAAMidkgoAAACA3CmpAAAAAMidkgoA\nAACA3CmpAAAAAMidkgoAAACA3CmpAAAAAMidkgoAAACA3CmpAAAAAMidkgoAAACA3CmpAAAAAMid\nkgoAAACA3CmpAAAAAMidkgoAAACA3CmpAAAAAMidkgoAAACA3CmpAAAAAMidkgoAAACA3CmpAAAA\nAMidkgoAAACAVaXpiL6dkgoAAACArDSNcfvtN6JvqaQCAAAAIKN0xx1Ruu++EX1PJRUAAAAAL0rT\naL3oohF/WyUVAAAAAINK99wTpd//fsTfV0kFAAAAwKDyxRfn8r5KKgAAAAAiIqL4xz9G03/9Vy7v\nraQCAAAAICIiypdcktt7K6kAAAAAiMKjj0bTrbfm9/65vTMAAAAAdaN82WWRpOnguvL614/o+yup\nAAAAABpc4amnovnGGzOznpNOGtkMI/puAAAAANSdlq9/PZJKZXBd3Xnn6P+3fxvRDEoqAAAAgAaW\nPP98tMyenZn1TJkSUSyOaA4lFQAAAEADa5k1K5KensF1bautou/DHx7xHEoqAAAAgAaVLFkS5Wuu\nycx6Tjghorl5xLMoqQAAAAAaVMu110aydOngurbpptF7xBG5ZFFSAQAAADSirq5oueKKzKj305+O\naGvLJY6SCgAAAKABtcyeHYUFCwbXaUdH9B51VG55lFQAAAAAjaavL8pf+1pm1HP00ZFutFFOgZRU\nAAAAAA2n+cYbo/CPfwyu03I5eo89NsdESioAAACAxlKtRvmyyzKj3iOOiHTixJwCDVBSAQAAADSQ\npltvjeL/+3+D67RUit7jj88x0QAlFQAAAECjSNMoX3JJZtR30EFR23bbnAK9SEkFAAAA0CBKd9wR\npTlzBtdpkkTPlCk5JnqRkgoAAACgQbz0KKr+D3wgarvsklOaLCUVAAAAQAMo3XNPNN17b2bWM3Vq\nTmlWpaQCAAAAaACrHEX1f/5PVP/pn3JKsyolFQAAAMAYV3zooWi6447MrOfkk3NKs3pKKgAAAIAx\n7qVHUVXe8paovO1tOaVZPSUVAAAAwBhWeOyxaLrllsys++STI5Ikp0Srp6QCAAAAGMPKl10WSZoO\nriuTJ0dln31yTLR6SioAAACAMSp5+ulovuGGzKznpJPq7iiqCCUVAAAAwJhV/vrXI6lUBtfVnXaK\n/v33zzHRmimpAAAAAMag5Pnno2X27MysZ8qUiGIxp0QvT0kFAAAAMAa1XHllJN3dg+vaVltF38EH\n55jo5SmpAAAAAMaazs4oX311ZtRz/PERzc05BXplSioAAACAMaZ87bWRLF06uK5tumn0HnFEjole\nmZIKAAAAYCzp6oqWK67IjHqPPTaivT2nQGtHSQUAAAAwhrRcf30U5s8fXKcdHdF79NE5Jlo7SioA\nAACAsaKvL8pf/Wpm1HvUUZFutFFOgdaekgoAAABgjGj+wQ+iMHfu4Dotl6Pn05/OMdHaU1IBAAAA\njAXVapQvuywz6v3IRyKdODGnQOtGSQUAAAAwBjTddlsUH3tscJ2WStF7wgk5Jlo3SioAAACA0S5N\no3zJJZlR30EHRW3bbXMKtO6UVAAAAACjXOm//itKDz00uE6TJHpOPDHHROtOSQUAAAAwyr30KKr+\nf/3XqL3mNTmlWT9KKgAAAIBRrHjvvdH0u99lZj1Tp+aUZv0pqQAAAABGsdaXHkX1nvdE9Y1vzCnN\n+lNSAQAAAIxSxTlzoun22zOznpNPzinNhlFSAQAAAIxSL70WVWXPPaPy9rfnlGbDKKkAAAAARqHC\nY49F049/nJl1n3xyRJLklGjDKKkAAAAARqHWCy6IJE0H15XddovKvvvmmGjDKKkAAAAARpniww9H\n8003ZWY9o/goqgglFQAAAMCoU54+PbOuTJ4c/fvvn1OaoaGkAgAAABhFiv/939H8859nZt1f/GJE\nYXTXPKM7PQAAAECDaT3vvMy6ssceo/paVCsoqQAAAABGidKdd0bTXXdlZt1f+tKovhbVCkoqAAAA\ngNEgTaP13HMzo/53vSsqe+2VU6ChpaQCAAAAGAWafvGLKN1/f2bW/cUv5pRm6CmpAAAAAOpdrRbl\nl1yLqm+//aL65jfnFGjoKakAAAAA6lzTzTdH6U9/GlynSRLd06blmGjoKakAAAAA6lmlEq0zZmRG\n/QceGLXXvS6nQMNDSQUAAABQx5q/+90oPv744DotFqP7C1/IMdHwUFIBAAAA1Kve3ihfeGFm1HfY\nYVHbeeecAg0fJRUAAABAnWr59rej+PTTg+u0uTm6Tz01x0TDR0kFAAAAUI+WL4/yRRdlRr1HHhnp\nNtvkFGh4KakAAAAA6lDL1VdH4fnnB9dpW1v0TJ2aY6LhpaQCAAAAqDPJkiVRvuyyzKzn2GMjnTgx\np0TDT0kFAAAAUGdavv71KCxZMriujR8fvccfn2Oi4aekAgAAAKgjyfPPR3nWrMys94QTIp0wIadE\nI0NJBQAAAFBHypdeGsny5YPr2mabRc8xx+SYaGQoqQAAAADqRDJ3brR885uZWc/UqREdHTklGjlK\nKgAAAIA60TpzZiS9vYPr2lZbRe+RR+aYaOQoqQAAAADqQOGJJ6L5+uszs+5TT40ol3NKNLKUVAAA\nAAB1oHzBBZFUKoPr6o47Rt9hh+WYaGQpqQAAAAByVnjkkWi+8cbMrPu00yKamnJKNPKUVAAAAAA5\na50xI5I0HVxXd901+g88MMdEI09JBQAAAJCj4gMPRPNtt2Vm3dOmRRQaq7ZprF8tAAAAQJ1pPe+8\nzLrypjdF/3775ZQmP0oqAAAAgJyUfvvbaPrVrzKz7tNPj0iSnBLlR0kFAAAAkIc0jdZzz82M+vfa\nKyrvfnc+eXKmpAIAAADIQemOO6J0332ZWaMeRRWhpAIAAAAYebXaKtei6t9336i+5S05BcqfkgoA\nAABghDXdemuUHnooM+s+/fSc0tQHJRUAAADASKpWo3X69Myob//9o/qGN+QUqD4oqQAAAABGUPMN\nN0TxsccG12mhEN2nnZZjovqgpAIAAAAYKX19Ub7gguzo4IOjtssuOQWqH0oqAAAAgBHSMnt2FP/+\n98F12tQUPZ//fI6J6oeSCgAAAGAkdHVF+aKLMqPej30satttl1Og+qKkAgAAABgBLddeG4V58wbX\naWtr9Jx8co6J6ouSCgAAAGC4dXZG+dJLM6Peo4+OdMstcwpUf5RUAAAAAMOsfMUVUVi0aHCddnRE\nz5QpOSaqP0oqAAAAgGGULFwY5csvz8x6PvOZSDfZJKdE9UlJBQAAADCMypddFsmyZYPr2iabRM+n\nP51jovqkpAIAAAAYJsnTT0fL1VdnZj1TpkSMH59TovqlpAIAAAAYJm1nnx1JT8/gurblltF79NE5\nJqpfSioAAACAYVC8775o/uEPM7Puz38+orU1p0T1TUkFAAAAMNRqtWg7/fTMqDJ5cvR95CM5Bap/\nSioAAACAIdZ8ww1ReuCBzKz7/PMjisWcEtU/JRUAAADAUFq2LFrPOScz6vvgB6PyjnfkFGh0UFIB\nAAAADKHyZZdFYd68wXXa3BzdZ5+dY6LRQUkFAAAAMEQKTz0V5csvz8x6jjsuajvskE+gUURJBQAA\nADBEWs88M5KensF1beLE6Jk6NcdEo4eSCgAAAGAIFO+9N5p/9KPMrPuLX4wYNy6nRKOLkgoAAABg\nQ9Vq0TZtWmZU2X336DvssJwCjT5KKgAAAIAN1Pzd70bpf/4nM+uePj2ioHpZW36nAAAAADbE0qXR\neu65mVHf/vtH5W1vyynQ6KSkAgAAANgA5UsvjcKzzw6u05aW6D777BwTjU5KKgAAAID1VPjb36L8\njW9kZj3HHx+17bbLKdHopaQCAAAAWE+tZ54ZSW/v4Lq25ZbRM2VKjolGLyUVAAAAwHoo/fa30XzL\nLZlZ95e+FNHRkVOi0U1JBQAAALCuqtVonTYtM6q88Y3Rd/DBOQUa/ZRUAAAAAOuo+T/+I0pz5mRm\nXeedF1FQtawvv3MAAAAA66KzM1rPPTcz6jvwwKi+9a05BRoblFQAAAAA66D14ouj8Pzzg+u0tTW6\nzjorv0BjhJIKAAAAYC0VnngiWmbNysx6jj8+0m22ySnR2KGkAgAAAFhLrWeeGUlf3+C6NmlS9Jx4\nYo6Jxg4lFQAAAMBaKP3mN9F8222ZWfeZZ0a0t+eUaGxRUgEAAAC8kmo1WqdNy4wqb35z9H3oQzkF\nGnuUVAAAAACvoHn27Cj96U+ZWdf06REF1cpQ8TsJAAAA8HI6O6N1+vTMqPegg6K6xx45BRqblFQA\nAAAAL6N15swozJ8/uE5bW6P7jDNyTDQ2KakAAAAA1qDw+OPRcuWVmVnPiSdGuvXWOSUau5RUAAAA\nAGvQesYZkfT3D65rW28dPSeckGOisUtJBQAAALAapV//Opp/9rPMrOussyLa2vIJNMYpqQAAAABe\nqlKJttNPz4722CP6Dzwwp0Bjn5IKAAAA4CWav/OdKP75z5lZ1/nnRyRJTonGPiUVAAAAwEqSJUui\ndfr0zKz3kEOi+qY35ZSoMSipAAAAAFZS/spXorBw4eA6bWuL7i9+McdEjUFJBQAAAPCCwmOPRcvV\nV2dmPSedFOlWW+WUqHEoqQAAAABe0PqlL0VSqQyuq9tsEz2f+UyOiRqHkgoAAAAgIkr/+Z/R/Mtf\nZmbdZ50V0dqaT6AGo6QCAAAAqFSi7SXXnep/61uj///+35wCNR4lFQAAANDwWq67Lop/+cvgOk2S\n6J4+PSJJckzVWJRUAAAAQENL5s2L8nnnZWZ9hxwS1X/6p5wSNSYlFQAAANDQ2qZNi0Jn5+A6bW+P\n7i99KcdEjUlJBQAAADSspl/8Ipp/9KPMrPu00yLdcsucEjUuJRUAAADQmJYujbZTTsmMKm98Y/Qe\nc0xOgRqbkgoAAABoSK3Tp0dh7tzBdVosRtcll0QUizmmalxKKgAAAKDhFO+/P1quuioz6z3uuKi+\n4Q05JUJJBQAAADSW/v5omzo1kjQdHFW33z66P/e5HEOhpAIAAAAaSssVV0Tp4Yczs66ZMyPa23NK\nRISSCgAAAGgghSeeiNYLLsjMeg86KCp7751TIlZQUgEAAACNIU2j7bOfjaS7e3BU23jj6D733BxD\nsYKSCgAAAGgIzTfeGE2//nVm1v3lL0e6+eb5BCJDSQUAAACMecmCBdF6+umZWf873xl9hx6aUyJe\nSkkFAAAAjHmtZ5wRhQULBtdpS0t0XXxxRJLkmIqVKakAAACAMa10553R8t3vZmY9p54atZ13zikR\nq6OkAgAAAMau7u5oO/nkzKi6667Rc/zxOQViTZRUAAAAwJhVvvDCKD7xxOA6TZJYfumlEc3NOaZi\ndZRUAAAAwJhU/NOfovy1r2VmvUcfHdU99sgpES9HSQUAAACMPdVqtE2ZEkm1OjiqTZoU3S/5hD/q\nh5IKAAAAGHNarr02Sg88kJl1XXhhxPjxOSXilSipAAAAgDElefrpaD333Mys7wMfiP799sspEWtD\nSQUAAACMHWkabZ/7XCTLlr04GjcuumbMyDEUa0NJBQAAAIwZTbfeGs0//3lm1nXmmZFutVVOiVhb\nSioAAABgTEiWLIm2L3whM6vsuWf0ffzj+QRinSipAAAAgDGh9ZxzojBv3uA6bWqK5ZdcElFQf4wG\n/isBAAAAo17x3nuj5brrMrOeE0+M2q675pSIdaWkAgAAAEa33t5oP+mkzKi6887R89nP5hSI9aGk\nAgAAAEa18mWXRfHRRzOzrksuiSiXc0rE+lBSAQAAAKNW4dFHo3zxxZlZ7+GHR2WvvXJKxPpSUgEA\nAACjU60WbVOnRtLX9+Jo882j+5xzcgzF+lJSAQAAAKNS87//ezTdc09m1jV9eqQbb5xTIjaEkgoA\nAAAYdZJnn43WM8/MzPr32Sf6Dzwwp0RsKCUVAAAAMOq0TZsWhSVLBtdpW1t0zZwZkSQ5pmJDKKkA\nAACAUaX0y19G8803Z2bdp50Wte22yykRQ0FJBQAAAIwey5ZF2ymnZEaV3XeP3mOOySkQQ0VJBQAA\nAIwareefH8Wnnx5cp4VCdF16aUSplGMqhoKSCgAAABgVig8+GC1XXpmZ9X7601HdffecEjGUlFQA\nAABA/evqivZjj42kVhscVbfdNrq/8IUcQzGUlFQAAABA3Ws9++woPvZYZtY1c2ZEe3tOiRhqSioA\nAACgrpVuvz3KV1+dmfUedlhU9t03p0QMByUVAAAAULeS+fOj/YQTMrPqDjtE1/nn55SI4aKkAgAA\nAOpTmkbbSSdF4bnnXhwVCrF81qyIceNyDMZwUFIBAAAAdal59uxo/ulPM7Oez342qnvumVMihpOS\nCgAAAKg7hccfj7Zp0zKzypvfHD2nnJJTIoabkgoAAACoL/390X7MMZF0dQ2O0vb2gdP8mppyDMZw\nUlIBAAAAdaV80UVReuCBzKzrvPOitvPOOSViJCipAAAAgLpR/P3vo3zRRZlZ3377Rd8RR+SUiJGi\npAIAAADqw9Kl0f7pT0dSrQ6OahMnRtell0YkSY7BGAlKKgAAAKAutE2bFsUnnsjMln/ta5FutllO\niRhJSioAAAAgd0233hot11+fmfUcfXRU9t03p0SMNCUVAAAAkKvkmWei7aSTMrPqq18d3WedlU8g\ncqGkAgAAAPJTq0X78cdHYdGiwVHa1BTLr7oqoq0tx2CMNCUVAAAAkJuWa66Jpl/9KjPrnjYtqrvv\nnlMi8qKkAgAAAHJR+POfo/Ulp/T1v/3t0Xv88fkEIldKKgAAAGDk9fZG+7HHRtLTMzhKx42Lriuu\niCgWcwxGXpRUAAAAwIhrPf/8KM2Zk5l1zZwZtW23zSkReVNSAQAAACOqdPfd0fK1r2VmfQceGH0f\n+lBOiagHSioAAABgxCSLF0f7pz8dSZoOzmpbbx1dM2dGJEmOycibkgoAAAAYMW2nnhqFuXMH12mS\nxPJvfCPSCRNyTEU9UFIBAAAAI6LpBz+I5h/+MDPrPf74qLzznTklop4oqQAAAIBhV3jqqWg75ZTM\nrDJ5cnRPm5ZTIuqNkgoAAAAYXtVqtB13XBQ6OwdHaUtLLL/yyoiWlhyDUU+UVAAAAMCwarn88mj6\n7W8zs+6zzorarrvmlIh6pKQCAAAAhk3xoYei9bzzMrP+97wnej/5yZwSUa+UVAAAAMDw6O6O9k99\nKpL+/sFRbeONY/nXvx5RUEmQ5SsCAAAAGBatZ58dxUcfzcy6Lr000kmTckpEPVNSAQAAAEOudMcd\nUb7qqsys9/DDo/+DH8wpEfVOSQUAAAAMqWT+/Gg/4YTMrLrDDtE1fXpOiRgNlFQAAADA0EnTaJs6\nNQrPPvviqFCI5bNmRYwbl2Mw6p2SCgAAABgyLddcE80/+Ulm9sxRR0V1zz1zSsRooaQCAAAAhkTx\n3nuj9fTTM7Pnd9wxnjnqqJwSMZooqQAAAIANlsybFx1HHhlJpTI4q3V0xF2f+lREqZRjMkYLXyUA\nAADAhunri44jj8xchyoiYvFll0VnkuQUitHGkVQAAADABmk944wo3XdfZrbsxBOj9/3vzykRo5GS\nCgAAAFhvzTfcEOWrrsrMet/1rlh66qk5JWK0UlIBAAAA66U4Z060TZ2amVW22SYWXX55RLGYUypG\nKyUVAAAAsM6SRYui/aMfjaS7e3CWlsux6JprIt1kkxyTMVopqQAAAIB1U61G+6c+FcW//S0zXjJj\nRlTe8IacQjHaKakAAACAdVK+4IJo+s//zMyWf+xj0f3hD+eUiLFASQUAAACstaaf/zxaZ87MzPre\n/OboPPvsnBIxViipAAAAgLVSePzxaD/mmMysutlmseiqqyKam3NKxVihpAIAAABe2bJl0fHRj0ay\ndOngKC0WY/FVV0Vt0qQcgzFWKKkAAACAl5em0T5lShT//OfMuPOMM6LvrW/NKRRjjZIKAAAAeFkt\nV1wRzTffnJl1H3BAdB19dE6JGIuUVAAAAMAale6+O1rPPDMz699111gyc2ZEkuSUirFISQUAAACs\nVjJ3brQfdVQk1ergrDZ+fCy65ppI29pyTMZYpKQCAAAAVtXbGx0f/3gUnn8+M178ta9FdccdcwrF\nWKakAgAAAFbRNm1alO6/PzNbevLJ0bvvvjklYqxTUgEAAAAZzddfHy3XXZeZ9ey9dyw7+eScEtEI\nlFQAAADAoOL//E+0nXJKZlbZfvtY/LWvRRTUCAwfX10AAABAREQkCxZE+0c/Gklv7+AsLZdj0bXX\nRjphQo7JaARKKgAAACCiWo32o4+O4tNPZ8aLZ86Myutel1MoGomSCgAAAIjyeedF0513ZmbLjzoq\neg48MKdENBolFQAAADS4pltvjdZLL83Met/ylug844ycEtGIlFQAAADQwAqPPhrtn/lMZlbdYotY\nfOWVEU1NOaWiESmpAAAAoFEtXRodRxwRybJlg6O0qSkWXXVV1CZOzDEYjUhJBQAAAI0oTaP9M5+J\n4mOPZcadZ50V/XvskVMoGpmSCgAAABpQy1e/Gs233ZaZdR10UHR9/OP5BKLhKakAAACgwTTdemu0\nnnNOZta/226xZMaMiCTJKRWNTkkFAAAADaR4773RfswxkaTp4Kw2YUIsuvbaiNbWHJPR6JRUAAAA\n0CAKjz4aHYcdFklPz+AsLRZj0Te+EdXttssxGSipAAAAoCEk8+ZFx0EHRWHx4sx8yYUXRt+7351P\nKFiJkgoAAADGuqVLo+OQQ6L41FPZ8SmnRPchh+QUCrKUVAAAADCW9fdHx8c/HqWHHsqMuw47LJZN\nnZpTKFiVkgoAAADGqjSNtilToulXv8qMe/be2yf5UXeUVAAAADBGladPj5bvfS8z69t991g8a1ZE\nqZRTKlg9JRUAAACMQc3f+la0XnRRZlbZfvtYNHt2pO3tOaWCNVNSAQAAwBjT9LOfRdspp2Rm1U02\niYXXXx+1zTbLKRW8PCUVAAAAjCHF//7vaD/66EhqtcFZWi7Hou98J6o77ZRjMnh5SioAAAAYIwqP\nPx4dhx0WSXf34CwtFGLRrFnR/6Y35ZgMXpmSCgAAAMaA5LnnouOgg6KwYEFm3nn++dH73vfmlArW\nnpIKAAAARrtly6Lj0EOj+OSTmfHSKVOi64gj8skE60hJBQAAAKNZpRIdRx0VpQcfzIy7PvzhWPa5\nz+UUCtadkgoAAABGqzSNtpNPjqbbb8+Me9/1rlhy4YURSZJTMFh3SioAAAAYpcpf+Uq0/Pu/Z2b9\nkyfHoquvjmhqyikVrB8lFQAAAIxCzbNnR+sFF2RmlW22iYWzZ0fa0ZFTKlh/SioAAAAYZUq33x5t\nJ5+cmdU23jgWXn991LbYIqdUsGGUVAAAADCKFB98MDqOPDKSanVwlpbLsfC666L66lfnmAw2jJIK\nAAAARonCk09GxyGHRNLVNThLkyQWXX559O+5Z47JYMMpqQAAAGAUSObPj46DDorC889n5p1f/nL0\nvv/9OaWCoaOkAgAAgHrX1RUdhx4axccfz4yXHXdcdH3iEzmFgqGlpAIAAIB6VqlE+yc/GaX778+M\nuw88MJZOm5ZTKBh6SioAAACoV2kabZ//fDT/7GeZce9ee8Xiiy+OKPhrPWOHr2YAAACoU+ULL4yW\n667LzPpf97pYdM01Ec3NOaWC4aGkAgAAgDpUnjkzWmfMyMyqW20VC2fPjnT8+JxSwfAp5R0AAAAA\nyCp/5SurFFS1jTaKhddfH7VJk3JKBcNLSQUAAAB1pDxjRrR+5SuZWa29PRZ+61tRec1rckoFw09J\nBQAAAPUgTQcKqgsvzIxr7e2x8Prro3/PPXMKBiNDSQUAAAB5S9MoT58erRddlBnXOjoGCqo99sgp\nGIwcJRUAAADkKU2jfN550XrxxZlxbdy4WPgf/xH9b35zTsFgZCmpAAAAIC9pGuUvfzlaL700M66N\nGxcLv/vd6H/Tm3IKBiNPSQUAAAB5SNNoPfvsKH/1q5lxbfz4gYLqjW/MKRjkQ0kFAAAAIy1No/XM\nM6P89a9nxrWNNoqF3/te9O++e07BID9KKgAAABhJaRqtX/pSlL/xjcy4ttFGseD734/KG96QUzDI\nl5IKAACVkIiNAAAgAElEQVQARkqaRuvpp0d51qzMuDZhQiz43vcUVDQ0JRUAAACMhDSN1mnTonzl\nlZlxbeONBwqq178+p2BQH5RUAAAAMNzSNFpPOy3KV12VGdc23njgFL/Jk3MKBvVDSQUAAADDKU2j\n9fOfj/I112TGtY03jgU33BCV3XbLKRjUFyUVAAAADJdaLVo/97kof/ObmXF1k01i4Q03ROV1r8sp\nGNQfJRUAAAAMh1ot2k49NVquuy4zrm66aSy88caovPa1OQWD+qSkAgAAgKFWq0XbZz8bLd/+dmZc\n3WyzgYLqNa/JKRjULyUVAAAADKVaLdqmTo2W2bMz4+rmmw8UVLvsklMwqG9KKgAAABgqtVq0TZkS\nLddfnxlXN988Fv7gB1F59atzCgb1T0kFAAAAQ6FajbYTT4yW7343O544MRbceGNUFVTwsgp5BwAA\nAIBRb00F1RZbxIIf/EBBBWvBkVQAAACwIarVaDv++Gj5/vez4y23HDiCauedcwoGo4uSCgAAANZX\nV1e0H3tsNN92W2ZcnTRpoKDaaaecgsHoo6QCAACA9ZA891x0HHZYlB54IDOvTpo0cIrfjjvmlAxG\nJyUVAAAArKPCX/4SHQcfHMW//z0zr2611UBBtcMO+QSDUcyF0wEAAGAdlH7zmxj3vvetUlD177pr\nzP/xjxVUsJ6UVAAAALCWmr/3vej40IeisGRJZt7z7nfHgh/9KGpbb51TMhj9lFQAAADwStI0yjNm\nRPtxx0XS35/Z1HX44bHo29+OdNy4nMLB2OCaVAAAAPBy+vqibcqUaPn+91fZ1DltWiz/zGcikiSH\nYDC2KKkAAABgDZLFi6P9ox+NprvvzszTlpZYfOml0bP//jklg7FHSQUAAACrUfjb36Ljwx+O4mOP\nZea1jTeOhdddF/177plTMhiblFQAAADwEsX774+Oww6LwvPPZ+aVHXeMhbNnR3WnnXJKBmOXC6cD\nAADASppuuy3G/du/rVJQ9e2xR8y/5RYFFQwTJRUAAABERKRptHzjG9H+sY9F0t2d2dS9//6x4Pvf\nj3TTTXMKB2Of0/0AAACgUonWadOifM01q2xadsIJsfTzn48oOM4DhpOSCgAAgMa2bFm0f/KT0fyL\nX2TGabEYS2bMiO7DD88pGDQWJRUAAAANK3nmmeg49NAoPfRQZl7r6IhFV10Vfe9+dz7BoAEpqQAA\nAGhIhUceiXEHHxyFuXMz8+qkSbFw9uyovO51OSWDxuSEWgAAABpO6Ve/ivHve98qBVX/5Mkx/yc/\nUVBBDpRUAAAANJTm2bOj4+CDI1m2LDPv2WefWHDzzVHbcsuckkFjU1IBAADQGGq1KJ97brRPmRJJ\npZLZtPxjH4tF3/xmpO3tOYUDXJMKAACAsa+rK9pPPDGab7opM06TJJaecUYs/9SnIpIkp3BAhJIK\nAACAMa7w5z9Hxyc+EcW//CUzT8vlWPz1r0fPfvvllAxYmdP9AAAAGJvSNJqvvz7G77PPKgVVddNN\nY8GNNyqooI44kgoAAICxZ9myaDv11Gj5/vdX2VR51ati4ezZUd1++xyCAWviSCoAAADGlOKf/hTj\n9957tQVV14c+FPN/9jMFFdQhR1IBAAAwNqRpNH/729E2bVokPT3ZTeVyLJk+PboPPtgF0qFOKakA\nAAAY/To7o/3kk1f59L6IiP5ddonFV10VlV12ySEYsLaUVAAAAIxqxYceivZPfCKKf/3rKtu6Djkk\nlpx7bkRbWw7JgHWhpAIAAGB0StNo+eY3o/X00yPp68tsqrW1ReeMGdH9oQ/lFA5YV0oqAAAARp/O\nzmg/8cRovuWWVTb177prLJo1K6qvfnUOwYD15dP9AAAAGFWKDz4Y49/1rtUWVMuPOCLm33abggpG\nIUdSAQAAMDqkabRceWW0nnlmJP39mU21jo5Y8pWvRM8BB+QUDthQSioAAADqXrJ4cbSdcEI0/+Qn\nq2zrnzx54PS+nXbKIRkwVJzuBwAAQF0r/uEPMe5d71ptQbX84x+P+bfcoqCCMcCRVAAAANSnWi1a\nvvGNaD3nnEgqleymceNiyUUXRc8HPpBTOGCoKakAAACoO8nChdF23HHR/MtfrrKtb/fdY/GsWVHd\nfvsckgHDxel+AAAA1JXivffG+H/+59UWVMs++clY8OMfK6hgDHIkFQAAAPWhvz/KX/1qlGfMiKRa\nzWyqbbRRLL7kkuh93/tyCgcMNyUVAAAAuSv+4Q/RdtJJUXrkkVW29b35zbH4iiuius02OSQDRoqS\nCgAAgPwsXRqt550XLVdfHUmarrJ52bHHxtLTTotoasohHDCSlFQAAADkounnP4+2U06Jwj/+scq2\n2sYbx+LLLoveffbJIRmQByUVAAAAIyqZNy/avvCFaL7lltVu7/rQh2LpmWdGbdNNRzgZkCclFQAA\nACOjVovm73wnWs86Kwqdnatsrmy/fSyZMSP63vWuHMIBeVNSAQAAMOwK//u/0T51apTuu2+VbWmx\nGMuPPTaWTp0a0daWQzqgHiipAAAAGD69vVG++OIoX3ppJP39q2zu2333WHLhhVGZPDmHcEA9UVIB\nAAAwLEq/+120TZ0axcceW2Vbra0tln7hC9F15JERxWIO6YB6o6QCAABgSCWLF0frWWdFy3e+s9rt\nPfvsE0umT4/aNtuMcDKgnimpAAAAGBppGk0/+lG0nXZaFJ57bpXN1c03j84vfzl6PvjBiCTJISBQ\nz5RUAAAAbLDk6aej7ZRTovmXv1zt9q7DD4/O00+PdMKEEU4GjBZKKgAAANZftRotV18dreedF8ny\n5atsruy8cyy58MLoe+tbcwgHjCZKKgAAANZLcc6caDvppCg9+OAq29Kmplh2/PGx7IQTIsrlHNIB\no42SCgAAgHWzfHm0XnhhtFx+eSTV6iqb+/bYI5ZceGFUdtklh3DAaKWkAgAAYO309UXL7NlRnjkz\nCs8+u8rm2rhxsfSLX4yuww+PKBRyCAiMZkoqAAAAXl6tFk033RSt06dH8cknV7tL9wc+EJ3nnBO1\nLbcc2WzAmKGkAgAAYPXSNEq33x6tX/5ylP70p9XuUp00KZZMnx69//IvIxwOGGuUVAAAAKyidM89\n0XrOOVG6777Vbk/L5Vj+iU/EsilTIh03boTTAWORkgoAAIBBxYcfjtYvfzmabr99tdvTUim6Djss\nlp10klP7gCGlpAIAACAKf/1rtJ5/fjT/8Idr3Kf7gANi6amnRnXHHUcwGdAolFQAAAANLHnmmWid\nOTOaZ8+OpFJZ7T49e+8dSz//+ahMnjzC6YBGoqQCAABoQMnixVG+7LJoueqqSLq7V7tP3x57ROe0\nadH/lreMcDqgESmpAAAAGsny5VG+6qpo+epXo7BkyWp36X/d62LpF74QvXvvHZEkIxwQaFRKKgAA\ngEbQ1xcts2dHeebMKDz77Gp3qWy/fSw99dToOeCAiEJhhAMCjU5JBQAAMJbVatH8wx9G+fzzo/jk\nk6vdpTpxYiybOjW6Dj00orl5ZPMBvEBJBQAAMBalaTT94hdRPvfcKD3yyGp3qW20USw77rjoOuqo\nSNvaRjggQJaSCgAAYCxZvjyab7ghyldeGcVHH13tLmm5HMuPPjqWHXdcpBMmjHBAgNVTUgEAAIwB\nhaeeipZrronm73xnjRdET0ul6Dr88Fh20klR22KLEU4I8PKUVAAAAKNVmkbpnnuiZdasaPrpTyOp\n1Va/W5JEzwEHxNJTT43qDjuMbEaAtaSkAgAAGG16eqL5ppui5corozRnzhp3S4vF6Nlvv1h24olR\n2W23EQwIsO6UVAAAAKNE8swz0fLNb0bLt78dhfnz17hfbeONo+sjH4nlH/1o1LbeegQTAqw/JRUA\nAECdK/7hD1G+8spo+vGPI6lU1rhf/2tfG8uPOiq6DzwworV1BBMCbDglFQAAQD3q74+mW26J8qxZ\nUbr//jXuliZJ9L73vbH8qKOi7x3viEiSEQwJMHSUVAAAAHUkmT8/Wr71rWi57rooPPPMGverjRsX\nXYceGl1HHhnV7bcfwYQAw0NJBQAAUAeKDz8cLbNmRfMPfxhJb+8a96vstNPAKX0f/nCk7e0jmBBg\neCmpAAAA8tLdHU2/+EW0XHttNP32ty+7a8+73x1dRx8dve9+d0ShMDL5AEaQkgoAAGAk9fVF6de/\njuabbormn/40kmXL1rhrrbU1uj/84Vj+iU9E9dWvHsGQACNPSQUAERH9/ZEsXhzJkiUD9y88Lqx4\nvGxZRKUycKtWI+nvH3wclcrAJy2t2LbS45duG1y/8DhWfEJTc3NEc3OkLS0v3jc1ZdcrzaOlJdLm\n5lXvX7pvW1ukG2304m3cOP/6DpCHajVKd98dzTfdFE233hqFxYtfdvfKtttG15FHRtehh0a60UYj\nFBIgX0oqAMaO3t5IFi16sWhauWRaqXhauYgqrJgtX553+hGTjhsXtRWl1fjxq5RYmfVL9xk/fqAk\nA+CV1WpR/P3vo/nmm6P5xz+OwnPPveJTet/+9lh+1FHR+973RhSLIxASoH4oqQAYPZYti8JTT0Xh\nqaei+Pe/Dzxecf/UU1F4/vm8E44KydKlUVy6NOLpp9fr+ekLR2fVNtkk0s03j9rEiZFuttnA/eab\nR22zzSKdODFqm28e6WabDRwlBtAo0jSKf/zjwKl8N98chblzX/Ep1S22iJ4PfjC6Dj44KrvtNgIh\nAeqTkgqA+tHZGcWVi6e//33g9vTTA/cLF+adkIhIuroi6ep62Y9FX1ltwoSB8mrzzdd8P3Fi1Dbb\nLKKjY5jTAwyPwp//PFhMFf/611fcv7bxxtH9gQ9Ez/77R99b3uKoKYBQUgEwkvr6ovjYY1F48slV\nC6i//z0KS5bkFi0tFAaODnrhlo4fH7UJEwZPi6u9cJpbWioN/EWiVIp0xf0GzKJUikjTiL6+SF64\nRW/vwOP+/hcfv9y8ry+S3t6B+YrHK+bLl0ehszMKS5ZE0tkZhZe5OO9wKSxeHLF4cRQfe+wV903b\n2qK2+eZRmzQp0kmTorbVVgO3lR6nW2zhlEOgLhSeeCKab745mm66KUqPPPKK+9c6OqLn/e+PngMO\niN699vJnGcBLKKkAGB6dnVF6+OEoPvRQFOfMGbj95S8DRcowSQuFgaN2XiiXBgumCROyBdTKj1cU\nUR0djXFB8Wo1kqVLo9DZOXDNrqVLB+47OwdKrBX3q5u9cJ/UasMWL+nqiuLf/hbFv/1tjfukSRLp\nFltkiqvapEmRrlxmTZoU0dY2bDmBxpXMnRvNP/pRNN98c5QeeOAV90/L5ejZd9/oPuCA6H3PeyLK\n5RFICTA6KakA2DBpGskzz0Tx4Yej9NBDA6XUww9H8cknh/6tSqWobr11VLfd9sX7bbeN6jbbDNxv\nueXAkUmsWbEY6YQJUZ0wYf2en6aRLF8eyeLFUVywIArz50fh+ecHbgsWRHGlx4Xnn4/CwoVDXmol\naRrJvHlRmDcv4sEH17hfbcKEgSOvXnIkVm2bbaK27bZR23rriNbWIc0GjEG12sD3uDvvjKaf/zya\n7rnnFZ+SNjVF73veE9377x+9731vpO3tIxAUYPTzkzwAa69ajcLjj0dxzpwozZkzWEgV5s8fkpdP\nm5sHyqcVpdML95UX7mtbbOGaHXlLkkg7OiLt6IjaNtu88v7VahQWLXqxyJo/P4oriq358wdLruIL\nj5O+viGLWnjh0xvjZU7BqW2++UBpteK27baZ+3STTSKSZMgyAaNAmkbhiSeidNdd0XTnnVH6zW/W\n6pqIabEYfXvtFd377x8973tfpOv7jwEADUxJBcDqdXdH8ZFHXiyk5syJ4iOPRNLVtUEvW500KSq7\n7BKVlY+CWlFCTZzYGKfcNZJiMWqbbTZwUfRdd335fdN04FTEZ5+N4rx5UZw3LwrPPBPFlW6FefOi\nOISf4riiPFvTEVlpW1vUtt56oLR6SYFV23bbgdMKHb0Ho17y3HMvllJ33RXFp55a6+f2vvWt0bP/\n/tHzr/868GcdAOvNT1UADOjsjKZ77onSr38dpbvvjuL//m8k1ep6v1xaKETlVa+KyuTJ0b/bboO3\ndNNNhzA0Y0qSRDp+fFTHj4/qq1+95v36+qL47LOZAqswb96Lj595JorPPhtJpbLhkbq6ovjYY2u8\n6HtaKAxc4H1F0brddgMF1nbbDZZZTimEOtTZGU2/+93AKXx33RXFP/95nZ7e98Y3Rs/++0f3Bz4Q\nta22GqaQAI1HSQXQqHp7o/SHP0Tp178e+AH9gQfWu5RKy+UXi6jJk6Oy227R/9rX+ss5w6O5efB6\nZGu8DH+tNnBq4YrSasXtH/+Iwty5UXz66SjOm7dBRWxERFKrRTJ3bhTmzo3SffetPsoWW2SKq+qK\nAuuFW7hWDQy/DfyeVxs/Pvre9rbo3Wuv6N1776jusMPwZQVoYEoqgEZRrQ6curfidIZ7742ku3vd\nX2aTTQaOjlpxhNTkyVHdaSfXiqK+FApRmzhx4BTS3Xdf/T6VysARWHPnDtyefvrF+xduhfX4f2SV\nKM8+G4Vnn424//7Vbq9tuumqR2Btt91AmbXNNhHjx29wBmg4tdrA97w771yv73lpS0v07bFH9O61\nV/TttVf0v+ENTu0FGAH+pAUYq9I0Cn/964s/oN99dxQWLVqnl6hsv/2LR0a9UErVttzShaQZG0ql\nwQumr/aIrDSNZNGibIH10jJrCD40oLBgQRQWLFjjdbFqEyZkr4P1kmtkpZtv7lpuNLzkuecGrp04\nZ06UHnxwnb/npUkS/bvvHn177TVQTO2xh6OBAXKgpAIYQ5J586LprrsGr7FRmDt3nZ5fedWroved\n7xz4Af1tb/PJRDS2JIl0k02isskmUXn961e/T3d3FP/xjxePvpo7N4pPPRWlp54aOBJr3rxIarUN\nijH4KYVz5qx2e9rS8mJxtbqLvG+1VURLywZlgLpRq0XhyScHP122tOJTZufNW+eXqrzqVQOn773z\nnb7nAdQJJRXAaNbZGU133z14Cl/xL39Zp6dXJ00a+OF8r72i9x3vGPikMmDttbZGdeedo7rzzqvf\n3t8/cC2sF0qrwfsVj//xjw2/LlZvbxT/+tco/vWvq92eJkmkK66L9dJPJ9xmm6htvfXAX84dIUm9\n6e2N4v/+7/9n787jbKz7P46/r7PMPvatG7ctRFHkTqKQpO1Od0Wpm0I/tBdlKRWy3AopUWSLW7Zu\nWqVbm0pJkmRJ3Ckp+zb7OWfOuX5/jDnmMoMZZs51zpnX8/HwmOv6XNec8z7u+xHec13fK3iFlPPH\nH+XauFFGWtoZvZy/WrXjf+a1acOfeQAQhiipACDCGHv3Kuadd+ReulSuNWuKdJVGoGxZeS+7LHi1\nlL9ePf5hCpQkt1v+Y+tLFSjPuliu33+3llnHbik0fCddHr5QDNOUsWdPzpUma9cWeI4ZH6/AOeco\n8Je/KHDOOTL/8pfgdnBWpQprz6HEGEePyrlxY/AKKeeGDXJu3XpWT+kM/pl3rJTyn3suf+YBQJij\npAKACGAcPiz3u+8qZulSub74otDFlBkXl7Pw6+WXy3v55fJdcAH/yATCSd51sVq2zH88EJBj717r\nelh518f64w85UlLOOoaRmXnKq7EkyXQ6ZVardry4ylNiBUutatW4tRCnZBw9KsfOnXL89pucW7Yc\nv0rqt9/O6nXNmBj5zjvv+BqKzZrJ16QJf+YBQIShpAKAcJWaqpgPPpB7yRK5P/mkUD9NNh0O+S66\nKOdWhssvl/fii6W4uBCEBVAiHI6cIuicc+Rr0aLAU4yUlPwLuuf56ti7V4ZpnnUUw++X8ccfp13r\nLlCp0vGrrypXVqBKFZmVKilQubLMKlUUqFRJZpUqMsuXZ8H3aHPsYQOOnTvl+P3341+PbTt37pSR\nmnrWbxMoWzb4MI/s3K/nniu53cXwIQAAdqKkAoBwkpkp93//q5glS+ResUJGVtZpv8XXoMHxUqpV\nK5k8rh4oVcwyZZRdpoyyGzUq+ASvN2ddrJMUWY49e+TIyCi2PI4DB+Q4cEDasOHUuZ3O4+VV5coF\nf80ttSpXpoAIB6Yp4+DBnPIp99euXcECyrFr1xmvF3Uy2dWrW54wm92kifzVq3PbHgBEKUoqALCb\n1yv3p5/KvWSJYj74oFB/wfedf74yO3dW1o03nnytGwCQpJgY+WvVkr9WrYKPm2bO1Vh79sixe3dO\noXXsl2PPnuPbhw8XayzD75exd68ce/cW6vxA+fI5pVaVKjIrVpRZtmzOrzJljm8f2w/kmSspiULj\nVDIzZRw5kvPr6FE5jh49vn/kiBz79lmuijIyM0skhul0Kvvcc+W74ILjpVTjxjIrVCiR9wMAhCdK\nKgCwg98v15df5lwx9e67OY+XP43sevWUedNNyrzxRvnr1w9BSAClgmHILFtW2WXLSg0bnvy8zEw5\n9+w5Xmb9+WfOfp4yy7FvX5Ee5lAUjsOHpcOH5dy2rUjfZzocBRZZllne7YQEKSZGZkyMFBtr/RoT\nIzM2Vjq2bfvtiqYpZWdLHo+Mo0dzSqY8BVPe8sk4Vj458s6OHJHh8YQ2cmys/NWry1+zprJr1z5+\ny17DhlJ8fEizAADCDyUVAIRKICDnmjWKWbpUMW+/Lce+faf9luyaNZXVubMyO3dWduPGXA0AwD7x\n8fLXqSN/nTonPyc7W459+3Kuvtq7V479+4O3/zn275czz7ajGNYmKgwjEJBx5IhUiB8GFJXpducU\nWLlfTyi25HYHSy0zJibnqrXs7Jxiye+XsrML3j+2rexsGXm3TzxWQoXg2TDj4pRds6b8NWvKX6NG\nzq/c7Zo1FahUyf5yDwAQtiipAKAkmaacP/ygmCVLFLN06WkXHJYkf9WqyrzxRmXdeKN8zZtTTAGI\nHC5X8Ml/vtOdm5Ulx4EDch48mFNa5Sm0nCeUW45Dh4pl8ffiZvh8ks+n0vRf6UBi4kkLKH/NmgpU\nqMCfWwCAM0ZJBQAlISNDMYsWKW7aNDl/+um0pwfKl1fmDTcoq3NneVu25JHZAKJfXJwCNWooUKPG\n6c/1++U4dOh4mXXkiBwpKTm3t6WmykhJyVlLKSUlZ5779ehROUpoDaVoYbrdwTW8AuXK5WyXLatA\n2bIKlCsns3x5+WvUUPaxUsosX54SCgBQYiipAKAYGbt2KW76dMXMmXPadaYCycnKuvZaZXXuLE+b\nNjy5CgBOxulU4NgT/4rM5wuWVpZi6+hRa6GVW3RlZsrwenO+z+PJ2fZ6LV9zf4UD0+XKuYKtbFkF\njq2tVWDZlHv82LFA2bIyy5WTGR9P6QQACBuUVABwtkxTrtWrFfvqq3K///4p1wgx4+KUdfXVyuzc\nWZ727aW4uBAGBYBSyO2WWbGi/BUryl+cr2uaJy+vcsutPEWX4fXKdDgklyunWHI6c7ZzvxYwsxwv\nYCaHg4IJABBVKKkA4Ex5PIpZskSxU6fKtWHDSU8znU55OnRQ5k03ydOxo8zExBCGBACUCMPIWSQ9\nNlaSFH4rZgEAEHkoqQCgiIw9exQ7c6ZiX39djv37T3peoHx5Zdx5p9LvukuB6tVDmBAAAAAAIg8l\nFQAUknPdOsVOnaqYt97KeaLTSfgaNlT6Pfco8x//kBISQpgQAAAAACIXJRUAnIrPJ/c77yhu2jS5\nvv32pKeZhiFPx45Kv+ceeVu3Zo0QAAAAACgiSioAKIBx8KBiX39dsTNmyLF790nPCyQnK+P225XR\ns6f8tWuHLiAAAAAARBlKKgDIw7lpk2JffVUxb74pw+M56XnZdesqvVcvZXbtKjMpKYQJAQAAACA6\nUVIBgN8v9/Llip06Ve4vvzzlqZ62bZV+zz3ytG+f8+hvAAAAAECxoKQCUHqZptzvvaf4UaPk/Pnn\nk54WiI9XZteuyujVS9n164cwIAAAAACUHpRUAEol1+efK37ECLnWrTvpOdk1aiijZ09ldOsms1y5\nEKYDAAAAgNKHkgpAqeJct07xzz4r98qVJz3H06qVMnr3VtbVV0su/jMJAAAAAKHAv74AlAqOn39W\n/KhRinn33QKPmw6HMm++Wel9+ij7ggtCnA4AAAAAQEkFIKoZu3YpfuxYxcyfLyMQKPCcrGuvVeqg\nQcpu0CDE6QAAAAAAuSipAEQl48ABxU2YoNiZM2V4vQWe42ndWqlDhsjXvHmI0wEAAAAATkRJBSC6\npKYqbsoUxU2eLCMtrcBTvE2bKnXIEHmvuEIyjBAHBAAAAAAUhJIKQHTIylLsrFmKmzBBjoMHCzwl\nu149pQ4apKzrr6ecAgAAAIAwQ0kFILJlZytmwQLFjx0rxx9/FHiK/5xzlDpggDK7duVpfQAAAAAQ\npvjXGoDIZJpyv/uu4keNknPbtgJPCZQvr7SHHlL6XXdJcXEhDggAAAAAKApKKgARx/XZZ4ofOVKu\ndesKPB5ITFR6375K79tXZnJyiNMBAAAAAM4EJRWAiOFct07xzz4r98qVBR43Y2KU0aOH0h56SIFK\nlUKcDgAAAABwNiipAIQ948ABxT/1lGIXLizwuOlwKLNLF6UNGCB/jRohTgcAAAAAKA6UVADCl2kq\nZuFCxQ8dKsehQwWeknnddUobOFDZDRqEOBwAAAAAoDhRUgEIS44dO5TQv/9Jb+3ztGmj1CFD5GvW\nLMTJAAAAAAAlgZIKQHjx+RQ7ZYrix46VkZWV//B55yll2DB5r7jChnAAAAAAgJJCSQUgbDi/+04J\njzwi16ZN+Y6ZsbFK7d9f6f36SW63DekAAAAAACWJkgqA/VJTFT96tGKnTZNhmvkOe9q00dF//Uv+\nunVtCAcAAAAACAVKKgC2cn/4oRIee0yOP/7IdyxQvrxSnnlGmV26SIZhQzoAAAAAQKhQUgGwhbFn\njxKGDFHM228XeDzz5puVMmyYApUqhTgZAAAAAMAOlFQAQisQUMzcuYp/5hk5UlLyHc6uWVNHx46V\nt6HRuskAACAASURBVF270GcDAAAAANiGkgpAyDh+/lkJjz4q99df5ztmOp1K79NHaQMGyExIsCEd\nAAAAAMBOlFQASp7Ho7iJExX3wgsyvN58h71Nm+ro888ru0kTG8IBAAAAAMIBJRWAEuX6+mslPPKI\nnNu25TsWSEhQ6qBByujZU3LxnyMAAAAAKM34VyGAEmEcPar4YcMU+/rrBR7PuvJKpfzrX/LXqBHi\nZAAAAACAcERJBaB4mabc77yjhMGD5di7N99hf6VKSnn2WWXdeKNkGDYEBAAAAACEI0oqAMXG2LtX\nCY8+qpjlyws8nnHHHUp58kmZ5cuHOBkAAAAAINxRUgEoFq7PPlNi375y7N+f71h23bo6+vzz8rZq\nZUMyAAAAAEAkoKQCcHaysxU3dqziJkyQYZqWQ6bbrbT771faQw9JcXE2BQQAAAAARAJKKgBnzPjz\nTyX26SP3V1/lO+a9+GIdHTdO2Q0b2pAMAAAAABBpKKkAnBHXRx8p8d575Th40DI3DUNp/fsr7ZFH\nJKfTpnQAAAAAgEhDSQWgaHw+xY8erbgXX8x3yF+lio5Mnixv69Y2BAMAAAAARDJKKgCFZuzapaR7\n7pFrzZp8xzxXXKEjkyYpULmyDckAAAAAAJHOYXcAAJHBvXy5yrRtm6+gChiGDvbvr0NvvEFBBQAA\nAAA4Y1xJBeDUvF7FjxihuClT8h0KnHOOFnburL/de68SHXTeAAAAAIAzx78qAZyUY+dOJV93XYEF\nle+qq5SycqV21a1rQzIAAAAAQLShpAJQIPd77ym5bVu51q2zzE2nUxnDhiltwQKZlSrZlA4AAAAA\nEG243Q+Alcej+GeeUdy0afkOBapXV9r06fK3bGlDMAAAAABANKOkAhDk2LFDib17y7V+fb5j3muu\nUcbLL8usUMGGZAAAAACAaMftfgAkSe633lKZdu3yFVSmy6WMkSOVPm8eBRUAAAAAoMRwJRVQ2mVl\nKX7oUMXNnJnvkP+vf1X6jBnyX3yxDcEAAAAAAKUJJRVQijm2b1dir15ybdyY75j3hhuUMWmSzLJl\nbUgGAAAAAChtuN0PKKXcb76pMldema+gMmNilPGvfyn99dcpqAAAAAAAIcOVVEBp4/EoYdAgxc6Z\nk++Qv3Ztpc+cKf9FF9kQDAAAAABQmlFSAaWIceiQErt3l/vrr/Md8950k9InTpTKlLEhGQAAAACg\ntKOkAkoJx44dSrrtNjm3b7fMzdhYZYweLe/dd0uGYU84AAAAAECpR0kFlALONWuUdOedchw8aJn7\n69ZV+qxZ8jdpYlMyAAAAAABysHA6EOXcb72l5M6d8xVUvlatlLpiBQUVAAAAACAsUFIB0co0FfvS\nS0rq1UuGx2M55Ln1VqUtWSKzfHmbwgEAAAAAYMXtfkA0ys5WwsCBip09O9+hzMceU9aQIaw/BQAA\nAAAIK5RUQLRJTVVSr15yf/yxZWy6XMp44QV577zTpmAAAAAAAJwcJRUQRYw//lBSt25ybdxomZvJ\nyUqbM0fZbdvalAwAAAAAgFOjpAKihPPHH5V0++1y7N5tmftr1FDawoUKNGpkUzIAAAAAAE6PhdOB\nKOBasULJ11+fr6DKbtZMqStWUFABAAAAAMIeJRUQ4WJmz1bSHXfISEuzzL3XXqvUd96RWbWqTckA\nAAAAACg8SiogUgUCih82TIn9+8vw+y2Hsvr0UfqcOVJiok3hAAAAAAAoGtakAiJRZqYS77tPMW+/\nbRmbhqHMUaPk6dfPpmAAAAAAAJwZSiogwhgHDijpzjvl+vZby9yMj1f6a6/Jd911NiUDAAAAAODM\nUVIBEcSxbZuSbrtNzl9/tcwDVaoo7Y035G/e3J5gAAAAAACcJUoqIEK4vvpKif/8pxxHjljm/oYN\nlbZwoQJ//atNyQAAAAAAOHssnA5EAPebbyrp5pvzFVS+K65Q6vLlFFQAAAAAgIhHSQWEM9NU3Lhx\nSurTR4bXaznk6dZNaYsWySxb1qZwAAAAAAAUH273A8KVz6eE/v0VO29evkOZQ4Yo67HHJMOwIRgA\nAAAAAMWPkgoIR+npSureXe7PPrOMTbdbGZMmydu1qz25AAAAAAAoIZRUQLhJT1fS7bfLvWqVZRwo\nV07pc+cqu3Vrm4IBAAAAAFByKKmAcJKWllNQffWVZeyvVSvnCX4NGtgUDAAAAACAkkVJBYSL1FQl\n3Xab3KtXW8bZTZoo7c03ZVaubFMwAAAAAABKHiUVEA5SU5Xctatc33xjGWdfeKHSliyRWb68TcEA\nAAAAAAgNh90BgFIvJUXJXbrkL6guukhpS5dSUAEAAAAASgWupALslJKi5FtvlWvtWss4u3lzpf3n\nPzLLlrUpGAAAAAAAoUVJBdglJUXJt9wi13ffWcYUVAAAAACA0oiSCrCBcfSokm65Ra516yzz7Isv\nVup//iOVKWNTMgAAAAAA7MGaVECIGUeOKOnmm/MXVC1aUFABAAAAAEotSioghIIF1fffW+bZf/ub\nUt98k4IKAAAAAFBqUVIBIWIcPqykf/xDrvXrLfPsli0pqAAAAAAApR5rUgEhECyoNmywzH2XXqq0\nhQul5GSbkgEAAAAAEB64kgooYcahQ0q66ab8BVWrVkpbtIiCCgAAAAAAUVIBJco4eDCnoPrxR8vc\n17p1zhVUSUk2JQMAAAAAILxwux9QQowDB3IKqs2bLXNfmzZKmz9fSky0KRkAAAAAAOGHK6mAEmDs\n36/kzp3zF1RXXKG0BQsoqAAAAAAAOAElFVDMcgsq55YtlrmvbVulvfGGlJBgUzIAAAAAAMIXJRVQ\njIx9+5R8441y/vSTZe5r146CCgAAAACAU6CkAoqJsXdvTkG1datl7mvfXmnz5knx8TYlAwAAAAAg\n/FFSAcXA2LMnp6D6+WfL3NehAwUVAAAAAACFQEkFnCVjz56cNai2bbPMfVddpbS5c6W4OJuSAQAA\nAAAQOSipgLNg7N6dcwXVCQWV9+qrKagAAAAAACgCSirgDBmHDin5ppvk3L7dMvd26qT011+XYmNt\nSgYAAAAAQOShpALORGamkrp1y38F1bXXKn32bAoqAAAAAACKiJIKKCq/X4l9+sj17beWsfe665Q+\naxYFFQAAAAAAZ4CSCigK01T8kCGKef99y9jXpo3SZ8yQYmJsCgYAAAAAQGSjpAKKIPallxQ3fbpl\n5m/USOlz53IFFQAAAAAAZ4GSCiikmMWLlTB8uGUWOOccpS5cKLNsWZtSAQAAAAAQHSipgEJwrVyp\nhAcesMzM5GSlLl4ss0YNm1IBAAAAABA9KKmA03Bu2qSkHj1k+HzBmRkTo7R//1uBxo1tTAYAAAAA\nQPSgpAJOwdi1S0ldu8pITbXM0ydPVvbll9uUCgAAAACA6ENJBZyEceSIkrt0kWP3bss8Y/hw+W65\nxaZUAAAAAABEJ0oqoCBZWUr85z/l3LrVOu7TR54T1qYCAAAAAABnj5IKOFEgoMT77pP7q68sY+/f\n/67MUaMkw7ApGAAAAAAA0YuSCjhB/FNPKeattywz36WXKn3qVMnptCkVAAAAAADRjZIKyCN2yhTF\nvfKKZeZv0EDp8+ZJcXE2pQIAAAAAIPpRUgHHuJcuVcLQoZZZoFo1pS1eLLN8eZtSAQAAAABQOlBS\nAZJcq1Yp8d57LTMzKUlpCxcqULOmTakAAAAAACg9KKlQ6jm2bFHiP/8pw+sNzkyXS2mvvy5/kyY2\nJgMAlEbjxo1Tu3btVL16dVWvXl39+/e3OxIAAEBIUFKhVDP+/FPJXbrIcfSoZZ4xaZKy27e3KRUA\noDR77LHH9Nlnn+nSSy+VpOBXAACAaEdJhdIrJUVJXbvK8eeflnHmU0/Je9ttNoUCACDH1q1bZRgG\nJRUAACg1KKlQOnm9SurRQ67Nmy3jrF69lPXIIzaFAgAgx7Zt23T48GFVq1ZNf/3rX+2OAwAAEBKU\nVCh9AgElPPCA3J9/bhl7r7tOmWPHSoZhUzAAAHKsWbNGktSyZUubkwAAAIQOJRVKnfgRIxT75puW\nWXaLFkqfNk1yOm1KBQDAcbklFbf6AQCA0oSSCqVK7GuvKe6llywzf716Sps/X0pIsCkVAABWa9as\nYT0qAABQ6rjsDgCEivvddxU/eLBlFqhcWWmLF8usWNGmVAAAWO3du1c7d+5UxYoV5XQ61bdvX/35\n5586evSorrzySg0ePFhxcXF2xwQAACh2lFQoFZyrVyuxb18ZphmcmYmJSlu4UIHate0LBgDACb75\n5htJUmxsrAYNGqSxY8eqbt262r9/v9q3b6+dO3dq5syZNqcEAAAoftzuh6jn+PlnJd15p4ysrODM\ndDqVNnOm/BddZGMyAEBps3DhQrVp00b16tXTVVddpVmzZsnM8wMU6fh6VGXLltWsWbNUt25dSVLl\nypV1zTXX6MMPP9R3330X8uwAAAAljZIKUc04elRJd9whx+HDlnnGxInK7tjRplQAgNJo0qRJ6t+/\nv5o2bar169dr5MiRWrRokXr27KlAIBA8L7ekev7555WUlGR5jQoVKkiSPv3009AFBwAACBFKKkSv\nQEAJ994r5y+/WMaZgwfLe+edNoUCAJRG3333ncaOHauEhASNGjVKycnJ+uqrr7Rjxw6tWLFCCxcu\nlCSlpaVpy5YtKlu2rJo1a5bvdQ4ePChJOnDgQEjzAwAAhAIlFaJW3Pjxilm+3DLz3HGHsh5/3KZE\nAIDSyOfzacCAATJNU//4xz9Uvnx57dixQ+PHj1dqaqqk41dGrV27VoFAQC1atCjwtX766SdJUpky\nZUITHgAAIIQoqRCVXCtWKO5f/7LMsps3V8a4cZJh2JQKAFAaLVmyRNu2bZNhGLr11lslSX6/33KO\ny5XzLJvvv/9ektSyZct8r5OVlaXNmzdLkho3blySkQEAAGxBSYWo4/j1VyX26WN5kl+gYkWlzZ4t\n8chuAEAImaapKVOmSJKqV6+uSy65RJJ07rnn6uGHH1ZycrIaNWqk/v37S5J27NghSWrevHm+11q9\nerW8Xq9iY2PVtm3bEH0CAACA0HHZHQAoVhkZSuzRQ46jR4Mj0+FQ+owZMmvUsDEYAKA0WrlypbZv\n3y5J6tChg+XYwIEDNXDgQMssd62pBg0a5HutDz74QJL097//XeXLly+JuAAAALbiSipED9NUQv/+\ncm3caBlnPv20sq+4wqZQAIDSbMGCBcHtE0uqgpxzzjmSpLJly1rmKSkpeuutt5SYmKjHWVsRAABE\nKUoqRI3Y6dMVu2iRZea98UZ5HnzQpkQAgNIsNTVV//3vfyVJMTExuuyyy077Pa1bt5Yk7dy50zIf\nMWKE0tLSNHr0aNXgymAAABClKKkQFZyrVyv+ySctM3+DBkqfNImF0gEAtvjoo4/k8XgkSU2bNlV8\nfPxpv6dz586qV6+eXnvtNUlSIBDQ888/r8WLF2v06NHBhdcBAACiEWtSIeIZe/YoqWdPGdnZwZmZ\nlKS0uXOl5GQbkwEASrPcq6gkFeoqKklyOp164403NGTIEHXo0EEOh0P16tXTsmXLdP7555dUVAAA\ngLBASYXI5vUqqWdPOfbutYzTX3lFgfr1bQoFACjtTNPU559/HtzPfapfYdSoUUNz584tiVgAAABh\njdv9ENHin35arm++scwy+/eX7/rrbUoEAIC0ceNGHTlyRJLkcDh08cUX25wIAAAg/FFSIWLFLFqk\nuGnTLDNf+/bKGjLEpkQAAOT44osvgtt16tRRmTJlbEwDAAAQGSipEJGcP/6ohEcftcz8NWsq/bXX\nJKfTplQAAOT48ssvg9sXXnihjUkAAAAiByUVIo5x+LASe/SQkZkZnJlxcUqfM0dmhQo2JgMAQPJ6\nvfomz63oTZs2tTENAABA5KCkQmTx+5XYp4+cv/1mGWeMHy8/P6kGAISBdevWKSsrK7hPSQUAAFA4\nlFSIKHFjx8r98ceWWVavXvJ262ZTIgAArFatWhXcdjgcuuCCC2xMAwAAEDkoqRAx3MuXK37cOMss\nu0ULZY4ebVMiAADy+/rrr4PbtWrVUmJioo1pAAAAIgclFSKC43//U2LfvpZZoHJlpc2eLcXE2BMK\nAIATeL1erVu3LrjfpEkTG9MAAABEFkoqhL+0NCX16CEjNTU4Mp1Opc+aJfMvf7ExGAAAVt9//708\nHk9wn5IKAACg8CipEN5MU4kPPyznli2WceaIEcq+7DKbQgEAULC8T/WTKKkAAACKgpIKYS32lVcU\ns3SpZea95RZ5+vWzKREAACe3evXq4LZhGDr//PNtTAMAABBZKKkQtlxffqn4Z56xzLIbN1b6xImS\nYdiUCgCAgvn9fq1duza4X7VqVVWoUMHGRAAAAJGFkgphyfjjDyX27i3D7w/OAmXKKH3OHImnJAEA\nwtDGjRuVnp4e3G/cuLGNaQAAACIPJRXCj8ejpLvvlmP/fss4Y+pUBerWtSkUAACn9u2331r2zzvv\nPJuSAAAARCZKKoSdhCeekOu77yyzzIED5evUyaZEAACc3po1ayz7jRo1sikJAABAZKKkQliJmTdP\nsbNmWWa+jh2VNXCgTYkAACic7074AQtXUgEAABQNJRXChnP9eiU89phl5q9dW+lTp0oO/q8KAAhf\nu3bt0p49e4L7LpdL5557ro2JwsfWrVt16aWXavv27SF7z0ceeUTDhw8P2fsBAIDiwb/8ERaMgweV\n2KOHDI8nODPj45U+d67McuVsTAYAwOmdeKtf7dq1FRMTY1Oa8LFmzRrdfPPNuv/++0Na2o0YMUKf\nf/65Bg4cKNM0S/S9AoGADh8+rB07duj777/Xp59+qszMzBJ9TwAAopXL7gCATFMJDz4o565dlnHG\nxInyn3++TaEAACi8aL/Vz+PxaMaMGVq4cKF+//13Va5cWddff70GDBigxJM8dffnn39W9+7d1bNn\nT3Xv3j2kecuUKaN58+apU6dO8ng8evHFF0vkfa677jr9+OOPCgQClvk333yjGjVqlMh7AgAQzbiS\nCraLef11xSxfbpll9e0rb5cuNiUCAKBoTnyyXzQtmp6amqquXbtq1KhR6tKli7799ls9+OCDmj17\n9knLp0OHDunuu+9WgwYNNGjQoBAnzlGtWjVNmDBBb775pl5//fUSeY9bbrlFvXv3tlwlZhhGibwX\nAAClASUVbOXYvl0JQ4daZtktWihzxAibEgEAUDQZGRnasmWLZRZNV1INGjRIa9euVfv27fXAAw9o\n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\nACFkA6eYdyQ3AAAAAElFTkSuQmCC\n",
428 "text": [
450 "text": [
429 "<matplotlib.figure.Figure at 0x110035290>"
451 "<matplotlib.figure.Figure at 0x1078d7e10>"
430 ]
452 ]
431 }
453 }
432 ],
454 ],
433 "prompt_number": 3
455 "prompt_number": 3
434 }
456 }
435 ],
457 ],
436 "metadata": {}
458 "metadata": {}
437 }
459 }
438 ]
460 ]
439 }
461 } No newline at end of file
@@ -1,208 +1,230 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": ""
3 "name": ""
4 },
4 },
5 "nbformat": 3,
5 "nbformat": 3,
6 "nbformat_minor": 0,
6 "nbformat_minor": 0,
7 "worksheets": [
7 "worksheets": [
8 {
8 {
9 "cells": [
9 "cells": [
10 {
10 {
11 "cell_type": "heading",
11 "cell_type": "heading",
12 "level": 1,
12 "level": 1,
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "Plotting with Matplotlib"
15 "Plotting with Matplotlib"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "markdown",
19 "cell_type": "markdown",
20 "metadata": {},
20 "metadata": {},
21 "source": [
21 "source": [
22 "IPython works with the [Matplotlib](http://matplotlib.org/) plotting library, which integrates Matplotlib with IPython's display system and event loop handling."
22 "IPython works with the [Matplotlib](http://matplotlib.org/) plotting library, which integrates Matplotlib with IPython's display system and event loop handling."
23 ]
23 ]
24 },
24 },
25 {
25 {
26 "cell_type": "heading",
26 "cell_type": "heading",
27 "level": 2,
27 "level": 2,
28 "metadata": {},
28 "metadata": {},
29 "source": [
29 "source": [
30 "matplotlib mode"
30 "matplotlib mode"
31 ]
31 ]
32 },
32 },
33 {
33 {
34 "cell_type": "markdown",
34 "cell_type": "markdown",
35 "metadata": {},
35 "metadata": {},
36 "source": [
36 "source": [
37 "To make plots using Matplotlib, you must first enable IPython's matplotlib mode.\n",
37 "To make plots using Matplotlib, you must first enable IPython's matplotlib mode.\n",
38 "\n",
38 "\n",
39 "To do this, run the `%matplotlib` magic command to enable plotting in the current Notebook.\n",
39 "To do this, run the `%matplotlib` magic command to enable plotting in the current Notebook.\n",
40 "\n",
40 "\n",
41 "This magic takes an optional argument that specifies which Matplotlib backend should be used. Most of the time, in the Notebook, you will want to use the `inline` backend, which will embed plots inside the Notebook:"
41 "This magic takes an optional argument that specifies which Matplotlib backend should be used. Most of the time, in the Notebook, you will want to use the `inline` backend, which will embed plots inside the Notebook:"
42 ]
42 ]
43 },
43 },
44 {
44 {
45 "cell_type": "code",
45 "cell_type": "code",
46 "collapsed": false,
46 "collapsed": false,
47 "input": [
47 "input": [
48 "%matplotlib inline"
48 "%matplotlib inline"
49 ],
49 ],
50 "language": "python",
50 "language": "python",
51 "metadata": {},
51 "metadata": {},
52 "outputs": [],
52 "outputs": [],
53 "prompt_number": 1
53 "prompt_number": 1
54 },
54 },
55 {
55 {
56 "cell_type": "markdown",
56 "cell_type": "markdown",
57 "metadata": {},
57 "metadata": {},
58 "source": [
58 "source": [
59 "You can also use Matplotlib GUI backends in the Notebook, such as the Qt backend (`%matplotlib qt`). This will use Matplotlib's interactive Qt UI in a floating window to the side of your browser. Of course, this only works if your browser is running on the same system as the Notebook Server. You can always call the `display` function to paste figures into the Notebook document."
59 "You can also use Matplotlib GUI backends in the Notebook, such as the Qt backend (`%matplotlib qt`). This will use Matplotlib's interactive Qt UI in a floating window to the side of your browser. Of course, this only works if your browser is running on the same system as the Notebook Server. You can always call the `display` function to paste figures into the Notebook document."
60 ]
60 ]
61 },
61 },
62 {
62 {
63 "cell_type": "heading",
63 "cell_type": "heading",
64 "level": 2,
64 "level": 2,
65 "metadata": {},
65 "metadata": {},
66 "source": [
66 "source": [
67 "Making a simple plot"
67 "Making a simple plot"
68 ]
68 ]
69 },
69 },
70 {
70 {
71 "cell_type": "markdown",
71 "cell_type": "markdown",
72 "metadata": {},
72 "metadata": {},
73 "source": [
73 "source": [
74 "With matplotlib enabled, plotting should just work."
74 "With matplotlib enabled, plotting should just work."
75 ]
75 ]
76 },
76 },
77 {
77 {
78 "cell_type": "code",
78 "cell_type": "code",
79 "collapsed": false,
79 "collapsed": false,
80 "input": [
80 "input": [
81 "import matplotlib.pyplot as plt\n",
81 "import matplotlib.pyplot as plt\n",
82 "import numpy as np"
82 "import numpy as np"
83 ],
83 ],
84 "language": "python",
84 "language": "python",
85 "metadata": {},
85 "metadata": {},
86 "outputs": [],
86 "outputs": [],
87 "prompt_number": 2
87 "prompt_number": 2
88 },
88 },
89 {
89 {
90 "cell_type": "code",
90 "cell_type": "code",
91 "collapsed": false,
91 "collapsed": false,
92 "input": [
92 "input": [
93 "x = np.linspace(0, 3*np.pi, 500)\n",
93 "x = np.linspace(0, 3*np.pi, 500)\n",
94 "plt.plot(x, np.sin(x**2))\n",
94 "plt.plot(x, np.sin(x**2))\n",
95 "plt.title('A simple chirp');"
95 "plt.title('A simple chirp');"
96 ],
96 ],
97 "language": "python",
97 "language": "python",
98 "metadata": {},
98 "metadata": {},
99 "outputs": [
99 "outputs": [
100 {
100 {
101 "metadata": {},
101 "metadata": {},
102 "output_type": "display_data",
102 "output_type": "display_data",
103 "png": "iVBORw0KGgoAAAANSUhEUgAAAl0AAAGKCAYAAAA2UfQhAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsvXmUJFd9NXgjIveqrK7qTb1ILam1I7TQAskY05JowDay\nEAIf20KWJY3N2HMY4Bx/NsIsGj708eFlPN8I22AdzoBAFmZYxrYYYwSSQAhJg0A7uLWh3tSt3mvL\nyiXW+SMqqjOzIjLivfd7EZFZ757DOfQW71VWqfLWvfd3f5rneR4UFBQUFBQUFBSkQs/6AgoKCgoK\nCgoKKwGKdCkoKCgoKCgopABFuhQUFBQUFBQUUoAiXQoKCgoKCgoKKUCRLgUFBQUFBQWFFKBIl4KC\ngoKCgoJCClCkS0FBYaRxxRVX4MEHH5T2/DvvvBM333yztOcrKCiMDhTpUlBQSIR//dd/ha7rePzx\nx4Wf9fu///u44447CG4VD03ToGma1OfH4d///d9x+eWXS7uDgoLCcECRLgUFhUT4/Oc/j02bNuEf\n//EfhZ/1T//0T/jjP/5jglsNB6666iqpapuCgsJwQJEuBQWFWLz88st48MEH8ZWvfAVf+9rXMDc3\nl/WVFBQUFIYOinQpKCjE4o477sBv/MZv4C1veQvOPvtsfOUrX8n6SgoKCgpDB0W6FBQUBsI0Tdx5\n55248cYbAQA33nhjojzWCy+8gLe97W2o1+vYsmULbr/99qU/u+mmm/DlL38ZAPDiiy9C13U8+uij\neMMb3oBarYYdO3Zg//79uOeee3Duuedi1apVuOqqq3DgwIGeZ3zhC1/AX/7lX+KMM85AtVrFtm3b\n8J3vfCf24/nYxz6GTZs2oVar4corr8QzzzwT+/HccccdOOecc1CpVHD++efjq1/9as+ff/7zn8fp\np5+OyclJXH311T13/eEPf4grr7yy5+5/8zd/gz/5kz/B5OQkPvrRj+LLX/4ybrjhBvzbv/0bLrnk\nElSrVWzduhV/+7d/C9d1Y++noKCQfyjSpaCgMBDf/OY34bourr76agDAddddh+effx4//vGPB/67\n66+/Htu3b8fhw4dx11134a677lqyJbvD7cViEQDw53/+5/jiF7+IAwcOYOvWrXj3u9+Nv/qrv8L3\nv/997N69G5s2bcKHPvShpedrmoZPf/rTeOqpp/Cd73wHR44cwSc/+Un80R/9Ef7+7/8+8l7vec97\nMD09jUcffRRHjx7Fn/7pn+Id73gHdu3aFflvPvKRj+D222/HF77wBUxPT+Mf/uEf8NnPfhYzMzPw\nPA/f/e538cgjj+CRRx7Bc889h1Kp1HPXMNx+++3YsGEDDhw4gE996lMAgB/96Ee47bbb8NnPfhZH\njx7F17/+dXzzm9/E7/zO7wx8loKCwpDAU1BQUBiAN7/5zd4HP/jBnt975zvf6b33ve8d+O9Wr17t\nff/73w/9s5tuusm78847Pc/zvF27dnmapnnf+973lv587969nqZp3iOPPNLze2vXrl369Y033ui9\n6U1vWvbse++911u1apXX6XQ8z/O8K664wnvwwQc9z/O87373u94VV1yx7N/cdttt3gc+8IHQu+7Z\ns8erVCre888/H/rnX/rSl7yTTz7Zsyxr6feee+65nrv+4Ac/6Dn3xhtvXHaPL33pS97k5KR36NCh\nnt8/fPiwt2rVqp7XQkFBYTihlC4FBYVI/OIXv8CPf/xj/MEf/EHP799www341re+hWPHjkX+21tu\nuQXvfOc78a53vQu33347Dh06NPCsN77xjUv/f/PmzQCAbdu29fxe93mapuF3f/d3lz3nbW97GxzH\nwdNPP73szx566CE8+OCD0HW953+33nordu7cGXqvn/zkJzjttNNw9tlnD7x7oVBY+vXWrVsHvjaa\npuFXfuVXlv3+W97yFqxfv77n99atW4c3velNeOihhyKfp6CgMBxQpEtBQSESQT3EFVdcgXq9vvS/\nm266CaZp4otf/GLkv/3whz+MZ599Fm9729twzz334Pzzzx9o4dVqtaX/r+v+t6Zyubzs97rheR7T\nx6PrOt797nfDdd1l//v+978f+e8GdXFpmoaxsbGe3wss00HoJmkBoj4ez/Okdo0pKCikA0W6FBQU\nQtFsNnHXXXfhM5/5DJ5++ull//vABz4wMFBv2zbOOOMMvP/978f999+PSy65BP/yL/9Cdj/P8/CN\nb3xj2e/fd999MAwDF1100bI/u/zyy3HffffhyJEjPb//i1/8IjKsftlll2H37t148cUXaS4+AD/8\n4Q9x+PDhnt87evQoHn30Ubz5zW+Wfr6CgoJcKNKloKAQiq9+9avQdR0f/OAHsXXr1p7/nXHGGfjw\nhz+MvXv34nvf+96yfzs9PY0zzjgD3/rWt9DpdPDEE0/g2WefxVlnnUV6x3379uG9730vnn/+eczN\n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\nJgeMshD/dgAAAABJRU5ErkJggg==\n",
103 "png": "iVBORw0KGgoAAAANSUhEUgAAAl0AAAGKCAYAAAA2UfQhAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsvXmUJFd9NXgjIveqrK7qTb1ILam1I7TQAskY05JowDay\nEAIf20KWJY3N2HMY4Bx/NsIsGj708eFlPN8I22AdzoBAFmZYxrYYYwSSQAhJg0A7uLWh3tSt3mvL\nyiXW+SMqqjOzIjLivfd7EZFZ757DOfQW71VWqfLWvfd3f5rneR4UFBQUFBQUFBSkQs/6AgoKCgoK\nCgoKKwGKdCkoKCgoKCgopABFuhQUFBQUFBQUUoAiXQoKCgoKCgoKKUCRLgUFBQUFBQWFFKBIl4KC\ngoKCgoJCClCkS0FBYaRxxRVX4MEHH5T2/DvvvBM333yztOcrKCiMDhTpUlBQSIR//dd/ha7rePzx\nx4Wf9fu///u44447CG4VD03ToGma1OfH4d///d9x+eWXS7uDgoLCcECRLgUFhUT4/Oc/j02bNuEf\n//EfhZ/1T//0T/jjP/5jglsNB6666iqpapuCgsJwQJEuBQWFWLz88st48MEH8ZWvfAVf+9rXMDc3\nl/WVFBQUFIYOinQpKCjE4o477sBv/MZv4C1veQvOPvtsfOUrX8n6SgoKCgpDB0W6FBQUBsI0Tdx5\n55248cYbAQA33nhjojzWCy+8gLe97W2o1+vYsmULbr/99qU/u+mmm/DlL38ZAPDiiy9C13U8+uij\neMMb3oBarYYdO3Zg//79uOeee3Duuedi1apVuOqqq3DgwIGeZ3zhC1/AX/7lX+KMM85AtVrFtm3b\n8J3vfCf24/nYxz6GTZs2oVar4corr8QzzzwT+/HccccdOOecc1CpVHD++efjq1/9as+ff/7zn8fp\np5+OyclJXH311T13/eEPf4grr7yy5+5/8zd/gz/5kz/B5OQkPvrRj+LLX/4ybrjhBvzbv/0bLrnk\nElSrVWzduhV/+7d/C9d1Y++noKCQfyjSpaCgMBDf/OY34bourr76agDAddddh+effx4//vGPB/67\n66+/Htu3b8fhw4dx11134a677lqyJbvD7cViEQDw53/+5/jiF7+IAwcOYOvWrXj3u9+Nv/qrv8L3\nv/997N69G5s2bcKHPvShpedrmoZPf/rTeOqpp/Cd73wHR44cwSc/+Un80R/9Ef7+7/8+8l7vec97\nMD09jUcffRRHjx7Fn/7pn+Id73gHdu3aFflvPvKRj+D222/HF77wBUxPT+Mf/uEf8NnPfhYzMzPw\nPA/f/e538cgjj+CRRx7Bc889h1Kp1HPXMNx+++3YsGEDDhw4gE996lMAgB/96Ee47bbb8NnPfhZH\njx7F17/+dXzzm9/E7/zO7wx8loKCwpDAU1BQUBiAN7/5zd4HP/jBnt975zvf6b33ve8d+O9Wr17t\nff/73w/9s5tuusm78847Pc/zvF27dnmapnnf+973lv587969nqZp3iOPPNLze2vXrl369Y033ui9\n6U1vWvbse++911u1apXX6XQ8z/O8K664wnvwwQc9z/O87373u94VV1yx7N/cdttt3gc+8IHQu+7Z\ns8erVCre888/H/rnX/rSl7yTTz7Zsyxr6feee+65nrv+4Ac/6Dn3xhtvXHaPL33pS97k5KR36NCh\nnt8/fPiwt2rVqp7XQkFBYTihlC4FBYVI/OIXv8CPf/xj/MEf/EHP799www341re+hWPHjkX+21tu\nuQXvfOc78a53vQu33347Dh06NPCsN77xjUv/f/PmzQCAbdu29fxe93mapuF3f/d3lz3nbW97GxzH\nwdNPP73szx566CE8+OCD0HW953+33nordu7cGXqvn/zkJzjttNNw9tlnD7x7oVBY+vXWrVsHvjaa\npuFXfuVXlv3+W97yFqxfv77n99atW4c3velNeOihhyKfp6CgMBxQpEtBQSESQT3EFVdcgXq9vvS/\nm266CaZp4otf/GLkv/3whz+MZ599Fm9729twzz334Pzzzx9o4dVqtaX/r+v+t6Zyubzs97rheR7T\nx6PrOt797nfDdd1l//v+978f+e8GdXFpmoaxsbGe3wss00HoJmkBoj4ez/Okdo0pKCikA0W6FBQU\nQtFsNnHXXXfhM5/5DJ5++ull//vABz4wMFBv2zbOOOMMvP/978f999+PSy65BP/yL/9Cdj/P8/CN\nb3xj2e/fd999MAwDF1100bI/u/zyy3HffffhyJEjPb//i1/8IjKsftlll2H37t148cUXaS4+AD/8\n4Q9x+PDhnt87evQoHn30Ubz5zW+Wfr6CgoJcKNKloKAQiq9+9avQdR0f/OAHsXXr1p7/nXHGGfjw\nhz+MvXv34nvf+96yfzs9PY0zzjgD3/rWt9DpdPDEE0/g2WefxVlnnUV6x3379uG9730vnn/+eczN\n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\nJgeMshD/dgAAAABJRU5ErkJggg==\n",
104 "text": [
104 "text": [
105 "<matplotlib.figure.Figure at 0x108991850>"
105 "<matplotlib.figure.Figure at 0x108991850>"
106 ]
106 ]
107 }
107 }
108 ],
108 ],
109 "prompt_number": 3
109 "prompt_number": 3
110 },
110 },
111 {
111 {
112 "cell_type": "markdown",
112 "cell_type": "markdown",
113 "metadata": {},
113 "metadata": {},
114 "source": [
114 "source": [
115 "These images can be resized by dragging the handle in the lower right corner. Double clicking will return them to their original size."
115 "These images can be resized by dragging the handle in the lower right corner. Double clicking will return them to their original size."
116 ]
116 ]
117 },
117 },
118 {
118 {
119 "cell_type": "markdown",
119 "cell_type": "markdown",
120 "metadata": {},
120 "metadata": {},
121 "source": [
121 "source": [
122 "One thing to be aware of is that by default, the `Figure` object is cleared at the end of each cell, so you will need to issue all plotting commands for a single figure in a single cell."
122 "One thing to be aware of is that by default, the `Figure` object is cleared at the end of each cell, so you will need to issue all plotting commands for a single figure in a single cell."
123 ]
123 ]
124 },
124 },
125 {
125 {
126 "cell_type": "heading",
126 "cell_type": "heading",
127 "level": 2,
127 "level": 2,
128 "metadata": {},
128 "metadata": {},
129 "source": [
129 "source": [
130 "Loading Matplotlib demos with %load"
130 "Loading Matplotlib demos with %load"
131 ]
131 ]
132 },
132 },
133 {
133 {
134 "cell_type": "markdown",
134 "cell_type": "markdown",
135 "metadata": {},
135 "metadata": {},
136 "source": [
136 "source": [
137 "IPython's `%load` magic can be used to load any Matplotlib demo by its URL:"
137 "IPython's `%load` magic can be used to load any Matplotlib demo by its URL:"
138 ]
138 ]
139 },
139 },
140 {
140 {
141 "cell_type": "code",
141 "cell_type": "code",
142 "collapsed": false,
142 "collapsed": false,
143 "input": [
143 "input": [
144 "%load http://matplotlib.sourceforge.net/mpl_examples/pylab_examples/integral_demo.py"
144 "%load http://matplotlib.org/mpl_examples/showcase/integral_demo.py"
145 ],
145 ],
146 "language": "python",
146 "language": "python",
147 "metadata": {},
147 "metadata": {},
148 "outputs": [],
148 "outputs": [],
149 "prompt_number": 4
149 "prompt_number": 4
150 },
150 },
151 {
151 {
152 "cell_type": "code",
152 "cell_type": "code",
153 "collapsed": false,
153 "collapsed": false,
154 "input": [
154 "input": [
155 "#!/usr/bin/env python\n",
155 "\"\"\"\n",
156 "Plot demonstrating the integral as the area under a curve.\n",
156 "\n",
157 "\n",
157 "# implement the example graphs/integral from pyx\n",
158 "Although this is a simple example, it demonstrates some important tweaks:\n",
158 "from pylab import *\n",
159 "\n",
160 " * A simple line plot with custom color and line width.\n",
161 " * A shaded region created using a Polygon patch.\n",
162 " * A text label with mathtext rendering.\n",
163 " * figtext calls to label the x- and y-axes.\n",
164 " * Use of axis spines to hide the top and right spines.\n",
165 " * Custom tick placement and labels.\n",
166 "\"\"\"\n",
167 "import numpy as np\n",
168 "import matplotlib.pyplot as plt\n",
159 "from matplotlib.patches import Polygon\n",
169 "from matplotlib.patches import Polygon\n",
160 "\n",
170 "\n",
171 "\n",
161 "def func(x):\n",
172 "def func(x):\n",
162 " return (x-3)*(x-5)*(x-7)+85\n",
173 " return (x - 3) * (x - 5) * (x - 7) + 85\n",
163 "\n",
174 "\n",
164 "ax = subplot(111)\n",
165 "\n",
175 "\n",
166 "a, b = 2, 9 # integral area\n",
176 "a, b = 2, 9 # integral limits\n",
167 "x = arange(0, 10, 0.01)\n",
177 "x = np.linspace(0, 10)\n",
168 "y = func(x)\n",
178 "y = func(x)\n",
169 "plot(x, y, linewidth=1)\n",
170 "\n",
179 "\n",
171 "# make the shaded region\n",
180 "fig, ax = plt.subplots()\n",
172 "ix = arange(a, b, 0.01)\n",
181 "plt.plot(x, y, 'r', linewidth=2)\n",
182 "plt.ylim(ymin=0)\n",
183 "\n",
184 "# Make the shaded region\n",
185 "ix = np.linspace(a, b)\n",
173 "iy = func(ix)\n",
186 "iy = func(ix)\n",
174 "verts = [(a,0)] + list(zip(ix,iy)) + [(b,0)]\n",
187 "verts = [(a, 0)] + list(zip(ix, iy)) + [(b, 0)]\n",
175 "poly = Polygon(verts, facecolor='0.8', edgecolor='k')\n",
188 "poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')\n",
176 "ax.add_patch(poly)\n",
189 "ax.add_patch(poly)\n",
177 "\n",
190 "\n",
178 "text(0.5 * (a + b), 30,\n",
191 "plt.text(0.5 * (a + b), 30, r\"$\\int_a^b f(x)\\mathrm{d}x$\",\n",
179 " r\"$\\int_a^b f(x)\\mathrm{d}x$\", horizontalalignment='center',\n",
192 " horizontalalignment='center', fontsize=20)\n",
180 " fontsize=20)\n",
181 "\n",
193 "\n",
182 "axis([0,10, 0, 180])\n",
194 "plt.figtext(0.9, 0.05, '$x$')\n",
183 "figtext(0.9, 0.05, 'x')\n",
195 "plt.figtext(0.1, 0.9, '$y$')\n",
184 "figtext(0.1, 0.9, 'y')\n",
196 "\n",
185 "ax.set_xticks((a,b))\n",
197 "ax.spines['right'].set_visible(False)\n",
186 "ax.set_xticklabels(('a','b'))\n",
198 "ax.spines['top'].set_visible(False)\n",
199 "ax.xaxis.set_ticks_position('bottom')\n",
200 "\n",
201 "ax.set_xticks((a, b))\n",
202 "ax.set_xticklabels(('$a$', '$b$'))\n",
187 "ax.set_yticks([])\n",
203 "ax.set_yticks([])\n",
188 "show()\n"
204 "\n",
205 "plt.show()\n"
189 ],
206 ],
190 "language": "python",
207 "language": "python",
191 "metadata": {},
208 "metadata": {},
192 "outputs": [
209 "outputs": [
193 {
210 {
194 "metadata": {},
211 "metadata": {
212 "png": {
213 "height": 401,
214 "width": 596
215 }
216 },
195 "output_type": "display_data",
217 "output_type": "display_data",
196 "png": "iVBORw0KGgoAAAANSUhEUgAAAlMAAAGTCAYAAAAMQZfBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl8VPW9//H3rNlXErKx7xjAAALihi21tVV7qbbVFi3X\ntlaraPV31VZ7XW6rdrGLP+qj1dYrUvdqrValbmi1iICEfSeEANnIvmcyyzm/Pyj8jBMgMMmcWV7P\nx6OPmuTMnDdb5p3P+c732EzTNAUAAIBTYrc6AAAAQDSjTAEAAISAMgUAABACyhQAAEAIKFMAAAAh\noEwBAACEgDIFAAAQAsoUAABACChTAAAAIaBMAQAAhOC4Zeo///M/9dZbb0mSDMNQSUmJfD5fWIIB\nAABEg+OWqWuvvVZPPPGEJOmdd97R/Pnz5XK5wpELAAAgKhy3TM2dO1dlZWVqa2vTU089pWuuuSZc\nuQAAAKKCzTRN83gHPPzww+rp6dFbb72lN998M1y5AAAAooLzRAdcddVVGjNmjH7729+e8klWrFhx\nyo8FAAAIt/nz5/f72BOWqYyMDE2ePFlf//rXQwo1Y8aMkB4P67z66qu65JJLrI4BAIgQ0fq6sGp/\ni57beEhL/mPicY9bv379ST3vCbdGWLNmjWbOnKnExMSTemIAAIBI8ret9VpQnDvgz3vcydTDDz+s\ntWvX6qGHHhrwEwMAAITLnoYuVbf16LwxWQP+3MctU4sXLx7wEwIAAITbX7fUaUFxrpx224A/Nzug\nAwCAmFbX4dXHlW360qScQXl+yhROaMKECVZHAABEkGh7XXh5W70+P36IUtyOQXl+yhROaOLE47/r\nAQAQX6LpdaHTG9Cbuxv1lSkDv/D8CMoUAACIWf/Y1aAzhqVraKp70M5BmQIAADHJb5j629Z6XTZ1\n6KCehzIFAABi0gflzSpMT9CEnORBPQ9lCgAAxBzTNPXilrpBn0pJlCkAABCDNtV0qCdgaPbw9EE/\nF2UKAADEnBe31OmyKUNltw38Jp2fRpkCAAAxZX9zt/Y0dOlz47LDcj7KFAAAiCl/2VynL5+WK7cz\nPDWHMgUAAGJGXYdXqw+06sunDc6tY/pCmQIAADHjxS11unDCEKUlOMN2TsoUAACICS3dPq0oa9Kl\nUwZ/O4RPokwBAICY8PK2ep07OlNDUlxhPS9lCgAARL1Ob0Cv7WjQ16bmhf3clCkAABD1lu9s0PSi\nNBVlJIT93JQpAAAQ1bwBQy9trdcVp4d/KiVRpgAAQJR7e0+TxmQnaeyQwb2h8bFQpgAAQNQKGKZe\n2HxIV5RYM5WSKFMAACCK/auiRVlJLk3NT7UsA2UKAABEJdM09fymQ5atlTqCMgUAAKLS6gNtkqTZ\nw9MtzUGZAgAAUcc0TT21oUZXTs+XzWazNAtlCgAARJ21B9vkD5iaOzLD6iiUKQAAEF0OT6VqtXBG\nvuwWT6UkyhQAAIgy6yrb5fEZOmdUptVRJFGmAABAFDmyVmrh9MiYSkmUKQAAEEXWV7erwxvQuaMj\nYyolUaYAAECUME1TT62v1TdL8uWwR8ZUSqJMAQCAKLGppkOtHr/OH5NldZReKFMAACAqPLm+Vt+I\nsKmURJkCAABRYHNNuxq7vPrs2MiaSkmUKQAAEOFM09Sy0pqIWyt1BGUKAABEtPVV7Wrp9mv+uGyr\no/SJMgUAACKWaZp6orRGV80siMiplESZAgAAEeyjA63yBQydF0H7Sn0aZQoAAEQkwzS1bF2NFs0s\njJjdzvtCmQIAABHpg/IWuZ12nTki3eoox0WZAgAAESdgmPrz+hpdfUaBbBE8lZIoUwAAIAK9U9ak\n7GSXphemWR3lhChTAAAgongDhp5aX6urZ0b+VEqiTAEAgAjzxq5GjchMVHF+qtVR+oUyBQAAIobH\nb+jZjYe06IwCq6P0G2UKAABEjJe31um0vBRNyEm2Okq/UaYAAEBEaPX49eKWOn07iqZSEmUKAABE\niGc31ur8sVkqyki0OspJoUwBAADL1bT16J09Tbpyer7VUU4aZQoAAFjuidIaLSjOVWaSy+ooJ40y\nBQAALLW7oUubatp12dShVkc5JZQpAABgGdM09b9rq3XV9AIluRxWxzkllCkAAGCZ0qp2NXR6deHE\nIVZHOWWUKQAAYImAYeqxtdX69qxCOeyRf9uYY6FMAQAAS7y7t1mJLrvOGplhdZSQUKYAAEDYefyG\nnlhXrWtmFUbFzYyPhzIFAADC7sXNh3RaXkrU3Mz4eChTAAAgrOo7vfrbtnp9d1aR1VEGBGUKAACE\n1dKPq3XJ5BzlpbmtjjIgKFMAACBsdtZ1akN1hy4/Pc/qKAOGMgUAAMLCNE09srpKV58RvRt09oUy\nBQAAwuL98hb5AoY+Nz7b6igDijIFAAAGXY/f0GMfV+m6ucNkj/KtED6NMgUAAAbdi1vqNDE3RVNj\nYCuET6NMAQCAQVXX4dVLW+t0zexCq6MMCsoUAAAYVI+urtKC4lzlpyVYHWVQUKYAAMCgKa1qU1lj\nl74+LXa2Qvg0yhQAABgUvoCh36+q1PfPHKYEZ+xWjtj9lQEAAEu9tLVehekJOnNkhtVRBhVlCgAA\nDLj6Tq9e2HxI3587zOoog44yBQAABtwf11Tp4sk5KkyPzUXnn0SZAgAAA2pjdbt21nXpipJ8q6OE\nBWUKAAAMGG/A0MOrKnXdmUVKjOFF558UH79KAAAQFi9srlNhultnxfii80+iTAEAgAFR1erR37bW\nafFZw2WLsfvvHQ9lCgAAhMw0TS35sFLfKMnX0FS31XHCijIFAABC9u7eZrX3+LWgONfqKGFHmQIA\nACFp8/j1pzVVuvmcEXLY4+fy3hGUKQAAEJLHPq7WeWOyNCE32eoolqBMAQCAU7a5pkOllW1aNLPA\n6iiWoUwBAIBT4vUb+r8rD+j6ucOU4nZYHccylCkAAHBKntxQq1HZSTp7VKbVUSxFmQIAACdtd32X\n3tzVqMVnxf6NjE+EMgUAAE6KL2Do1x/s17VnFikryWV1HMtRpgAAwEl5btMh5aW59dmxWVZHiQiU\nKQAA0G/lTd36+/YG3XR2fN0y5ngoUwAAoF8ChqkfvbhOC6dmKSclvm4ZczyUKQAA0C+/e2uTGmsO\n6sw8p9VRIgplCgAAnNDuQ216s6Jb81IbrY4ScShTAADguLwBQ3e8vFFfLDSVavNZHSfiUKYAAMBx\nPfj6BiUZPbqoOE+SZJqmxYkiC2UKAAAcU+n+Rn1Y5dGt54+SzWaTzWajTH0KZQoAAPSp2xfQ//xj\nh746xqn0hPi9996JUKYAAECf7v7rGuU5unT++Nxen2cy1RtlCgAABHlnW6W2Nwd087yxVkeJeJQp\nAADQS3OXV7/9YL++OzVdSc7eu5yz63kwyhQAADjKME3d8uxqTUnr0emFaVbHiQqUKQAAcNQf39uu\nth6fvnvmyD6/zrv5glGmAACAJGl7dYte2d2mW88pksPe9+U8ylQwyhQAAFC3L6A7/r5FXx4u5ady\nE+OTQZkCAAD68YtrlOfw6AuT8457HJOpYJQpAADi3EvryrWn2aeb542xOkpUokwBABDHKho79ad1\ntVp8xhAlOk+87QGTqWCUKQAA4pTHb+j/vFCq+XmGxuckWx0nalGmAACIU3e+sFpZ9h59ZVrBST2O\nyVRvlCkAAOLQMx/tUVmzV/91/hh2NQ8RZQoAgDizo6ZVT25q0C1zcvu1TurTmEz1RpkCACCOdHoD\n+uErh/eTGpmVdNKPZwF6MMoUAABxwjRN3fzMhxqZ0HPC/aTQf5QpAADixG/e2KSmLr8WnzvqlJ+D\nyVQwyhQAAHHgra0HtaKiQ3fMGybXMe67h1NDmQIAIMbta+zQb1ce1PdPT1N2kjOk52IyFSy031EA\nABDROnr8uvmFDfpCvk3F+WlWx4lJTKYAAIhRAcPUTc98pBHuHn15WuGAPCeTqWCUKQAAYtTPXytV\nh8erm84bPWDPyQafwShTAADEoOfX7NFHlV268/wRcgzwgnMmU71RpgAAiDFryuv1xPp6/decIUpP\ncAz481OmeqNMAQAQQw40del/3tqjb01yn9IO5zh5lCkAAGJEm8evG/+yXp8d6teckdmDdh4mU71R\npgAAiAG+gKHvP7VK45J6dGnJMKvjxBXKFAAAUc40Td363EdyBLz6/jmjBvVcvJsvGGUKAIAo98Cr\n61XZ2qM7PjtadspO2LEDOgAAUeyxf27X6soO3feZ4UpwDH6RYtPOYEymAACIUi+v36eXdjTpznPy\nlDYIWyD0hTIVjDIFAEAUWrmnVo+uqdEtMzOUl+q2Ok5co0wBABBltlU36/4V5fpucZLG5qSE9dxM\npoJRpgAAiCIVjZ267ZXt+tpop6YPy7A6DkSZAgAgalS3duuGv2zQF4qk88fnWJKByVQwyhQAAFGg\nrqNH1z5bqvOGGrpkSoHVcfAJlCkAACJcU5dX1zy1VrOy/PradOt3N2cy1RtlCgCACNba7dN3/rxa\nxWk+XTlrhNVx2AG9D2zaCQBAhGrv8es7f16lcSkBfefMkVbHkXR4KsVkqjcmUwAARKA2j19XP7FK\nI5ICuu6skREzEWIBejDKFAAAEaa5y6erl32kUUk+3XB25BQp9I3LfAAARJCmLq++++QajUv26tqz\nRkVckWIyFYwyBQBAhGjoPFykTkvz6TtnRl6RQt8oUwAARIDaNo++9/RaTc8ytGj2KKvjHBOTqWCU\nKQAALLa3vl03vbhJ5+TadPkM67c/wMmhTAEAYKGNB5t05+s79cUimy6aUmh1nBNiMhWMMgUAgEX+\ntbtWD7xbrivGOHXuOGvutYfQUaYAALDAy6XlenRtra4pTlLJsAyr45wUJlO9UaYAAAgj0zT1yLvb\n9OruFv2fMzI1dkiy1ZFOCpf5glGmAAAIk4Bh6q6XPtbWui7dfW6Bhqa4rI6EAUCZAgAgDLp9AS1+\n+iN1dnv0wPxRSnZF501ImEwFi84/SQAAokh9R4+ufPxDuQMe/fSC0VFbpNA3JlMAAAyiLZVN+tGr\n2zUr29RVZ4xmV/MYRJkCAGCQvLB2rx5ff0hfH+vWPLY+iFmUKQAABljAMPWTV9aptKZLt84eotHZ\n0fWOveNhzVQwyhQAAAOopdunG5/+SH5fjx747GilumNrfRRlKhhlCgCAAbK5skl3vrpdk1P9uvYz\nY2RnfVRcoEwBABAi0zT12Ps79NLOFn11jFufGR/599g7VUymglGmAAAIQUePX//13GrVdXh11zmF\nyk9zWx0JYUaZAgDgFG2ubNKPX9uuUe5u/fwLY+Syx8dlPSZTvVGmAAA4SQHD1MPvbNEb5R366mhX\nTF/Ww4lRpgAAOAnVrd269S8fy+/z6t5zhys3zu6vx5qpYJQpAAD6wTRNPb9mr5ZtrNfcLEPfPGN0\nXL5bjx3cg1GmAAA4gaYur25//iPVd5v6r1k5GjMkz+pIlmIy1RtlCgCAYzBNU39Zu1dPbKjX1BRD\nt31+RNwsMj8WLvMFo0wBANCH6tZu/ejFj9Xm8evmWbkanxPf0ygcG2UKAIBPCBim/vTPbXpld7vm\nZBpaOG+kHHE+jfokm80mwzCsjhFRKFMAAPzbuooGPfDGdrkMr3589jAVsgEn+oEyBQCIew2dXt37\n0lrt65AWjErQZycU8a6142DNVG+UKQBA3PIFDP3xvW16raxDxUkePTh/tBKdlCicHMoUACDuGKap\nVzfu12NrKpVuduvHc4erMJ0F5v3Bu/mCUaYAAHFldXm9fv32dvn9AS2amqUZw7gVzMng8mcwyhQA\nIC5sr2nVL17foEafQ5eMTND8iblxuYM5Bh5lCgAQ03bUtunB1zeo1uvUvDynFkwriPuNN0PBZb5g\nlCkAQEzaXtOqB5dv0CGvS+fmSrefni+3gxKFgUeZAgDEDNM0tWpvvf7w7jY1B9w6d6hdP5qWLxcl\nakAxmeqNMgUAiHq+gKG/b6jQ0+sqFTAMfW54gj4/OY/LeQgLyhQAIGo1dvm09J9b9c8DXUoOdOlr\npw3R7BEZvONsELFmKhhlCggzj99QU5dPbR6/Gts6VdfSroa2TjV3eNTa7VVHj189voC8AUPegCm/\nIQVkl2Gzy9TxXyDsMmQ3DTlsppw2U26HXS6HXQkuh5LdTqUkOJWR5FZmapKyU5OUm5mmzNQkpbgc\nSnHblZbg5B5kiHiGaWptRaP+95/bVOlN1Ahbi26ZNUKjswqsjhYXKKrBKFPAAPIbpuo7vCqvb9XO\nA3XaV9+qQ23dau0x1WNPkNeRKMNmlyvgkTPglUt+JTmkJKeU4rIr1e1QUapTKYlJSnK7Dv8vwakE\np0Muu2S36Zh1ypAUMCRvwJTXH1C31yeP169ur1/dXp+6vH61dfSotrldHr8pT0DyGDb55VDA7lLA\n7lbA7pTD8Mll9Mht+pRsN5SR5FRuWpLyMlJVlJOhkUOzlJuaoOxkp1wOezh/exHnGjt9eubD7Xq7\nvE02w6+z8xy6eWqOkpy5VkeLO9zouDfKFHAKun0B7a3v0Lo9ldpa2aCqNp86bYnqcSTKFfAoKdCt\nLJeh/FS3Zhalq3BImrISncpMsCnZaQvDT3YuSYkn/SjDNNXhM9XuNdXuNdTQ3q1DLZ1q7OjS+sY2\nfbCrSl2mS15HonyORDkNr9wBj5JtPmUnOVWQmayRuZkaW5irYdkpGprilttJ4cKp6/IG9MaWg3qp\ntEKNZpKK1KJrS4o0KTeJCYlFuMwXjDIFnECbx68N+xv0r+0V2nWoQy1KlM+eoERfu3Jcfo3MTNCZ\n0/I0LCNR2Yl2OaP4MpndZlO626Z0tyQ5pGyXNDK9z2MN83DpaukxVNfRo8rGdtW2dmjvoRa9vOGA\nPI4keZ1Jcho+JQa6lOE0VJCeqNFDMzVx2FCNGpqhoaluJVC28Ck9fkP/2nNIL6zepQPeJGX4m/XZ\nMVk6b1yO3A6mUIg8lCngEwzT1N6GTr29ca9KK+pV50+Q35GgNF+rRqTadMGEIZowNFU5SXbZbUOs\njmspu82mjASbMhLsGpnu1KzClKBjDNNUq9dUY3dABxs7tL+hXR/vrdFbO2rUbf9k2epWptvUsMxk\njc3P0qTheRqWlayhqe6oLqfov44ev1bsqNar68tV5U9Wiq9VswuTdP3kIUpzU6AiCZOpYJQpxDXD\nNFXe2KU3Sndr7b4GNdjS5Ah4Vejs1hnDMzVtWLbyku2y23KsjhqV7DabshJsykqwa1xmljQ2q9fX\nj5Sthq6AKupbtb+hXe9vbdXfNx6Qx5ksnyNR7kCPUtSjoSkujcxJ06ThQzUqN135aQnKTnJyqSdK\nmaapiuZu/WP9Xn24t16NtlRleZs0Z3iqbpqYrVQ3/+YQPShTiDud3oBWbD2g5RvLddCXLLvhU5HL\no/PH5aikKF2ZCVx2CpdPlq3xWTnShN4voAHDVJPHUGVLl8prW3Sgqkbry6rUZUtQjytVhs2hRMOj\nbLepon9PtcYWZKswPUH5aQlKcTss+pWhLy3dPn2wq0Zvb67Qvi6nZAZUaO/UF8YN1RnDM5TopEBF\nCyZTvVGmEBdq2nr0wkc79GF5o1odacryt2pmUYquHpuj3GRecCOVw25TbrJDuclpml6YFvR1j99U\nXadPu6sbtL+hXiurq7TccKrHmaIeZ4rsMpRq8ykvxakRQ9I0vnCIijKTlZ/mVl6aW27ejThoTNNU\ndVuPVu6q0oc7q1TRKfnsCcryt2haXqK+UZKjvBQHk0XEBMoUYlZte4+e+WCLPtzfpm5Hkobb27Xg\ntDyVFKYqwcFPwLEg0WnTiAy3RmQUBn3NNA+/I7H8UIvKappUua9Wm3bslseRpB5nirzOJLkNnzJc\nhgrSEjQqN13jCrJUkJ6k/DS3hiS72HOrn0zT1KEOr7ZWNmv1roPaeahNzUqWzTSUHWjVaUOTdenU\nfA1Ld8luY/1TtGPNVDDKFGJKq8evp1du17t7GtVlT9RIZ6eunJ6vKblJctjzrI6HMLLZbEpPcKhk\nxBCVjAh+s4Bhmqpr79GemkZV1B/S1m0HtXKj/fBUy5Usv92txIBHmS5D+WlujRiSqvGFORqVk668\nNLfSE+JvqmKaphq7fNrf1K3NFTXaUdmgAy09arOnymYGlOZv1fBUhy4cn6NJ+enKTrRLYiPNWBNv\nf+/7gzKFqBcwTK3YXqlnVu3SITNNBWrVFVPzdXp+CpMFHJPdZlN+eqLy04t07sSioK97A4cvIZbX\nNutAY7u2723Syu0H1G1PlNeZrIDdKVfAqwSzR6lOU9lJLuVlJKkwK03Dh2aqIDNVWUkupSc6lOi0\nR8ULkGmaau8JqL7Tq8qmTpVVN6iirkXVrd1q9tnU7UiRzQwoydeuLKdfIzKT9NWpQzUuJ0npbruk\nfKt/CYAlKFOIWlUt3Xr07Y0qbTSVaHh0/sh0fXb8EHZDxoBwO2walu7WsPQ8ScFTTZ9hqs1rqrnb\nr+qmdtW2dKqhoVFlVfXq8Es9Nrd8jkT57W6ZNruchlcuwyeX/Ep2Sqluu9ITXcpMcis9OUHpyUlK\nS0lUZkqSUpPcSnYdLmFup10Om00O++E1ZIf/2yaH7fCEwDBNBQxThikFPvHffsOUx2+o2xdQtzeg\nlo5uNXd0qbWzW80d3Wrq7FFzl0/tXkPdhl1em1s+h1t205Db36XEQLcy3KaGpro1Z1iaRuVmqiDV\noRSXvc/fD8QPLvMFo0whqpimqQ921eix93eowUzWpMRO/WjucBWluayOhjjjsts0JNGmIYlujcsa\nIunY+475Aqa6/Id3l2/z+NTQ1qXmDo9auntU19Sl/YcC6gmYh28FZNjkl12G3SnD5pRhc8i02Q7f\nl/Hf/2/++z6Nps0mm2nKJlM205BNpnT0Y1N20y+H4Zfd9MslQwkOmxKdNiW5HMpIdKh4SIJyM5I1\nND1FaQl2pblscjsif4IGRBrKFKJClzegp1bu0Ou7mmQzDX1uVJo+N34I3/gRFVwOmzIcNmUkSEWp\nDinn5G/1A0QKJlPBKFOIaC3dPi35R6k+qpdyzTZ9p6RQxUO5JxcAIHJQphCRDrV59OvXPtaWdpdG\nuzp111nDlZ8y1OpYAABJhmFYHSGiUKYQUWraPPr5K2u0uytBpyX5dN+5+cpKpEQBQKTgykAwyhQi\nQmOnVw/8bbW2d7h1epqhX56f8+93DQEAIg1rpnqjTMFSbR6/fvXax/q4wabJyX797PzCf+9XAwCI\nREymglGmYAlfwNAj72zW8n3dGu3u1E/PHansJC7nAUA0YDLVG2UKYWWapl7fsE+PrqlSuq1Hd5w5\n7N+bIgIAogFbIwSjTCFsdtS06id/X68uw65vTcnUzKI0qyMBABAyyhQGXac3oJ++tFqbWuy6oCBB\nlxTncc88AIhSTKaCUaYwaEzT1Cul5frTx7UakeDRL84fqVQWlwMAYgxlCoOisqVLd7ywRm1+u64r\nGaLivAKrIwEABgiTqd4oUxhQhmnqj+9u1St7OjQ326ErZhTJySU9AIgZbI0QjDKFAXOgqUO3v/Cx\nAoapO+cWqijdbXUkAAAGHWUKIfvkNGreULe+enq+7PzkAgAxyWazcW++T6FMISSH2jy65bnV8gUM\n/fisIhWmuayOBABAWFGmcMpeWbdXj6w7pDOz7Vo4czjTKACIA2yNEIwyhZPm8QX0o+dXaW+7dNOM\nLE3MTbY6EgAAlqFM4aRsq2rWnX/fooIEv34+f6SSnEyjACCeMJkKRplCvz3xwXY9v71V/zEqQZ+f\nOMzqOAAARATKFE6ox2/otmdXan+7qTvPymPLAwCIc0ymeqNM4bgONHXq5uc/1hC3oZ99bqQSuawH\nAHGNTTuDUaZwTGsOtOq+N3fpnKF2fbVkOP+AAACSmEx9GmUKQUzT1POb6/T3bfWa6dmqL02YRZEC\nAEhiAXpf7FYHQGTx+g398v39+te+Zi35jwnKMtqtjgQAQESjTOGopi6fbn19j/wBU7++eIJyUlho\nDgDojclUMC7zQZJU1tCle94u1xcnDtHC6flc1gMAoJ8oU9Dag6168P0DuvGsYTpvTJbVcQAAEYwf\ntoNRpuLcG7satXRdtf7ngjE6LS/F6jgAAEQdylScMk1TT22o1dt7mvTri8drWEai1ZEAAFHCMAyr\nI0QUylQcChimlnx4UGWNXXrokgnKTnZZHQkAECW4zBeMMhVnevyG7luxT4Zp6lcXjVeSy2F1JABA\nlOHdfL1RpuJIlzegu98uV06yS7fOGymnnZ8uAAAnh60RglGm4kSbx68fv7lX44Yk6cazh8vOmBYA\ngAFBmYoDzd0+/Wh5mWYOS9c1swu53g0AOGVMpoJRpmJcXYdXP1xepvnjstiMEwAQMl5HglGmYlht\ne49ue71MC4pzddnUoVbHAQDECCZTvVGmYtShdq9ue71MX506VP9RnGt1HAAAYhY3Oo5BdR1e3bZ8\njy6bmkuRAgAMOCZTvVGmYkxdh1e3vb5HC4pztaCYS3sAgIHFmqlglKkYUt/p1e3L9+jLp+Xq0ikU\nKQAAwoEyFSMau3y67fUyXTQph8XmAIBBY7PZuDffp1CmYkCbx687/1GmC8Zn62vT8qyOAwBAXKFM\nRTmPL6C73tqr6UVp+mYJRQoAMLjYtDMYZSqKeQOG7n1nn0ZkJuraOUUsCgQADDpea4JRpqJUwDD1\ni/f2K9ll183njOAvNwAgbJhM9UaZikKmaeqhlQfU6QvoR58ZJYedIgUAgFUoU1Hoz+trVdHs0T2f\nGy23gz9CAEB4MZnqjdvJRJnlOxv03t4mPXTJBCW5HFbHAQDEGRagB6NMRZG1B9u0rLRGv7l4vDKT\nXFbHAQAA4jJf1Njd0KUH39+vez43RkUZiVbHAQDEKd7wFIwyFQVq23t0z1vluvmc4TotL8XqOACA\nOEaZCkaZinAdPX79+M29uvz0PJ09KtPqOAAAsGbqUyhTESxgmLr/3QrNLErXguJcq+MAAMBkqg+U\nqQj2yOoq2WzStXOKrI4CAMBRTKZ6o0xFqNd2NGh9dZvu/AybcgIAEMnYGiECbaxu15Pra/Sbiyco\nNYE/IgDeiQvZAAATy0lEQVRAZDEMw+oIEYXJVISpavXogXcrdMdnRqkoI8HqOAAA9MKmncEoUxGk\n0xvQ3W+Xa9HMApUUplkdBwAA9ANlKkIYpqkH39+v0wvSdNHkHKvjAADQJyZTwShTEeL5TYfU3O3T\n98/knXsAgMjF1gjBKFMRoLSyTa9sr9dd80fL5eCPBACAaMIrt8Vq23v0i3/u152fGaWcFLfVcQAA\nOC4mU8EoUxby+A39zzv7dEVJnqYVsOAcABAdWDPVG2XKIqZp6ncfHtSIzER9hVvFAACiCGWqN8qU\nRd7Y1ajdDV265ZzhjEwBAIhilCkL7Gvq1uPranTXZ0cr0eWwOg4QE/7yl79o3rx52rp1q9VRgJjG\n1gjBKFNh1u0L6L539+ma2YUakZVodRwgZlx00UVKSEhQcXGx1VEAxBnKVBgdWSc1OTdFn58wxOo4\nQExZt26dpk+fzmVzYJDZbDbuzfcplKkwemtPk/Y0dGvxWcOsjgLEnDVr1shms+mNN97QAw88oLKy\nMqsjATGJH1iCUabCpKK5W4+trdaP549inRQQoueee07z58/XlVdeqf3790s6XKYWLlyoCy+8UOed\nd55+//vfW5wSiF2smeqNMhUGHr+h+1dU6LuzCzUqK8nqOEBUW7dunX7729/qoYceUmdnp37605+q\ntrZWpmlq6tSpkqTGxka1tLRYnBSITUymglGmwuBPa6o0ZkiSPj8+2+ooQNT73e9+p7lz52rChAky\nTVN5eXnasWOHSkpKjh6zevVqnXXWWRamBBBPKFODbPWBVq092KYbzxpGmwdCtHXrVm3fvl0XXHCB\nEhIS9PLLL+v+++9XSkqK0tIO30XgwIEDKisr05VXXmlxWiB2cZmvN8rUIGru9umhfx3Q7eePVGqC\n0+o4QNRbvny5JAVNnWbNmiW73a7XXntNzz77rP7whz8oMZGtRwCEB6/wg8Q0Tf36gwO6cOIQTc1P\ntToOEBPef/99jRkzRllZWb0+b7PZ9IMf/ECSdPHFF1sRDYgbbNoZjMnUIHl1R4NaPX5dOaPA6ihA\nTDhw4IDq6up6rY0CEH4sWQlGmRoE+5u79eT6Wv3o/JFy2vlLBwyEjz/+WJI0ZcoUi5MAYDLVG2Vq\ngHkDhn723n59Z1ahijJYswEMlNLSUknS5MmTLU4CxDcmU8EoUwPs6Q21yk9z6wsT2AYBGEilpaVy\nu90aPXq01VGAuMdkqjfK1ADaWdepN3Y16gfnDKe5AwNo//79ampq0rhx4+RwcAcBwEq8vgWjTA0Q\nr9/Qgx/s1/fnDlNWksvqOEBM2bBhgyRpwoQJFicBIDGZ+jTK1ABZVlqj0VlJOn9M1okPBnBS1q9f\nL0kaN26cxUkASJSpT6NMDYBttR1asbdJN5493OooQEzasmWLpMgoU4FA4JQf6/f7BzAJgEhBmQqR\nxxfQgx8c0I1nDVdGInugAgOtublZlZWVstlsGjt2rKVZ3n333aO7sJ+KpUuXatOmTQOYCAg/Nu0M\nRpkK0f9+XKNJuck6e1Sm1VGAmLR582ZJUlZWljIzB//f2cGDB3XzzTdryZIl+tnPfnb0RaO0tFQb\nNmzQJZdccsrPffXVV+vxxx/Xvn37+nX8rbfeqoULF7KrOyIKC9CDUaZCsKW2QysrWnT93GFWRwFi\n1pEyFY5LfD6fT4sXL9b8+fPV2NioV155RZ2dnero6NCSJUu0ePHikJ7f6XTqjjvu0D333NOvS36/\n+MUvNGPGDB06dCik8wIDjclUb5SpU+T1G3roXwe0+KxhSufyHjBotm7dKkkaP378oJ/ro48+UnV1\ntWbMmKGvf/3rWrJkiVJTU7V06VJ98YtfVEJCQsjnyM/P19ixY/Xaa6+d8FiHw8E7GBFxmEwFo0yd\nomc21mpkViKX94BBFAgEtH37dknhKVOlpaXKyspSUVGRiouLNXv2bHV3d+vll1/Wl770pQE7z+WX\nX65ly5YN2PMB4cZkqjfK1Ckob+rW6zsbdcNZvHsPGEwVFRXyeDyy2WxhKVPbtm3Taaed1utzK1eu\nVGFhodLT0wfsPBMmTFBra6t27tw5YM8JhAsL0INxfeokBQxTv/3XAX37jAINSWZzTmAwHZlKORwO\njRkzZtDOc++996qpqUmbNm3SqFGjdNNNN6moqEg//OEPtWbNGk2bNu2Yj92xY4eWL18uu92umpoa\n/fd//7deeukltbe3q76+Xt/73vc0bFjvdZV2u10lJSVavXq1Jk2adPTze/fu1dKlS5Wenq7ExES5\nXC5lZR1777pTOTeAgUeZOkkvb6tXotOuCycOsToKEPOOlKkxY8bI6Ry8b1f33nuvqqqqtGDBAt1w\nww06//zzj35t9+7d+spXvtLn4yorK/Xqq6/q9ttvP/o8V199te69914ZhqFrrrlGEydO1MKFC4Me\nO2LECO3evfvox5s2bdIPfvAD/eY3v9GMGTMkSV1dXbr++uv7XKMSyrmBULFuqjcu852E2vYePbux\nVjefM4K/SEAYHClTEydOHPRz7dq1S1LwLWuqq6uVlpbW52Oefvpp3XjjjUc/7u7uVnp6uqZOnar8\n/HxdeeWVx9xKIS0tTdXV1ZIkwzB07733atasWUeLlCQlJyfr85//fJ+XVEI5N4CBRZnqJ9M09dDK\ng/r6tDwVZYT+jh4AxxcIBFRWViZJmjx58qCfb/fu3UpNTVVhYWGvz3d0dByzTF111VVKSko6+vGW\nLVs0e/ZsSVJeXp5uuummY661yszMVEdHh6TD2z9UVlbq9NNP73feUM4NYGBRpvrpvb3Naun267Kp\nQ62OAsSFiooKeb1e2Wy2sJWpvrYhsNlsMgyjz8d8snhVVFSovr5eZ5xxRr/OZxjG0YnTkX2kTqb8\nhHJuAAOLMtUPHT1+/XFtlX5wznA57FzeA8LhyHoip9MZlst8u3fv7vM8aWlpamtrO+Hj161bJ5fL\n1WuxemVl5TGPb2trOzrxysvLkyR5PJ6TjX1K5wYwsChT/bCstEZnjsjQ5KEpVkcB4saePXskHd75\n3OUa3HfOtra26tChQ31uv1BYWKiWlpagz3s8Hi1ZsuTopcg1a9Zo/PjxRzf2NAxDTz755HHPWVRU\nJElH1zkd2aD0k/q6sXKo5wYwsChTJ7C7oUsf7GvRt88oPPHBAAbMkaIwZcqUQT/XkcXnfZWpkpKS\nPu+l9+GHH+rJJ59UeXm5KioqdPDgQbnd7qNff/zxx4+7AHzfvn1HL186HA7dfffdWrly5dESKUkN\nDQ169dVXJUlVVVUDdm4AA4utEY4jYJj63YcH9e1ZhdwyBgizI2WquLh40M+1c+dOpaWl9blmau7c\nufrNb34T9PmZM2fqkksu0c6dO7Vr1y498cQT+vnPf64HHnhALpdL8+bNO2YR9Pv92rx5s2666aaj\nn5s1a5aWLFmiP/3pTyooKFBycrKcTqcuuugiLVu2TDfffLMWLlyoBQsWhHRuYCCwaWdvNITj+Meu\nRrnsNl0wPtvqKEBcObLppM1mC1uZmjVrluz24GH99OnT1dDQoPr6euXm5h79fGZmpu6+++5ex957\n7739Ot+2bduUn58fNAmbMmWKfvnLXwYdv2jRol4fh3JuAAOPy3zH0Nzt07LSGt149nDZ2VMKCKu9\ne/dKOvzutlGjRg3KOZYtW6YbbrhB0uH9rObPn9/ncW63W5dffrmeffbZATv3M888w2aaiGrstdgb\nZeoYHltbrQvGZ2t0dtKJDwYwoMrLyyUdXq80WJYvXy632609e/bI5XIds0xJ0re+9S2tWrWqX+/q\nO5GKigrV1taypgmIIZSpPmyuadfG6nZdNSPf6ihAXDpSpqZPnz5o57jqqquUm5urpUuX6sEHH5TD\n4TjmsYmJibrrrrt03333hbRWpKenRw8++KDuv/9+frIHYghrpj4lYJh6eFWlrj2zSEmuY39zBTB4\njryjbTAnUxdffLEuvvjifh9fXFysyy67TM8//7yuuOKKUzrn0qVLdcMNN3DzYSDGUKY+5fWdDcpI\ndOrcUZlWRwHi1p49e5SUlKRJkyZZHaWXOXPmaM6cOaf8+Ouuu24A0wCIFFzm+4Q2j19Prq/V9XOH\nMYIHLFJTU6P29nZNmTLluJfeACBSUKY+4c/razRvTCaLzgEL7dixQ9LhfZwAIBpQpv5tX1O33i9v\n0bdmFFgdBYhr27ZtkyTNnj3b4iQA0D+UKR3eyfX3H1Xqqhn57HQOWGzr1q1KSUkJy2adADAQKFOS\nPqxoVavHr4sm5VgdBYhrHo9HW7du1Zw5c/rcjRxAZOB2Mr3F/Xcrr9/Qo2uq9P0zh8lhZ9E5YKV1\n69bJ6/Vq3rx5VkcBgH6L+zL14pY6jctJ0vSiNKujAHHnV7/6lb7xjW/I7/dLkt544w2lp6cfdzdy\nAIg0cV2mGjq9+uvWOn1vdpHVUYC4tHbtWnk8HhmGodraWr377rv65je/qYSEBKujAUC/xfVq62Wl\nNfrSpBwVpPONG7DC6aefruzsbLW1teknP/mJRowYoUWLFlkdCwBOStxOpvY2dmvNgTZdcXqe1VGA\nuHXDDTdo27ZtWrBggdxut373u9/J6ez7Zzy/368//OEP+utf/6rnn39et9xyiyorK8OcGIDEAvRP\ni9vJ1GNrq7Rwer5S3OywDFglMzNTDz/8cL+O/dnPfqbx48frsssuU0tLix599FHucQcgIsTlZGpd\nZZtq2726aDJbIQDRYM+ePXr77bd16aWXSpLKyso0Y8YMi1MB8YtbrvUWd2UqYJj605oqfWdWoZxs\nhQBEhbVr16qkpERut/vox7NmzVJ7e7vFyQAgDsvUO2VNSnY7dPaoDKujAOin9PR05eQcniR3dXXp\nvffe07Rp0/SPf/zD4mQAEGdlyuMLaNm6Gn1vThEjSiCKfOELX5DNZtObb76pFStW6MILL9SqVatU\nVMS2JgCsF1cL0P+6tV6n5aVo8tAUq6MAOAlut1t33XWX1TEAoE9xM5lq7vbppa11+vasQqujAACA\nGBI3ZerJ9bW6YHy2CtmgEwAADKC4KFNVrT36oLxZ3yzJtzoKAACIMXFRpv68vkZfmTJU6YlxtUQM\nAACEQcyXqb2N3dpY3a6vFOdaHQUAAMSgmC9TT5RW6/LT85TMbWMAAMAgiOkyte1Qh/Y1deviSdw2\nBgAADI6YLVOmaWrpuhpdOb1AbmfM/jIBAIDFYrZlrK9qV3OXTxeMz7Y6CgAAiGExWaZM09Tj66q1\naGaBHNzMGAAADKKYLFMrK1olUzpndKbVUQAAQIyLuTIVMEw9UVqt/zyjUHZuZgwAAAZZzJWpFWVN\nykx06YxhaVZHAQAAcSCmylTAMPXMxlotmpkvG1MpAAAQBjFVplaUNSk3xa1pBUylAABAeMRMmfIb\npp7eUKurZhRYHQUAgJhmmqbVESJKzJSpFWVNyktza1pBqtVRAABAHImJMuU3TD2zoVZXTmcqBQAA\nwismytQ7e5hKAQAAa0R9mfL/+x18rJUCAABWiPoy9c6eJhWkJWhqPlMpAAAQflFdpo5Mpa6ckW91\nFAAAEKeiukwxlQIAAFaL2jL1/9dKMZUCAADWidoy9d7eZuWlujWFqRQAALBQVJYpwzT13KZafbOE\nqRQAALBWVJapDytalexyqKSQqRQAALBW1JUp0zT17MbDUymbzWZ1HAAAEOeirkytq2yX3zA1Z0S6\n1VEAAACir0w9u7FW3yjJk52pFAAAlujo6LA6QkSJqjK1pbZDTd0+nTc6y+ooAADELcpUb1FVpp7d\nWKvLp+XJYWcqBQAAIkPUlKndDV3a3+zR/PHZVkcBAAA4KmrK1HMba/XVqUPldkRNZAAAEAeiopns\nb+7W1tpOfXHiEKujAAAQ99iaqDebaZrmYJ9kxYoVg30KAACAATN//vx+HxuWMgUAABCrouIyHwAA\nQKSiTAEAAISAMgUAABACyhQAAEAIKFMAAAAhoEwBAIB+2bZtm5588kmrY0QcyhQAAOgXNuvsG2UK\nAAAgBGzaiWPyer1aunSpGhoa1NbWpksuuUTnnHOO1bEAABbZvn27VqxYIa/Xq7a2Ntntdl1++eWa\nNGmS1dEs5bQ6ACKX2+3WpZdeqtzcXHk8Ht11112UKQCIY6ZpqqysTPfdd5/S0tLU0dGh+++/X/fc\nc48SExOtjmcZyhSOyev16r333tPevXvl9/vV0dFhdSQAgIVsNpumT5+utLQ0SVJqaqrGjBmjmpoa\njR492uJ01mHNFI5p1apVMgxDd9xxh2655RY5HA6rIwEALGSapjZs2HD0h+uOjg6Vl5ersLDQ4mTW\nYjKFYyouLtaKFSv0wAMPqKCgQNnZ2VZHAgBYyGazady4cXrkkUfU2dkpm82mRYsWKSEhwepolmIB\nOgAAQAi4zAcAABACyhQAAEAIKFMAAAAhoEwBAACEgDIFAAAQAsoUAABACChTAAAAIaBMAQAAhIAy\nBQAAEALKFAAAQAgoUwAAACGgTAEAAISAMgUAABACyhQAAMAnPPfcc7r66qslSS+++KJuu+224x5v\nM03TDEcwAACAaHH77bcrJSVF69ev19/+9jfZ7ceePznDmAsAACAqLF68WMXFxXr00UePW6QkLvMB\nAAD04vV6dd1112n16tV65JFHVFZWdtzjKVMAAACfcNNNN+n6669XcXGxli5dqkWLFqmzs/OYx7Nm\nCgAAIARMpgAAAEJAmQIAAAgBZQoAACAElCkAAIAQUKYAAABCQJkCAAAIAWUKAAAgBJQpAACAEFCm\nAAAAQvD/AKh2fy0Nfo/2AAAAAElFTkSuQmCC\n",
218 "png": "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\nu0ULZY4ebVMiAADy+/rrr4PbtWrVUmJioo1pAAAAIgclFSKC43//U2LfvpZZoHJlpc2eLcXE2BMK\nAIATeL1erVu3LrjfpEkTG9MAAABEFkoqhL+0NCX16CEjNTU4Mp1Opc+aJfMvf7ExGAAAVt9//708\nHk9wn5IKAACg8CipEN5MU4kPPyznli2WceaIEcq+7DKbQgEAULC8T/WTKKkAAACKgpIKYS32lVcU\ns3SpZea95RZ5+vWzKREAACe3evXq4LZhGDr//PNtTAMAABBZKKkQtlxffqn4Z56xzLIbN1b6xImS\nYdiUCgCAgvn9fq1duza4X7VqVVWoUMHGRAAAAJGFkgphyfjjDyX27i3D7w/OAmXKKH3OHImnJAEA\nwtDGjRuVnp4e3G/cuLGNaQAAACIPJRXCj8ejpLvvlmP/fss4Y+pUBerWtSkUAACn9u2331r2zzvv\nPJuSAAAARCZKKoSdhCeekOu77yyzzIED5evUyaZEAACc3po1ayz7jRo1sikJAABAZKKkQliJmTdP\nsbNmWWa+jh2VNXCgTYkAACic7074AQtXUgEAABQNJRXChnP9eiU89phl5q9dW+lTp0oO/q8KAAhf\nu3bt0p49e4L7LpdL5557ro2JwsfWrVt16aWXavv27SF7z0ceeUTDhw8P2fsBAIDiwb/8ERaMgweV\n2KOHDI8nODPj45U+d67McuVsTAYAwOmdeKtf7dq1FRMTY1Oa8LFmzRrdfPPNuv/++0Na2o0YMUKf\nf/65Bg4cKNM0S/S9AoGADh8+rB07duj777/Xp59+qszMzBJ9TwAAopXL7gCATFMJDz4o565dlnHG\nxInyn3++TaEAACi8aL/Vz+PxaMaMGVq4cKF+//13Va5cWddff70GDBigxJM8dffnn39W9+7d1bNn\nT3Xv3j2kecuUKaN58+apU6dO8ng8evHFF0vkfa677jr9+OOPCgQClvk333yjGjVqlMh7AgAQzbiS\nCraLef11xSxfbpll9e0rb5cuNiUCAKBoTnyyXzQtmp6amqquXbtq1KhR6tKli7799ls9+OCDmj17\n9knLp0OHDunuu+9WgwYNNGjQoBAnzlGtWjVNmDBBb775pl5//fUSeY9bbrlFvXv3tlwlZhhGibwX\nAAClASUVbOXYvl0JQ4daZtktWihzxAibEgEAUDQZGRnasmWLZRZNV1INGjRIa9euVfv27fXAAw9o\n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\nACFkA6eYdyQ3AAAAAElFTkSuQmCC\n",
197 "text": [
219 "text": [
198 "<matplotlib.figure.Figure at 0x106a476d0>"
220 "<matplotlib.figure.Figure at 0x106ef1190>"
199 ]
221 ]
200 }
222 }
201 ],
223 ],
202 "prompt_number": 5
224 "prompt_number": 5
203 }
225 }
204 ],
226 ],
205 "metadata": {}
227 "metadata": {}
206 }
228 }
207 ]
229 ]
208 } No newline at end of file
230 }
@@ -1,930 +1,930 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": ""
3 "name": ""
4 },
4 },
5 "nbformat": 3,
5 "nbformat": 3,
6 "nbformat_minor": 0,
6 "nbformat_minor": 0,
7 "worksheets": [
7 "worksheets": [
8 {
8 {
9 "cells": [
9 "cells": [
10 {
10 {
11 "cell_type": "heading",
11 "cell_type": "heading",
12 "level": 1,
12 "level": 1,
13 "metadata": {},
13 "metadata": {},
14 "source": [
14 "source": [
15 "Using R Within the IPython Notebok"
15 "Using R Within the IPython Notebok"
16 ]
16 ]
17 },
17 },
18 {
18 {
19 "cell_type": "markdown",
19 "cell_type": "markdown",
20 "metadata": {},
20 "metadata": {},
21 "source": [
21 "source": [
22 "Using the `rmagic` extension, users can run R code from within the IPython Notebook. This example Notebook demonstrates this capability. "
22 "Using the `rmagic` extension, users can run R code from within the IPython Notebook. This example Notebook demonstrates this capability. "
23 ]
23 ]
24 },
24 },
25 {
25 {
26 "cell_type": "code",
26 "cell_type": "code",
27 "collapsed": false,
27 "collapsed": false,
28 "input": [
28 "input": [
29 "%matplotlib inline"
29 "%matplotlib inline"
30 ],
30 ],
31 "language": "python",
31 "language": "python",
32 "metadata": {},
32 "metadata": {},
33 "outputs": [],
33 "outputs": [],
34 "prompt_number": 1
34 "prompt_number": 1
35 },
35 },
36 {
36 {
37 "cell_type": "heading",
37 "cell_type": "heading",
38 "level": 2,
38 "level": 2,
39 "metadata": {},
39 "metadata": {},
40 "source": [
40 "source": [
41 "Line magics"
41 "Line magics"
42 ]
42 ]
43 },
43 },
44 {
44 {
45 "cell_type": "markdown",
45 "cell_type": "markdown",
46 "metadata": {},
46 "metadata": {},
47 "source": [
47 "source": [
48 "IPython has an `rmagic` extension that contains a some magic functions for working with R via rpy2. This extension can be loaded using the `%load_ext` magic as follows:"
48 "IPython has an `rmagic` extension that contains a some magic functions for working with R via rpy2. This extension can be loaded using the `%load_ext` magic as follows:"
49 ]
49 ]
50 },
50 },
51 {
51 {
52 "cell_type": "code",
52 "cell_type": "code",
53 "collapsed": true,
53 "collapsed": true,
54 "input": [
54 "input": [
55 "%load_ext rmagic "
55 "%load_ext rmagic "
56 ],
56 ],
57 "language": "python",
57 "language": "python",
58 "metadata": {},
58 "metadata": {},
59 "outputs": [],
59 "outputs": [],
60 "prompt_number": 2
60 "prompt_number": 2
61 },
61 },
62 {
62 {
63 "cell_type": "markdown",
63 "cell_type": "markdown",
64 "metadata": {},
64 "metadata": {},
65 "source": [
65 "source": [
66 "A typical use case one imagines is having some numpy arrays, wanting to compute some statistics of interest on these\n",
66 "A typical use case one imagines is having some numpy arrays, wanting to compute some statistics of interest on these\n",
67 " arrays and return the result back to python. Let's suppose we just want to fit a simple linear model to a scatterplot."
67 " arrays and return the result back to python. Let's suppose we just want to fit a simple linear model to a scatterplot."
68 ]
68 ]
69 },
69 },
70 {
70 {
71 "cell_type": "code",
71 "cell_type": "code",
72 "collapsed": false,
72 "collapsed": false,
73 "input": [
73 "input": [
74 "import numpy as np\n",
74 "import numpy as np\n",
75 "import matplotlib.pyplot as plt\n",
75 "import matplotlib.pyplot as plt\n",
76 "X = np.array([0,1,2,3,4])\n",
76 "X = np.array([0,1,2,3,4])\n",
77 "Y = np.array([3,5,4,6,7])\n",
77 "Y = np.array([3,5,4,6,7])\n",
78 "plt.scatter(X, Y)"
78 "plt.scatter(X, Y)"
79 ],
79 ],
80 "language": "python",
80 "language": "python",
81 "metadata": {},
81 "metadata": {},
82 "outputs": [
82 "outputs": [
83 {
83 {
84 "metadata": {},
84 "metadata": {},
85 "output_type": "pyout",
85 "output_type": "pyout",
86 "prompt_number": 3,
86 "prompt_number": 3,
87 "text": [
87 "text": [
88 "<matplotlib.collections.PathCollection at 0x107efe2d0>"
88 "<matplotlib.collections.PathCollection at 0x107efe2d0>"
89 ]
89 ]
90 },
90 },
91 {
91 {
92 "metadata": {},
92 "metadata": {},
93 "output_type": "display_data",
93 "output_type": "display_data",
94 "png": "iVBORw0KGgoAAAANSUhEUgAAAkoAAAF9CAYAAAD7tEcRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAEYFJREFUeJzt3V1slQcdx/H/OX0JAqULuK3uLYspUAqSUWi3MLoEiWQ6\nXMLdkGwsMXMaMxIvNm+IFXGyZPECo9udGZHohReG93mxadyicbMvTqEyRzY6NidZprRYQUrrhdps\nuj+nKuc8Xfv53MDTPWy/PEvgy3OenlOamJiYCAAA/kO56AEAANOVUAIASAglAICEUAIASAglAICE\nUAIASAglAIBE/VRO2rt3b7zyyitRLpfj2muvjc997nNRXz+lXwoA8IFV8Y7S6OhovPzyy7Fr167Y\nuXNn/OUvf4kzZ87UYhsAQKEq3haaO3durF27Nh588MFoaGiINWvWxHXXXVeLbQAAhap4R+ntt9+O\nX/3qV7Fnz5741re+FcPDw3H8+PFabAMAKFTFO0q///3vY9WqVTFnzpyIiFi3bl0cO3Ys2tvb33Pe\nM888U52FAABVsGHDhornVAylG264IX7605/Gpk2bolwux69//etYtmzZ+57b0dHx36/kf3bw4MH4\n9Kc/XfSMWcU1rz3XvPZc89pzzWuvr69vSudVDKUbb7wxVq9eHV/5yleiVCrFsmXL4rbbbvu/BwIA\nTHdT+h7/jRs3xsaNG6u9BQBgWvGGkwAACaEEAJAQSh9gS5YsKXrCrOOa155rXnuuee255tOXUPoA\nW7p0adETZh3XvPZc89pzzWvPNZ++hBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAk\nhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIA\nQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIo\nAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAk\n6iudMDAwEPv37588Pn36dDz88MOxZMmSqg4DAChaxVC65ZZb4pZbbomIiAsXLsTXv/71WLx4cdWH\nAcBM97e/RfT21sVvf1sXK1ZcitWrL0VjY9GreLeKofRuhw8fjk984hNRKpWqtQcAZo3+/rrYtKkp\nJiZKUS5PxJEjI9HVdanoWbzLlJ9RGh0djd7e3uju7q7mHgCYNU6fLsfExD9uPoyPl+L0aY8OTzdT\n/j9y+PDhuPPOO91NAoArZPHi8Zg3byIiIubPn4jW1vGCF/HvpvTS27lz56K/vz8effTRau8BgFlj\n5cpL8fTTw/H66+W48cbxWL5cKE03UwqlgwcPxqc+9Sl3kwDgClu+XCBNZ1MKpS1btlR7BwDAtOOp\nMQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCA\nhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFAC\nAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgI\nJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAhFACAEgIJQCAxJRC6cyZM/HN\nb34zxsfHq70HAGDaqK90wvj4eBw6dCi++MUvRrnsBhTATPb226X4059KsXDhRCxaNFH0HChcxfLZ\nv39/nDp1Kvbs2RM/+clParEJgAKcOlWObdvmxa23Nse2bfNiaKhU9CQo3GXvKJ05cyaGhoaip6cn\nIiK+/e1vx7XXXhvt7e01GQdA7fT318UvftEQERE//3lD9PfXx003XSx4FRTrsneU+vr6orOzM8rl\ncpTL5Vi3bl0cP368VtsAqKE5cyYuewyz0WVDqampKV566aXJ4/7+/rjpppuqPgqA2lu9+lI8/PBf\nY8mSS/HlL/81Vq++VPQkKNxlX3pbu3ZtnDx5Mnbs2BGlUilWrFgRXV1dtdoGQA1dffVEPPLI+fjC\nF85HU1NEXV3Ri6B4lw2lUqkU9913X622AFCwurqIq64qegVMH77fHwAgIZQAABJCCQAgIZQAABJC\nCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAg\nIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQA\nABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJC\nCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABL1Uzlp+/btsWjRosnjhx56KBYuXFi1\nUQAA08GUQmnevHnR09NT7S0wbZ0/H/HLX9bHiy/WR2fnWNx661jMmVP0KgCqbUqhdPHixdi1a1eM\njIzExz/+8bjzzjurvQumlb6+uti8eX5ElKJUmojDh0fittsuFT0LgCqbUijt3r07Ghoa4uLFi/HY\nY49FW1tb3HzzzVWeBtPHH/5QjohSRERMTJTizTfLESGUAGa6KT3M3dDQMPljZ2dnnDp1qqqjYLpZ\nuvRSLFgwHhERzc3jsXSpSAKYDSqG0unTp+PQoUMRETE2Nhb9/f3R2tpa9WEwnaxYMR5PPz0SP/zh\nSBw9OhLLl48XPQmAGqj40ltLS0u88cYbsWPHjiiXy7Fx48a4/vrra7ENppW2tvFoaxNIALNJxVCq\nr6+PBx98sBZbAACmFW84CQCQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoA\nAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmh\nBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQ\nEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoAAAmhBACQEEoA\nAAmhBACQmFIoXbhwIXp6euJ73/tetfcAAEwbUwqlffv2xfr166u9BeA93nqrFMeOleOtt0pFTwFm\nqYqhdPTo0Vi1alVcc801tdgDEBERr75ajnvumR/d3c2xdev8eO01TwoAtXfZ33kGBwdjeHg4Ojo6\nYmJiolabAGJgoC5eeqk+IiL6++tjYKCu4EXAbFR/uX84MDAQQ0ND8fjjj8fIyEicPXs2mpub4+67\n767VPmCWmj9/4rLHALVw2VDasmXL5M+PHz8evb29IgmoidWrx+KrXx2N/fsbY/Pmv0VHx1jRk4BZ\n6LKh9O9KJQ9UArWxcGHE9u0X4oEHLsSHPlT0GmC2mnIotbe3R3t7ezW3APwHkQQUybeRAAAkhBIA\nQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIo\nAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAk\nhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIA\nQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQEIoAQAkhBIAQKJ+Kift3bs3Tpw4\nEQ0NDdHV1RV33XVXtXcBABSuYiidP38+li9fHtu2bYuIiJ07d0Z3d3csWLCg6uN4f6OjEc8/Xx8/\n+1l93HHHWKxbNxZz5xa9CgBmnoqhNGfOnFizZk1ERIyOjk5+jeL09dXFPffMj4hSPPHERBw8OBK3\n336p6FkAMONM6aW3iIinnnoqnnvuudi6dWs0NjZWcxMV/PGP5Ygo/fOo9M9joQQAV9qUH+a+//77\n48knn4ze3t547bXXqjiJSpYtuxSLFo1HRMSHPzwey5aJJACohop3lE6ePBnvvPNOdHZ2RmNjYzQ3\nN8fw8HAttpFobx+Po0dH4s03S3HddRPR2jpe9CQAmJEqhlJLS0scOHAgDh06FBERS5cujZUrV1Z9\nGJfX2joera1FrwCAma1iKM2bNy++9KUv1WILAMC04g0nAQASQgkAICGUAAASQgkAICGUAAASQgkA\nICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGU\nAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAAS\nQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkAICGUAAASQgkA\nICGUAAASQgkAICGUAAASQukD7MSJE0VPmHVc89pzzWvPNa8913z6EkofYC+//HLRE2Yd17z2XPPa\nc81rzzWfvuqnctKRI0fi+eefj/r6+vjIRz4SDzzwQNTXT+mXAgB8YFW8o3Tu3LkYGhqKRx99NL72\nta9FU1NTvPDCC7XYBgBQqIq3hebPnx+f//znJ48vXLgQV199dVVHAQBMB//VM0o/+tGPYu7cubF4\n8eJq7QEAmDZKExMTE5VOGh8fj+9+97vR0tISmzZtet9znnnmmSs+DgCgWjZs2FDxnIqhdP78+fjO\nd74T3d3d0dXVdcXGAQBMdxVD6ciRI3Hw4MFoaWmZ/Nr69evjjjvuqPo4AIAiTemlNwCA2cgbTgIA\nJIQSAEBCKAEAJIQSAECiKh/Y1t/fH0888UT09PTEDTfcUI3/xKx34MCBePHFFyMioqOjIzZv3lzw\noplvbGwsvv/978fg4GDs3r276Dmzgs+ZrL29e/fGiRMnoqGhIbq6uuKuu+4qetKscOHChfjGN74R\nra2tce+99xY9Z8bbvn17LFq0aPL4oYceioULF77vuVf8d5zf/e530dfXFytXrgzfUFcdg4OD8eqr\nr8auXbsiIuLJJ5+M3/zmN/Gxj32s4GUz2w9+8INYsWJFDA4OFj1lVnj350yWSqXYt29fvPDCC7F2\n7dqip81Y58+fj+XLl8e2bdsiImLnzp3R3d0dCxYsKHjZzLdv375Yv359vP7660VPmRXmzZsXPT09\nUzr3ir/01tbWFp/97Gejrq7uSv+r+af+/v73vJvohg0boq+vr8BFs8O9994bHR0dRc+YNf71OZOl\nUikifM5kLcyZMyfWrFkTERGjo6OTX6O6jh49GqtWrYprrrmm6CmzxsWLF2PXrl3xyCOPxNNPP33Z\nc/+nO0p//vOfY8+ePf/xdW9EWRsjIyPR1NQ0ebxgwYI4e/ZsgYugunzOZG099dRT8dxzz8XWrVuj\nsbGx6Dkz2uDgYAwPD8cnP/nJOHbsWNFzZo3du3dHQ0NDXLx4MR577LFoa2uLm2+++X3P/Z9C6aqr\nrpryLSuuvKamphgeHp48Hh4edmucGendnzPpObzauf/+++Mzn/lM7NmzJz760Y+mf4Dw/xsYGIih\noaF4/PHHY2RkJM6ePRvNzc1x9913Fz1tRmtoaJj8sbOzM06dOnVlQ4lidXR0xI9//OPJZ5KeffbZ\nuP322wteBVeWz5msvZMnT8Y777wTnZ2d0djYGM3Nze/5SxlX3pYtWyZ/fvz48ejt7RVJVXb69OkY\nGBiITZs2xdjYWPT398d9992Xnl/VUPrXswVcWW1tbXHixInYsWNHRPwjnDzIzUzz7LPPxiuvvBLn\nzp2Lo0ePRoSX96utpaUlDhw4EIcOHYqIiKVLl8bKlSsLXjW7+HOz+lpaWuKNN96IHTt2RLlcjo0b\nN8b111+fnu+z3gAAEt5wEgAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJCCQAgIZQAABJ/B42SRiUf\nH7s1AAAAAElFTkSuQmCC\n",
94 "png": "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\nH7s1AAAAAElFTkSuQmCC\n",
95 "text": [
95 "text": [
96 "<matplotlib.figure.Figure at 0x108019350>"
96 "<matplotlib.figure.Figure at 0x108019350>"
97 ]
97 ]
98 }
98 }
99 ],
99 ],
100 "prompt_number": 3
100 "prompt_number": 3
101 },
101 },
102 {
102 {
103 "cell_type": "markdown",
103 "cell_type": "markdown",
104 "metadata": {},
104 "metadata": {},
105 "source": [
105 "source": [
106 "We can accomplish this by first pushing variables to R, fitting a model and returning the results. The line magic %Rpush copies its arguments to variables of the same name in rpy2. The %R line magic evaluates the string in rpy2 and returns the results. In this case, the coefficients of a linear model."
106 "We can accomplish this by first pushing variables to R, fitting a model and returning the results. The line magic %Rpush copies its arguments to variables of the same name in rpy2. The %R line magic evaluates the string in rpy2 and returns the results. In this case, the coefficients of a linear model."
107 ]
107 ]
108 },
108 },
109 {
109 {
110 "cell_type": "code",
110 "cell_type": "code",
111 "collapsed": false,
111 "collapsed": false,
112 "input": [
112 "input": [
113 "%Rpush X Y\n",
113 "%Rpush X Y\n",
114 "%R lm(Y~X)$coef"
114 "%R lm(Y~X)$coef"
115 ],
115 ],
116 "language": "python",
116 "language": "python",
117 "metadata": {},
117 "metadata": {},
118 "outputs": [
118 "outputs": [
119 {
119 {
120 "output_type": "pyout",
120 "output_type": "pyout",
121 "prompt_number": 3,
121 "prompt_number": 3,
122 "text": [
122 "text": [
123 "array([ 3.2, 0.9])"
123 "array([ 3.2, 0.9])"
124 ]
124 ]
125 }
125 }
126 ],
126 ],
127 "prompt_number": 3
127 "prompt_number": 3
128 },
128 },
129 {
129 {
130 "cell_type": "markdown",
130 "cell_type": "markdown",
131 "metadata": {},
131 "metadata": {},
132 "source": [
132 "source": [
133 "We can check that this is correct fairly easily:"
133 "We can check that this is correct fairly easily:"
134 ]
134 ]
135 },
135 },
136 {
136 {
137 "cell_type": "code",
137 "cell_type": "code",
138 "collapsed": false,
138 "collapsed": false,
139 "input": [
139 "input": [
140 "Xr = X - X.mean(); Yr = Y - Y.mean()\n",
140 "Xr = X - X.mean(); Yr = Y - Y.mean()\n",
141 "slope = (Xr*Yr).sum() / (Xr**2).sum()\n",
141 "slope = (Xr*Yr).sum() / (Xr**2).sum()\n",
142 "intercept = Y.mean() - X.mean() * slope\n",
142 "intercept = Y.mean() - X.mean() * slope\n",
143 "(intercept, slope)"
143 "(intercept, slope)"
144 ],
144 ],
145 "language": "python",
145 "language": "python",
146 "metadata": {},
146 "metadata": {},
147 "outputs": [
147 "outputs": [
148 {
148 {
149 "output_type": "pyout",
149 "output_type": "pyout",
150 "prompt_number": 4,
150 "prompt_number": 4,
151 "text": [
151 "text": [
152 "(3.2000000000000002, 0.90000000000000002)"
152 "(3.2000000000000002, 0.90000000000000002)"
153 ]
153 ]
154 }
154 }
155 ],
155 ],
156 "prompt_number": 4
156 "prompt_number": 4
157 },
157 },
158 {
158 {
159 "cell_type": "markdown",
159 "cell_type": "markdown",
160 "metadata": {},
160 "metadata": {},
161 "source": [
161 "source": [
162 "It is also possible to return more than one value with %R."
162 "It is also possible to return more than one value with %R."
163 ]
163 ]
164 },
164 },
165 {
165 {
166 "cell_type": "code",
166 "cell_type": "code",
167 "collapsed": false,
167 "collapsed": false,
168 "input": [
168 "input": [
169 "%R resid(lm(Y~X)); coef(lm(X~Y))\n"
169 "%R resid(lm(Y~X)); coef(lm(X~Y))\n"
170 ],
170 ],
171 "language": "python",
171 "language": "python",
172 "metadata": {},
172 "metadata": {},
173 "outputs": [
173 "outputs": [
174 {
174 {
175 "output_type": "pyout",
175 "output_type": "pyout",
176 "prompt_number": 5,
176 "prompt_number": 5,
177 "text": [
177 "text": [
178 "array([-2.5, 0.9])"
178 "array([-2.5, 0.9])"
179 ]
179 ]
180 }
180 }
181 ],
181 ],
182 "prompt_number": 5
182 "prompt_number": 5
183 },
183 },
184 {
184 {
185 "cell_type": "markdown",
185 "cell_type": "markdown",
186 "metadata": {},
186 "metadata": {},
187 "source": [
187 "source": [
188 "One can also easily capture the results of %R into python objects. Like R, the return value of this multiline expression (multiline in the sense that it is separated by ';') is the final value, which is \n",
188 "One can also easily capture the results of %R into python objects. Like R, the return value of this multiline expression (multiline in the sense that it is separated by ';') is the final value, which is \n",
189 "the *coef(lm(X~Y))*. To pull other variables from R, there is one more magic."
189 "the *coef(lm(X~Y))*. To pull other variables from R, there is one more magic."
190 ]
190 ]
191 },
191 },
192 {
192 {
193 "cell_type": "markdown",
193 "cell_type": "markdown",
194 "metadata": {},
194 "metadata": {},
195 "source": [
195 "source": [
196 "There are two more line magics, %Rpull and %Rget. Both are useful after some R code has been executed and there are variables\n",
196 "There are two more line magics, %Rpull and %Rget. Both are useful after some R code has been executed and there are variables\n",
197 "in the rpy2 namespace that one would like to retrieve. The main difference is that one\n",
197 "in the rpy2 namespace that one would like to retrieve. The main difference is that one\n",
198 " returns the value (%Rget), while the other pulls it to self.shell.user_ns (%Rpull). Imagine we've stored the results\n",
198 " returns the value (%Rget), while the other pulls it to self.shell.user_ns (%Rpull). Imagine we've stored the results\n",
199 "of some calculation in the variable \"a\" in rpy2's namespace. By using the %R magic, we can obtain these results and\n",
199 "of some calculation in the variable \"a\" in rpy2's namespace. By using the %R magic, we can obtain these results and\n",
200 "store them in b. We can also pull them directly to user_ns with %Rpull. They are both views on the same data."
200 "store them in b. We can also pull them directly to user_ns with %Rpull. They are both views on the same data."
201 ]
201 ]
202 },
202 },
203 {
203 {
204 "cell_type": "code",
204 "cell_type": "code",
205 "collapsed": false,
205 "collapsed": false,
206 "input": [
206 "input": [
207 "b = %R a=resid(lm(Y~X))\n",
207 "b = %R a=resid(lm(Y~X))\n",
208 "%Rpull a\n",
208 "%Rpull a\n",
209 "print(a)\n",
209 "print(a)\n",
210 "assert id(b.data) == id(a.data)\n",
210 "assert id(b.data) == id(a.data)\n",
211 "%R -o a"
211 "%R -o a"
212 ],
212 ],
213 "language": "python",
213 "language": "python",
214 "metadata": {},
214 "metadata": {},
215 "outputs": [
215 "outputs": [
216 {
216 {
217 "output_type": "stream",
217 "output_type": "stream",
218 "stream": "stdout",
218 "stream": "stdout",
219 "text": [
219 "text": [
220 "[-0.2 0.9 -1. 0.1 0.2]\n"
220 "[-0.2 0.9 -1. 0.1 0.2]\n"
221 ]
221 ]
222 }
222 }
223 ],
223 ],
224 "prompt_number": 6
224 "prompt_number": 6
225 },
225 },
226 {
226 {
227 "cell_type": "markdown",
227 "cell_type": "markdown",
228 "metadata": {},
228 "metadata": {},
229 "source": [
229 "source": [
230 "%Rpull is equivalent to calling %R with just -o\n"
230 "%Rpull is equivalent to calling %R with just -o\n"
231 ]
231 ]
232 },
232 },
233 {
233 {
234 "cell_type": "code",
234 "cell_type": "code",
235 "collapsed": false,
235 "collapsed": false,
236 "input": [
236 "input": [
237 "%R d=resid(lm(Y~X)); e=coef(lm(Y~X))\n",
237 "%R d=resid(lm(Y~X)); e=coef(lm(Y~X))\n",
238 "%R -o d -o e\n",
238 "%R -o d -o e\n",
239 "%Rpull e\n",
239 "%Rpull e\n",
240 "print(d)\n",
240 "print(d)\n",
241 "print(e)\n",
241 "print(e)\n",
242 "import numpy as np\n",
242 "import numpy as np\n",
243 "np.testing.assert_almost_equal(d, a)"
243 "np.testing.assert_almost_equal(d, a)"
244 ],
244 ],
245 "language": "python",
245 "language": "python",
246 "metadata": {},
246 "metadata": {},
247 "outputs": [
247 "outputs": [
248 {
248 {
249 "output_type": "stream",
249 "output_type": "stream",
250 "stream": "stdout",
250 "stream": "stdout",
251 "text": [
251 "text": [
252 "[-0.2 0.9 -1. 0.1 0.2]\n",
252 "[-0.2 0.9 -1. 0.1 0.2]\n",
253 "[ 3.2 0.9]\n"
253 "[ 3.2 0.9]\n"
254 ]
254 ]
255 }
255 }
256 ],
256 ],
257 "prompt_number": 7
257 "prompt_number": 7
258 },
258 },
259 {
259 {
260 "cell_type": "markdown",
260 "cell_type": "markdown",
261 "metadata": {},
261 "metadata": {},
262 "source": [
262 "source": [
263 "On the other hand %Rpush is equivalent to calling %R with just -i and no trailing code."
263 "On the other hand %Rpush is equivalent to calling %R with just -i and no trailing code."
264 ]
264 ]
265 },
265 },
266 {
266 {
267 "cell_type": "code",
267 "cell_type": "code",
268 "collapsed": false,
268 "collapsed": false,
269 "input": [
269 "input": [
270 "A = np.arange(20)\n",
270 "A = np.arange(20)\n",
271 "%R -i A\n",
271 "%R -i A\n",
272 "%R mean(A)\n"
272 "%R mean(A)\n"
273 ],
273 ],
274 "language": "python",
274 "language": "python",
275 "metadata": {},
275 "metadata": {},
276 "outputs": [
276 "outputs": [
277 {
277 {
278 "output_type": "pyout",
278 "output_type": "pyout",
279 "prompt_number": 8,
279 "prompt_number": 8,
280 "text": [
280 "text": [
281 "array([ 9.5])"
281 "array([ 9.5])"
282 ]
282 ]
283 }
283 }
284 ],
284 ],
285 "prompt_number": 8
285 "prompt_number": 8
286 },
286 },
287 {
287 {
288 "cell_type": "markdown",
288 "cell_type": "markdown",
289 "metadata": {},
289 "metadata": {},
290 "source": [
290 "source": [
291 "The magic %Rget retrieves one variable from R."
291 "The magic %Rget retrieves one variable from R."
292 ]
292 ]
293 },
293 },
294 {
294 {
295 "cell_type": "code",
295 "cell_type": "code",
296 "collapsed": false,
296 "collapsed": false,
297 "input": [
297 "input": [
298 "%Rget A"
298 "%Rget A"
299 ],
299 ],
300 "language": "python",
300 "language": "python",
301 "metadata": {},
301 "metadata": {},
302 "outputs": [
302 "outputs": [
303 {
303 {
304 "output_type": "pyout",
304 "output_type": "pyout",
305 "prompt_number": 9,
305 "prompt_number": 9,
306 "text": [
306 "text": [
307 "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n",
307 "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n",
308 " 17, 18, 19], dtype=int32)"
308 " 17, 18, 19], dtype=int32)"
309 ]
309 ]
310 }
310 }
311 ],
311 ],
312 "prompt_number": 9
312 "prompt_number": 9
313 },
313 },
314 {
314 {
315 "cell_type": "heading",
315 "cell_type": "heading",
316 "level": 2,
316 "level": 2,
317 "metadata": {},
317 "metadata": {},
318 "source": [
318 "source": [
319 "Plotting and capturing output"
319 "Plotting and capturing output"
320 ]
320 ]
321 },
321 },
322 {
322 {
323 "cell_type": "markdown",
323 "cell_type": "markdown",
324 "metadata": {},
324 "metadata": {},
325 "source": [
325 "source": [
326 "R's console (i.e. its stdout() connection) is captured by ipython, as are any plots which are published as PNG files like the notebook with arguments --pylab inline. As a call to %R may produce a return value (see above) we must ask what happens to a magic like the one below. The R code specifies that something is published to the notebook. If anything is published to the notebook, that call to %R returns None."
326 "R's console (i.e. its stdout() connection) is captured by ipython, as are any plots which are published as PNG files, as with `%matplotlib inline`. As a call to %R may produce a return value (see above) we must ask what happens to a magic like the one below. The R code specifies that something is published to the notebook. If anything is published to the notebook, that call to %R returns None."
327 ]
327 ]
328 },
328 },
329 {
329 {
330 "cell_type": "code",
330 "cell_type": "code",
331 "collapsed": false,
331 "collapsed": false,
332 "input": [
332 "input": [
333 "from __future__ import print_function\n",
333 "from __future__ import print_function\n",
334 "v1 = %R plot(X,Y); print(summary(lm(Y~X))); vv=mean(X)*mean(Y)\n",
334 "v1 = %R plot(X,Y); print(summary(lm(Y~X))); vv=mean(X)*mean(Y)\n",
335 "print('v1 is:', v1)\n",
335 "print('v1 is:', v1)\n",
336 "v2 = %R mean(X)*mean(Y)\n",
336 "v2 = %R mean(X)*mean(Y)\n",
337 "print('v2 is:', v2)"
337 "print('v2 is:', v2)"
338 ],
338 ],
339 "language": "python",
339 "language": "python",
340 "metadata": {},
340 "metadata": {},
341 "outputs": [
341 "outputs": [
342 {
342 {
343 "output_type": "display_data",
343 "output_type": "display_data",
344 "text": [
344 "text": [
345 "\n",
345 "\n",
346 "Call:\n",
346 "Call:\n",
347 "lm(formula = Y ~ X)\n",
347 "lm(formula = Y ~ X)\n",
348 "\n",
348 "\n",
349 "Residuals:\n",
349 "Residuals:\n",
350 " 1 2 3 4 5 \n",
350 " 1 2 3 4 5 \n",
351 "-0.2 0.9 -1.0 0.1 0.2 \n",
351 "-0.2 0.9 -1.0 0.1 0.2 \n",
352 "\n",
352 "\n",
353 "Coefficients:\n",
353 "Coefficients:\n",
354 " Estimate Std. Error t value Pr(>|t|) \n",
354 " Estimate Std. Error t value Pr(>|t|) \n",
355 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
355 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
356 "X 0.9000 0.2517 3.576 0.0374 *\n",
356 "X 0.9000 0.2517 3.576 0.0374 *\n",
357 "---\n",
357 "---\n",
358 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1 \n",
358 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1 \n",
359 "\n",
359 "\n",
360 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
360 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
361 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
361 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
362 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739 \n",
362 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739 \n",
363 "\n"
363 "\n"
364 ]
364 ]
365 },
365 },
366 {
366 {
367 "output_type": "display_data",
367 "output_type": "display_data",
368 "png": "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\nUpK06OAUzDPgiIjOnTvHggULYtWqVTFjxoz41re+FevWrYshQ4bEQw899B9/vmvXrtG1a9f9nnv5\n5Zdj/fr1h3oyAEkGDBgQEyZMiEceeSSaNGkS8+bNi5tvvvmgnrhlKqgA/9spp5wSU6dOjalTp8aO\nHTti06ZN2ZMAKDBlZWWxYcOGOOOMM6Jr167RvHnzeO+996JFixbZ02qlIAI8YcKE6Nix437PNWvW\nLJo1a1bHiwD4NBg5cmSMHDkye8Z/pSACPHDgwOwJAFCnCuZNWABQnwgwACQQYABIIMAAkECAASCB\nAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABI\nIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgA\nEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEG\ngAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECA\nASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJGmUPOJCdO3dG\nw4YNo6SkJHsKwEGprq6OGTNmxC9/+cs44ogj4rrrroszzzwzexYFpiCeAa9bty4GDx4cy5Ytiw0b\nNsTQoUOjXbt2cdRRR8WQIUNi9+7d2RMBam3w4MGxYMGCmDx5cowZMya+//3vx4svvpg9iwJTEAG+\n9dZb4/jjj4/Pf/7zcd9990VVVVWsXLky3nzzzdi+fXtMmjSpVteprq6Oqqqq/X5VV1dHTU3NYf6X\nAPXd66+/Hu+++248+eST0alTp+jevXvMmDEj7rvvvuxpFJiCuAX92muvxapVq+KII46IZ555JubN\nmxelpaURETFp0qQYMWJEra4zc+bMmDNnzn7PrV69Ok488cRDNRlgvyorK6N3794fO9ahQ4eorq5O\nWkShKogAd+3aNWbNmhXXXHNN9OzZM+bPnx+jR4+OiIgXXnghunTpUqvrDB06NIYOHbrfc2PHjo31\n69cfss0A+9O1a9e49957Y9OmTXHsscdGRMSiRYviww8/TF5GoSmIAE+bNi2+/vWvx8MPPxydO3eO\nG2+8MR555JH4zGc+E9u2bYvXXnsteyJArZxwwgkxdOjQaN26dcyePTu2bt0azz77bDz55JPZ0ygw\nBRHgk08+Od56661YsGBBrF69Oo4//vg4+uijo0uXLtG3b99o1KggZgLUSv/+/WP58uWxaNGiaNKk\nSZSXl+97Ngz/VjBla9CgQVx00UVx0UUXZU8B+J917949unfvnj2DAlYQ74IGgPpGgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASPCJ\nAN90002xffv2jC3UY5WVlfHyyy/HwoUL46OPPsqeA3DYfSLA69ati9NOOy0WLVqUsWefDRs2RFVV\nVeoG6sbatWvj0ksvjddffz0qKiqiZcuWsX79+uxZAIfVJwL8+OOPxx133BFlZWUxYcKE2L1792Ef\nMXjw4Fi1alVERKxevTr69u0bHTt2jHbt2sWoUaNiz549h30DOT766KM47bTT4rvf/W5873vfiylT\npsTMmTNjwoQJsXfv3ux5AIdNo/0dHDhwYHz1q1+NG2+8Mc4666y4/PLL95079dRT49JLLz2kI1au\nXBk7duyIiIgpU6bEKaecErNnz46NGzfGuHHjYsqUKXHrrbf+x+s899xzsWDBgv2eW7RoURx77LGH\ndDf/uz//+c9x1VVXRe/evfcdGzRoUDz33HPx/vvvR8eOHRPXARw++w1wRESDBg2ipKQk1q9fHytX\nrtx3vHnz5od10EsvvRRr1qyJFi1axDHHHBOTJ0+OcePG1SrAPXr0iJNOOmm/5yorK/dFnsLRuHHj\nqKys/Nix6urqWLt2bTRp0iRpFcDht98Al5eXx/XXXx9f/vKXY8WKFdGmTZvDPmTJkiXRvn37OOec\nc2LTpk3RokWLiIhYsWJFnH766bW6Rtu2baNt27b7Pde6dWuvKRegLl26xMknnxy33357TJgwIaqq\nquIrX/lK9OzZM1q3bp09D+Cw+USAr7jiiqioqIj7778/vvnNb9bJiKuuuiqef/75mDRpUmzdujUa\nN24c5eXlcdttt8W0adOioqKiTnaQY9KkSXH99dfHxRdfHE2bNo0hQ4bE8OHDs2cBHFafCHCrVq3i\nj3/84wGfSR4O48ePj/Hjx0dExN///vfYtm1bRET06dMnbrzxxsN+25tcDRs2jGnTpmXPAKhTnwjw\ngw8+mLFjnw4dOkSHDh0iIuKcc85J3QIAh4vfhAUACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEBRvgnTt3xrZt27JnQFFZtmxZ\nDBw4MPr06RNlZWWxadOm7ElQbxVsgOfOnRvjxo3LngFF469//WvccMMNMX78+Hj22Wdj6NChcfnl\nl8fmzZuzp0G91Ch7QEREly5dYuPGjR87tnv37qiqqoq5c+dG//79Y+bMmf/xOlu2bInKysr9ntu6\ndWvs2bPnkOyFT6O77ror7rjjjjjzzDMjIuJrX/tavPPOO/HYY4/F6NGjk9dB/VMQAZ45c2YMGTIk\nBg0aFFdffXVERMybNy+WLl0aP/jBD6JZs2a1uk5FRUXMnz9/v+d+85vfRNu2bQ/ZZvi0+fDDD6Nd\nu3YfO1ZaWhqrV69OWgT1W0EE+Pzzz49ly5bFqFGjYty4cfHAAw9E69ato3nz5nHCCSfU+jplZWVR\nVla233Njx46N9evXH6rJ8KnTo0eP+OEPfxgzZsyIiH/dZfrOd74Tc+fOTV4G9VNBBDgiomXLljFr\n1qx44okn4oILLogePXpEw4YNs2dB0Rg2bFjMnz8/evfuHf37948FCxbExIkTo1evXtnToF4qmAD/\n2+WXXx7nnXdejBw5Mrp37549B4pGw4YN47nnnouKiorYvHlzTJw4Mc4444zsWVBvFVyAI/71utTz\nzz+fPQOK0oUXXpg9AYgC/hgSABQzAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaA\nBAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIAB\nIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBg\nAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkE\nGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0AC\nAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIEGj7AGF7qWXXor3338/jjvuuOjTp0/2HACKRME+\nA967d29s27YtdcPVV18dTz31VJSUlMRdd90Vl112WVRXV6duAqA4FESA9+zZE1OmTIkhQ4bEG2+8\nEXPmzIm2bdvGUUcdFZdeemns2rWrzjeVl5fHW2+9FQ899FAMGjQofvGLX0TLli3jpz/9aZ1vAaD4\nFMQt6JtuuinefvvtOOOMM+KKK66IRo0axdy5c6O0tDTGjh0b8+bNiyuuuOI/Xmf27Nnx9NNP7/fc\nm2++GaWlpbXetHz58rjnnns+dmz48OHx+OOP1/oaAHAgBRHg+fPnx7Jly6Jly5bRpEmT+OCDD+LL\nX/5yRERMnjw5Jk6cWKsAX3bZZXHJJZfs99yTTz4ZO3bsqPWmli1bxurVq+P888/fd+z3v/99tGzZ\nstbXAIADKYgAn3TSSbFq1ao4++yz45prrom//e1v+86tWLEiOnfuXKvrNG7cOBo3brzfcy1btoy9\ne/fWetOwYcOirKws2rVrF2effXYsWrQoRowYEZWVlbW+BgAcSEEEeNy4cdGvX7/48Y9/HP369Yv2\n7dtHRMQtt9wSjzzySCxcuLDON7Vp0ybmzZsXN910U8yaNSvatGkT69ati1atWtX5FgCKT0EE+KKL\n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\nrkJggg==\n"
368 "png": "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\nUpK06OAUzDPgiIjOnTvHggULYtWqVTFjxoz41re+FevWrYshQ4bEQw899B9/vmvXrtG1a9f9nnv5\n5Zdj/fr1h3oyAEkGDBgQEyZMiEceeSSaNGkS8+bNi5tvvvmgnrhlKqgA/9spp5wSU6dOjalTp8aO\nHTti06ZN2ZMAKDBlZWWxYcOGOOOMM6Jr167RvHnzeO+996JFixbZ02qlIAI8YcKE6Nix437PNWvW\nLJo1a1bHiwD4NBg5cmSMHDkye8Z/pSACPHDgwOwJAFCnCuZNWABQnwgwACQQYABIIMAAkECAASCB\nAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABI\nIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgA\nEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEG\ngAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECA\nASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJGmUPOJCdO3dG\nw4YNo6SkJHsKwEGprq6OGTNmxC9/+cs44ogj4rrrroszzzwzexYFpiCeAa9bty4GDx4cy5Ytiw0b\nNsTQoUOjXbt2cdRRR8WQIUNi9+7d2RMBam3w4MGxYMGCmDx5cowZMya+//3vx4svvpg9iwJTEAG+\n9dZb4/jjj4/Pf/7zcd9990VVVVWsXLky3nzzzdi+fXtMmjSpVteprq6Oqqqq/X5VV1dHTU3NYf6X\nAPXd66+/Hu+++248+eST0alTp+jevXvMmDEj7rvvvuxpFJiCuAX92muvxapVq+KII46IZ555JubN\nmxelpaURETFp0qQYMWJEra4zc+bMmDNnzn7PrV69Ok488cRDNRlgvyorK6N3794fO9ahQ4eorq5O\nWkShKogAd+3aNWbNmhXXXHNN9OzZM+bPnx+jR4+OiIgXXnghunTpUqvrDB06NIYOHbrfc2PHjo31\n69cfss0A+9O1a9e49957Y9OmTXHsscdGRMSiRYviww8/TF5GoSmIAE+bNi2+/vWvx8MPPxydO3eO\nG2+8MR555JH4zGc+E9u2bYvXXnsteyJArZxwwgkxdOjQaN26dcyePTu2bt0azz77bDz55JPZ0ygw\nBRHgk08+Od56661YsGBBrF69Oo4//vg4+uijo0uXLtG3b99o1KggZgLUSv/+/WP58uWxaNGiaNKk\nSZSXl+97Ngz/VjBla9CgQVx00UVx0UUXZU8B+J917949unfvnj2DAlYQ74IGgPpGgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASPCJ\nAN90002xffv2jC3UY5WVlfHyyy/HwoUL46OPPsqeA3DYfSLA69ati9NOOy0WLVqUsWefDRs2RFVV\nVeoG6sbatWvj0ksvjddffz0qKiqiZcuWsX79+uxZAIfVJwL8+OOPxx133BFlZWUxYcKE2L1792Ef\nMXjw4Fi1alVERKxevTr69u0bHTt2jHbt2sWoUaNiz549h30DOT766KM47bTT4rvf/W5873vfiylT\npsTMmTNjwoQJsXfv3ux5AIdNo/0dHDhwYHz1q1+NG2+8Mc4666y4/PLL95079dRT49JLLz2kI1au\nXBk7duyIiIgpU6bEKaecErNnz46NGzfGuHHjYsqUKXHrrbf+x+s899xzsWDBgv2eW7RoURx77LGH\ndDf/uz//+c9x1VVXRe/evfcdGzRoUDz33HPx/vvvR8eOHRPXARw++w1wRESDBg2ipKQk1q9fHytX\nrtx3vHnz5od10EsvvRRr1qyJFi1axDHHHBOTJ0+OcePG1SrAPXr0iJNOOmm/5yorK/dFnsLRuHHj\nqKys/Nix6urqWLt2bTRp0iRpFcDht98Al5eXx/XXXx9f/vKXY8WKFdGmTZvDPmTJkiXRvn37OOec\nc2LTpk3RokWLiIhYsWJFnH766bW6Rtu2baNt27b7Pde6dWuvKRegLl26xMknnxy33357TJgwIaqq\nquIrX/lK9OzZM1q3bp09D+Cw+USAr7jiiqioqIj7778/vvnNb9bJiKuuuiqef/75mDRpUmzdujUa\nN24c5eXlcdttt8W0adOioqKiTnaQY9KkSXH99dfHxRdfHE2bNo0hQ4bE8OHDs2cBHFafCHCrVq3i\nj3/84wGfSR4O48ePj/Hjx0dExN///vfYtm1bRET06dMnbrzxxsN+25tcDRs2jGnTpmXPAKhTnwjw\ngw8+mLFjnw4dOkSHDh0iIuKcc85J3QIAh4vfhAUACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEBRvgnTt3xrZt27JnQFFZtmxZ\nDBw4MPr06RNlZWWxadOm7ElQbxVsgOfOnRvjxo3LngFF469//WvccMMNMX78+Hj22Wdj6NChcfnl\nl8fmzZuzp0G91Ch7QEREly5dYuPGjR87tnv37qiqqoq5c+dG//79Y+bMmf/xOlu2bInKysr9ntu6\ndWvs2bPnkOyFT6O77ror7rjjjjjzzDMjIuJrX/tavPPOO/HYY4/F6NGjk9dB/VMQAZ45c2YMGTIk\nBg0aFFdffXVERMybNy+WLl0aP/jBD6JZs2a1uk5FRUXMnz9/v+d+85vfRNu2bQ/ZZvi0+fDDD6Nd\nu3YfO1ZaWhqrV69OWgT1W0EE+Pzzz49ly5bFqFGjYty4cfHAAw9E69ato3nz5nHCCSfU+jplZWVR\nVla233Njx46N9evXH6rJ8KnTo0eP+OEPfxgzZsyIiH/dZfrOd74Tc+fOTV4G9VNBBDgiomXLljFr\n1qx44okn4oILLogePXpEw4YNs2dB0Rg2bFjMnz8/evfuHf37948FCxbExIkTo1evXtnToF4qmAD/\n2+WXXx7nnXdejBw5Mrp37549B4pGw4YN47nnnouKiorYvHlzTJw4Mc4444zsWVBvFVyAI/71utTz\nzz+fPQOK0oUXXpg9AYgC/hgSABQzAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaA\nBAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIAB\nIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBg\nAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkE\nGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0AC\nAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIEGj7AGF7qWXXor3338/jjvuuOjTp0/2HACKRME+\nA967d29s27YtdcPVV18dTz31VJSUlMRdd90Vl112WVRXV6duAqA4FESA9+zZE1OmTIkhQ4bEG2+8\nEXPmzIm2bdvGUUcdFZdeemns2rWrzjeVl5fHW2+9FQ899FAMGjQofvGLX0TLli3jpz/9aZ1vAaD4\nFMQt6JtuuinefvvtOOOMM+KKK66IRo0axdy5c6O0tDTGjh0b8+bNiyuuuOI/Xmf27Nnx9NNP7/fc\nm2++GaWlpbXetHz58rjnnns+dmz48OHx+OOP1/oaAHAgBRHg+fPnx7Jly6Jly5bRpEmT+OCDD+LL\nX/5yRERMnjw5Jk6cWKsAX3bZZXHJJZfs99yTTz4ZO3bsqPWmli1bxurVq+P888/fd+z3v/99tGzZ\nstbXAIADKYgAn3TSSbFq1ao4++yz45prrom//e1v+86tWLEiOnfuXKvrNG7cOBo3brzfcy1btoy9\ne/fWetOwYcOirKws2rVrF2effXYsWrQoRowYEZWVlbW+BgAcSEEEeNy4cdGvX7/48Y9/HP369Yv2\n7dtHRMQtt9wSjzzySCxcuLDON7Vp0ybmzZsXN910U8yaNSvatGkT69ati1atWtX5FgCKT0EE+KKL\n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\nrkJggg==\n"
369 },
369 },
370 {
370 {
371 "output_type": "stream",
371 "output_type": "stream",
372 "stream": "stdout",
372 "stream": "stdout",
373 "text": [
373 "text": [
374 "v1 is: [ 10.]\n",
374 "v1 is: [ 10.]\n",
375 "v2 is: [ 10.]\n"
375 "v2 is: [ 10.]\n"
376 ]
376 ]
377 }
377 }
378 ],
378 ],
379 "prompt_number": 10
379 "prompt_number": 10
380 },
380 },
381 {
381 {
382 "cell_type": "heading",
382 "cell_type": "heading",
383 "level": 2,
383 "level": 2,
384 "metadata": {},
384 "metadata": {},
385 "source": [
385 "source": [
386 "What value is returned from %R?"
386 "What value is returned from %R?"
387 ]
387 ]
388 },
388 },
389 {
389 {
390 "cell_type": "markdown",
390 "cell_type": "markdown",
391 "metadata": {},
391 "metadata": {},
392 "source": [
392 "source": [
393 "Some calls have no particularly interesting return value, the magic %R will not return anything in this case. The return value in rpy2 is actually NULL so %R returns None."
393 "Some calls have no particularly interesting return value, the magic %R will not return anything in this case. The return value in rpy2 is actually NULL so %R returns None."
394 ]
394 ]
395 },
395 },
396 {
396 {
397 "cell_type": "code",
397 "cell_type": "code",
398 "collapsed": false,
398 "collapsed": false,
399 "input": [
399 "input": [
400 "v = %R plot(X,Y)\n",
400 "v = %R plot(X,Y)\n",
401 "assert v == None"
401 "assert v == None"
402 ],
402 ],
403 "language": "python",
403 "language": "python",
404 "metadata": {},
404 "metadata": {},
405 "outputs": [
405 "outputs": [
406 {
406 {
407 "output_type": "display_data",
407 "output_type": "display_data",
408 "png": "iVBORw0KGgoAAAANSUhEUgAAAeAAAAHgCAYAAAB91L6VAAAD8GlDQ1BJQ0MgUHJvZmlsZQAAKJGN\nVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4\nA4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJ\nGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19\nHvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzz\nHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+Bkm\nfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q\n00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8O\ncxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqh\nz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s\n15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5\nnkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aru\nq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV\n35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15T\nMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5D\na9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5\nQH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok\n898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4\nBGDj42bzn+Vmc+NL9L8GcMn8F1kAcXjEKMJAAAAYFklEQVR4nO3de5DVBf3/8TfBKne8MICwqCiQ\nVkg6KuqYETZCkgPYqqGEBSIwgnJRGo0cRxgxw3FGhVJRErLFC4o3GoVNE4JKMhJSoCSlMkZuC0hy\nWXZ/fzQx40/4thTs+3j28ZjZP/bzmf2cFzPMPOd8zjm7DWpqamoCAKhTn8keAAD1kQADQAIBBoAE\nAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEg\ngQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAA\nSCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQY\nABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEgQaPsAXXp\nqaeeiqqqquwZABSINm3aRK9evVIeu0FNTU1NyiPXsblz58bdd98dV199dfYUAArEvffeG4899lh8\n8YtfrPPHrjfPgKuqqmLw4MExfPjw7CkAFIg1a9ZEdXV1ymN7DRgAEggwACQQYABIIMAAkECAASCB\nAANAAgEGgAT15nPAABSnt956K7Zu3Rqf/exn45hjjsmeU2sF8Qz4/fffj71792bPAOBTpKamJm69\n9daYNGlSzJ07N0pLS2Pp0qXZs2qtIALct2/fuOCCC2Lt2rXZUwD4lJg8eXLs2LEjysvLY+rUqfHG\nG2/EDTfcEO+99172tFopmFvQ3bp1i/POOy8mTJgQQ4cOjVatWh30NV577bX49a9/vd9zixYtijZt\n2sSIESP+16kAFIBly5bFjBkz9n1/yimnxJAhQ+JXv/pVnHDCCYnLaqcgngFHRAwbNiwWL14cP//5\nz6O0tDRGjBgRixcvjm3bttX6Gu3atYtu3brt96thw4axYcOGw/gvAKAuNW/ePHbu3PmxY5WVlVFS\nUpK06OAUzDPgiIjOnTvHggULYtWqVTFjxoz41re+FevWrYshQ4bEQw899B9/vmvXrtG1a9f9nnv5\n5Zdj/fr1h3oyAEkGDBgQEyZMiEceeSSaNGkS8+bNi5tvvvmgnrhlKqgA/9spp5wSU6dOjalTp8aO\nHTti06ZN2ZMAKDBlZWWxYcOGOOOMM6Jr167RvHnzeO+996JFixbZ02qlIAI8YcKE6Nix437PNWvW\nLJo1a1bHiwD4NBg5cmSMHDkye8Z/pSACPHDgwOwJAFCnCuZNWABQnwgwACQQYABIIMAAkECAASCB\nAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABI\nIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgA\nEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEG\ngAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECA\nASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJGmUPOJCdO3dG\nw4YNo6SkJHsKwEGprq6OGTNmxC9/+cs44ogj4rrrroszzzwzexYFpiCeAa9bty4GDx4cy5Ytiw0b\nNsTQoUOjXbt2cdRRR8WQIUNi9+7d2RMBam3w4MGxYMGCmDx5cowZMya+//3vx4svvpg9iwJTEAG+\n9dZb4/jjj4/Pf/7zcd9990VVVVWsXLky3nzzzdi+fXtMmjSpVteprq6Oqqqq/X5VV1dHTU3NYf6X\nAPXd66+/Hu+++248+eST0alTp+jevXvMmDEj7rvvvuxpFJiCuAX92muvxapVq+KII46IZ555JubN\nmxelpaURETFp0qQYMWJEra4zc+bMmDNnzn7PrV69Ok488cRDNRlgvyorK6N3794fO9ahQ4eorq5O\nWkShKogAd+3aNWbNmhXXXHNN9OzZM+bPnx+jR4+OiIgXXnghunTpUqvrDB06NIYOHbrfc2PHjo31\n69cfss0A+9O1a9e49957Y9OmTXHsscdGRMSiRYviww8/TF5GoSmIAE+bNi2+/vWvx8MPPxydO3eO\nG2+8MR555JH4zGc+E9u2bYvXXnsteyJArZxwwgkxdOjQaN26dcyePTu2bt0azz77bDz55JPZ0ygw\nBRHgk08+Od56661YsGBBrF69Oo4//vg4+uijo0uXLtG3b99o1KggZgLUSv/+/WP58uWxaNGiaNKk\nSZSXl+97Ngz/VjBla9CgQVx00UVx0UUXZU8B+J917949unfvnj2DAlYQ74IGgPpGgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASPCJ\nAN90002xffv2jC3UY5WVlfHyyy/HwoUL46OPPsqeA3DYfSLA69ati9NOOy0WLVqUsWefDRs2RFVV\nVeoG6sbatWvj0ksvjddffz0qKiqiZcuWsX79+uxZAIfVJwL8+OOPxx133BFlZWUxYcKE2L1792Ef\nMXjw4Fi1alVERKxevTr69u0bHTt2jHbt2sWoUaNiz549h30DOT766KM47bTT4rvf/W5873vfiylT\npsTMmTNjwoQJsXfv3ux5AIdNo/0dHDhwYHz1q1+NG2+8Mc4666y4/PLL95079dRT49JLLz2kI1au\nXBk7duyIiIgpU6bEKaecErNnz46NGzfGuHHjYsqUKXHrrbf+x+s899xzsWDBgv2eW7RoURx77LGH\ndDf/uz//+c9x1VVXRe/evfcdGzRoUDz33HPx/vvvR8eOHRPXARw++w1wRESDBg2ipKQk1q9fHytX\nrtx3vHnz5od10EsvvRRr1qyJFi1axDHHHBOTJ0+OcePG1SrAPXr0iJNOOmm/5yorK/dFnsLRuHHj\nqKys/Nix6urqWLt2bTRp0iRpFcDht98Al5eXx/XXXx9f/vKXY8WKFdGmTZvDPmTJkiXRvn37OOec\nc2LTpk3RokWLiIhYsWJFnH766bW6Rtu2baNt27b7Pde6dWuvKRegLl26xMknnxy33357TJgwIaqq\nquIrX/lK9OzZM1q3bp09D+Cw+USAr7jiiqioqIj7778/vvnNb9bJiKuuuiqef/75mDRpUmzdujUa\nN24c5eXlcdttt8W0adOioqKiTnaQY9KkSXH99dfHxRdfHE2bNo0hQ4bE8OHDs2cBHFafCHCrVq3i\nj3/84wGfSR4O48ePj/Hjx0dExN///vfYtm1bRET06dMnbrzxxsN+25tcDRs2jGnTpmXPAKhTnwjw\ngw8+mLFjnw4dOkSHDh0iIuKcc85J3QIAh4vfhAUACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEBRvgnTt3xrZt27JnQFFZtmxZ\nDBw4MPr06RNlZWWxadOm7ElQbxVsgOfOnRvjxo3LngFF469//WvccMMNMX78+Hj22Wdj6NChcfnl\nl8fmzZuzp0G91Ch7QEREly5dYuPGjR87tnv37qiqqoq5c+dG//79Y+bMmf/xOlu2bInKysr9ntu6\ndWvs2bPnkOyFT6O77ror7rjjjjjzzDMjIuJrX/tavPPOO/HYY4/F6NGjk9dB/VMQAZ45c2YMGTIk\nBg0aFFdffXVERMybNy+WLl0aP/jBD6JZs2a1uk5FRUXMnz9/v+d+85vfRNu2bQ/ZZvi0+fDDD6Nd\nu3YfO1ZaWhqrV69OWgT1W0EE+Pzzz49ly5bFqFGjYty4cfHAAw9E69ato3nz5nHCCSfU+jplZWVR\nVla233Njx46N9evXH6rJ8KnTo0eP+OEPfxgzZsyIiH/dZfrOd74Tc+fOTV4G9VNBBDgiomXLljFr\n1qx44okn4oILLogePXpEw4YNs2dB0Rg2bFjMnz8/evfuHf37948FCxbExIkTo1evXtnToF4qmAD/\n2+WXXx7nnXdejBw5Mrp37549B4pGw4YN47nnnouKiorYvHlzTJw4Mc4444zsWVBvFVyAI/71utTz\nzz+fPQOK0oUXXpg9AYgC/hgSABQzAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaA\nBAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIAB\nIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBg\nAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkE\nGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0AC\nAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIEGj7AGF7qWXXor3338/jjvuuOjTp0/2HACKRME+\nA967d29s27YtdcPVV18dTz31VJSUlMRdd90Vl112WVRXV6duAqA4FESA9+zZE1OmTIkhQ4bEG2+8\nEXPmzIm2bdvGUUcdFZdeemns2rWrzjeVl5fHW2+9FQ899FAMGjQofvGLX0TLli3jpz/9aZ1vAaD4\nFMQt6JtuuinefvvtOOOMM+KKK66IRo0axdy5c6O0tDTGjh0b8+bNiyuuuOI/Xmf27Nnx9NNP7/fc\nm2++GaWlpbXetHz58rjnnns+dmz48OHx+OOP1/oaAHAgBRHg+fPnx7Jly6Jly5bRpEmT+OCDD+LL\nX/5yRERMnjw5Jk6cWKsAX3bZZXHJJZfs99yTTz4ZO3bsqPWmli1bxurVq+P888/fd+z3v/99tGzZ\nstbXAIADKYgAn3TSSbFq1ao4++yz45prrom//e1v+86tWLEiOnfuXKvrNG7cOBo3brzfcy1btoy9\ne/fWetOwYcOirKws2rVrF2effXYsWrQoRowYEZWVlbW+BgAcSEEEeNy4cdGvX7/48Y9/HP369Yv2\n7dtHRMQtt9wSjzzySCxcuLDON7Vp0ybmzZsXN910U8yaNSvatGkT69ati1atWtX5FgCKT0EE+KKL\n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\nrkJggg==\n"
408 "png": "iVBORw0KGgoAAAANSUhEUgAAAeAAAAHgCAYAAAB91L6VAAAD8GlDQ1BJQ0MgUHJvZmlsZQAAKJGN\nVd1v21QUP4lvXKQWP6Cxjg4Vi69VU1u5GxqtxgZJk6XpQhq5zdgqpMl1bhpT1za2021Vn/YCbwz4\nA4CyBx6QeEIaDMT2su0BtElTQRXVJKQ9dNpAaJP2gqpwrq9Tu13GuJGvfznndz7v0TVAx1ea45hJ\nGWDe8l01n5GPn5iWO1YhCc9BJ/RAp6Z7TrpcLgIuxoVH1sNfIcHeNwfa6/9zdVappwMknkJsVz19\nHvFpgJSpO64PIN5G+fAp30Hc8TziHS4miFhheJbjLMMzHB8POFPqKGKWi6TXtSriJcT9MzH5bAzz\nHIK1I08t6hq6zHpRdu2aYdJYuk9Q/881bzZa8Xrx6fLmJo/iu4/VXnfH1BB/rmu5ScQvI77m+Bkm\nfxXxvcZcJY14L0DymZp7pML5yTcW61PvIN6JuGr4halQvmjNlCa4bXJ5zj6qhpxrujeKPYMXEd+q\n00KR5yNAlWZzrF+Ie+uNsdC/MO4tTOZafhbroyXuR3Df08bLiHsQf+ja6gTPWVimZl7l/oUrjl8O\ncxDWLbNU5D6JRL2gxkDu16fGuC054OMhclsyXTOOFEL+kmMGs4i5kfNuQ62EnBuam8tzP+Q+tSqh\nz9SuqpZlvR1EfBiOJTSgYMMM7jpYsAEyqJCHDL4dcFFTAwNMlFDUUpQYiadhDmXteeWAw3HEmA2s\n15k1RmnP4RHuhBybdBOF7MfnICmSQ2SYjIBM3iRvkcMki9IRcnDTthyLz2Ld2fTzPjTQK+Mdg8y5\nnkZfFO+se9LQr3/09xZr+5GcaSufeAfAww60mAPx+q8u/bAr8rFCLrx7s+vqEkw8qb+p26n11Aru\nq6m1iJH6PbWGv1VIY25mkNE8PkaQhxfLIF7DZXx80HD/A3l2jLclYs061xNpWCfoB6WHJTjbH0mV\n35Q/lRXlC+W8cndbl9t2SfhU+Fb4UfhO+F74GWThknBZ+Em4InwjXIyd1ePnY/Psg3pb1TJNu15T\nMKWMtFt6ScpKL0ivSMXIn9QtDUlj0h7U7N48t3i8eC0GnMC91dX2sTivgloDTgUVeEGHLTizbf5D\na9JLhkhh29QOs1luMcScmBXTIIt7xRFxSBxnuJWfuAd1I7jntkyd/pgKaIwVr3MgmDo2q8x6IdB5\nQH162mcX7ajtnHGN2bov71OU1+U0fqqoXLD0wX5ZM005UHmySz3qLtDqILDvIL+iH6jB9y2x83ok\n898GOPQX3lk3Itl0A+BrD6D7tUjWh3fis58BXDigN9yF8M5PJH4B8Gr79/F/XRm8m241mw/wvur4\nBGDj42bzn+Vmc+NL9L8GcMn8F1kAcXjEKMJAAAAYFklEQVR4nO3de5DVBf3/8TfBKne8MICwqCiQ\nVkg6KuqYETZCkgPYqqGEBSIwgnJRGo0cRxgxw3FGhVJRErLFC4o3GoVNE4JKMhJSoCSlMkZuC0hy\nWXZ/fzQx40/4thTs+3j28ZjZP/bzmf2cFzPMPOd8zjm7DWpqamoCAKhTn8keAAD1kQADQAIBBoAE\nAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEg\ngQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAA\nSCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQY\nABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEgQaPsAXXp\nqaeeiqqqquwZABSINm3aRK9evVIeu0FNTU1NyiPXsblz58bdd98dV199dfYUAArEvffeG4899lh8\n8YtfrPPHrjfPgKuqqmLw4MExfPjw7CkAFIg1a9ZEdXV1ymN7DRgAEggwACQQYABIIMAAkECAASCB\nAANAAgEGgAT15nPAABSnt956K7Zu3Rqf/exn45hjjsmeU2sF8Qz4/fffj71792bPAOBTpKamJm69\n9daYNGlSzJ07N0pLS2Pp0qXZs2qtIALct2/fuOCCC2Lt2rXZUwD4lJg8eXLs2LEjysvLY+rUqfHG\nG2/EDTfcEO+99172tFopmFvQ3bp1i/POOy8mTJgQQ4cOjVatWh30NV577bX49a9/vd9zixYtijZt\n2sSIESP+16kAFIBly5bFjBkz9n1/yimnxJAhQ+JXv/pVnHDCCYnLaqcgngFHRAwbNiwWL14cP//5\nz6O0tDRGjBgRixcvjm3bttX6Gu3atYtu3brt96thw4axYcOGw/gvAKAuNW/ePHbu3PmxY5WVlVFS\nUpK06OAUzDPgiIjOnTvHggULYtWqVTFjxoz41re+FevWrYshQ4bEQw899B9/vmvXrtG1a9f9nnv5\n5Zdj/fr1h3oyAEkGDBgQEyZMiEceeSSaNGkS8+bNi5tvvvmgnrhlKqgA/9spp5wSU6dOjalTp8aO\nHTti06ZN2ZMAKDBlZWWxYcOGOOOMM6Jr167RvHnzeO+996JFixbZ02qlIAI8YcKE6Nix437PNWvW\nLJo1a1bHiwD4NBg5cmSMHDkye8Z/pSACPHDgwOwJAFCnCuZNWABQnwgwACQQYABIIMAAkECAASCB\nAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABI\nIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgA\nEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEG\ngAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECA\nASCBAANAAgEGgAQCDAAJBBgAEggwACQQYABIIMAAkECAASCBAANAAgEGgAQCDAAJGmUPOJCdO3dG\nw4YNo6SkJHsKwEGprq6OGTNmxC9/+cs44ogj4rrrroszzzwzexYFpiCeAa9bty4GDx4cy5Ytiw0b\nNsTQoUOjXbt2cdRRR8WQIUNi9+7d2RMBam3w4MGxYMGCmDx5cowZMya+//3vx4svvpg9iwJTEAG+\n9dZb4/jjj4/Pf/7zcd9990VVVVWsXLky3nzzzdi+fXtMmjSpVteprq6Oqqqq/X5VV1dHTU3NYf6X\nAPXd66+/Hu+++248+eST0alTp+jevXvMmDEj7rvvvuxpFJiCuAX92muvxapVq+KII46IZ555JubN\nmxelpaURETFp0qQYMWJEra4zc+bMmDNnzn7PrV69Ok488cRDNRlgvyorK6N3794fO9ahQ4eorq5O\nWkShKogAd+3aNWbNmhXXXHNN9OzZM+bPnx+jR4+OiIgXXnghunTpUqvrDB06NIYOHbrfc2PHjo31\n69cfss0A+9O1a9e49957Y9OmTXHsscdGRMSiRYviww8/TF5GoSmIAE+bNi2+/vWvx8MPPxydO3eO\nG2+8MR555JH4zGc+E9u2bYvXXnsteyJArZxwwgkxdOjQaN26dcyePTu2bt0azz77bDz55JPZ0ygw\nBRHgk08+Od56661YsGBBrF69Oo4//vg4+uijo0uXLtG3b99o1KggZgLUSv/+/WP58uWxaNGiaNKk\nSZSXl+97Ngz/VjBla9CgQVx00UVx0UUXZU8B+J917949unfvnj2DAlYQ74IGgPpGgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASPCJ\nAN90002xffv2jC3UY5WVlfHyyy/HwoUL46OPPsqeA3DYfSLA69ati9NOOy0WLVqUsWefDRs2RFVV\nVeoG6sbatWvj0ksvjddffz0qKiqiZcuWsX79+uxZAIfVJwL8+OOPxx133BFlZWUxYcKE2L1792Ef\nMXjw4Fi1alVERKxevTr69u0bHTt2jHbt2sWoUaNiz549h30DOT766KM47bTT4rvf/W5873vfiylT\npsTMmTNjwoQJsXfv3ux5AIdNo/0dHDhwYHz1q1+NG2+8Mc4666y4/PLL95079dRT49JLLz2kI1au\nXBk7duyIiIgpU6bEKaecErNnz46NGzfGuHHjYsqUKXHrrbf+x+s899xzsWDBgv2eW7RoURx77LGH\ndDf/uz//+c9x1VVXRe/evfcdGzRoUDz33HPx/vvvR8eOHRPXARw++w1wRESDBg2ipKQk1q9fHytX\nrtx3vHnz5od10EsvvRRr1qyJFi1axDHHHBOTJ0+OcePG1SrAPXr0iJNOOmm/5yorK/dFnsLRuHHj\nqKys/Nix6urqWLt2bTRp0iRpFcDht98Al5eXx/XXXx9f/vKXY8WKFdGmTZvDPmTJkiXRvn37OOec\nc2LTpk3RokWLiIhYsWJFnH766bW6Rtu2baNt27b7Pde6dWuvKRegLl26xMknnxy33357TJgwIaqq\nquIrX/lK9OzZM1q3bp09D+Cw+USAr7jiiqioqIj7778/vvnNb9bJiKuuuiqef/75mDRpUmzdujUa\nN24c5eXlcdttt8W0adOioqKiTnaQY9KkSXH99dfHxRdfHE2bNo0hQ4bE8OHDs2cBHFafCHCrVq3i\nj3/84wGfSR4O48ePj/Hjx0dExN///vfYtm1bRET06dMnbrzxxsN+25tcDRs2jGnTpmXPAKhTnwjw\ngw8+mLFjnw4dOkSHDh0iIuKcc85J3QIAh4vfhAUACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIB\nBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBA\ngAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAk\nEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwA\nCQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQAD\nQAIBBoAEAgwACQQYABIIMAAkEGAASCDAAJBAgAEggQADQAIBBoAEBRvgnTt3xrZt27JnQFFZtmxZ\nDBw4MPr06RNlZWWxadOm7ElQbxVsgOfOnRvjxo3LngFF469//WvccMMNMX78+Hj22Wdj6NChcfnl\nl8fmzZuzp0G91Ch7QEREly5dYuPGjR87tnv37qiqqoq5c+dG//79Y+bMmf/xOlu2bInKysr9ntu6\ndWvs2bPnkOyFT6O77ror7rjjjjjzzDMjIuJrX/tavPPOO/HYY4/F6NGjk9dB/VMQAZ45c2YMGTIk\nBg0aFFdffXVERMybNy+WLl0aP/jBD6JZs2a1uk5FRUXMnz9/v+d+85vfRNu2bQ/ZZvi0+fDDD6Nd\nu3YfO1ZaWhqrV69OWgT1W0EE+Pzzz49ly5bFqFGjYty4cfHAAw9E69ato3nz5nHCCSfU+jplZWVR\nVla233Njx46N9evXH6rJ8KnTo0eP+OEPfxgzZsyIiH/dZfrOd74Tc+fOTV4G9VNBBDgiomXLljFr\n1qx44okn4oILLogePXpEw4YNs2dB0Rg2bFjMnz8/evfuHf37948FCxbExIkTo1evXtnToF4qmAD/\n2+WXXx7nnXdejBw5Mrp37549B4pGw4YN47nnnouKiorYvHlzTJw4Mc4444zsWVBvFVyAI/71utTz\nzz+fPQOK0oUXXpg9AYgC/hgSABQzAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaA\nBAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIAB\nIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBg\nAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkE\nGAASCDAAJBBgAEggwACQQIABIIEAA0ACAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIIEAA0AC\nAQaABAIMAAkEGAASCDAAJBBgAEggwACQQIABIEGj7AGF7qWXXor3338/jjvuuOjTp0/2HACKRME+\nA967d29s27YtdcPVV18dTz31VJSUlMRdd90Vl112WVRXV6duAqA4FESA9+zZE1OmTIkhQ4bEG2+8\nEXPmzIm2bdvGUUcdFZdeemns2rWrzjeVl5fHW2+9FQ899FAMGjQofvGLX0TLli3jpz/9aZ1vAaD4\nFMQt6JtuuinefvvtOOOMM+KKK66IRo0axdy5c6O0tDTGjh0b8+bNiyuuuOI/Xmf27Nnx9NNP7/fc\nm2++GaWlpbXetHz58rjnnns+dmz48OHx+OOP1/oaAHAgBRHg+fPnx7Jly6Jly5bRpEmT+OCDD+LL\nX/5yRERMnjw5Jk6cWKsAX3bZZXHJJZfs99yTTz4ZO3bsqPWmli1bxurVq+P888/fd+z3v/99tGzZ\nstbXAIADKYgAn3TSSbFq1ao4++yz45prrom//e1v+86tWLEiOnfuXKvrNG7cOBo3brzfcy1btoy9\ne/fWetOwYcOirKws2rVrF2effXYsWrQoRowYEZWVlbW+BgAcSEEEeNy4cdGvX7/48Y9/HP369Yv2\n7dtHRMQtt9wSjzzySCxcuLDON7Vp0ybmzZsXN910U8yaNSvatGkT69ati1atWtX5FgCKT0EE+KKL\n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\nrkJggg==\n"
409 }
409 }
410 ],
410 ],
411 "prompt_number": 11
411 "prompt_number": 11
412 },
412 },
413 {
413 {
414 "cell_type": "markdown",
414 "cell_type": "markdown",
415 "metadata": {},
415 "metadata": {},
416 "source": [
416 "source": [
417 "Also, if the return value of a call to %R (in line mode) has just been printed to the console, then its value is also not returned."
417 "Also, if the return value of a call to %R (in line mode) has just been printed to the console, then its value is also not returned."
418 ]
418 ]
419 },
419 },
420 {
420 {
421 "cell_type": "code",
421 "cell_type": "code",
422 "collapsed": false,
422 "collapsed": false,
423 "input": [
423 "input": [
424 "v = %R print(X)\n",
424 "v = %R print(X)\n",
425 "assert v == None"
425 "assert v == None"
426 ],
426 ],
427 "language": "python",
427 "language": "python",
428 "metadata": {},
428 "metadata": {},
429 "outputs": [
429 "outputs": [
430 {
430 {
431 "output_type": "display_data",
431 "output_type": "display_data",
432 "text": [
432 "text": [
433 "[1] 0 1 2 3 4\n"
433 "[1] 0 1 2 3 4\n"
434 ]
434 ]
435 }
435 }
436 ],
436 ],
437 "prompt_number": 12
437 "prompt_number": 12
438 },
438 },
439 {
439 {
440 "cell_type": "markdown",
440 "cell_type": "markdown",
441 "metadata": {},
441 "metadata": {},
442 "source": [
442 "source": [
443 "But, if the last value did not print anything to console, the value is returned:\n"
443 "But, if the last value did not print anything to console, the value is returned:\n"
444 ]
444 ]
445 },
445 },
446 {
446 {
447 "cell_type": "code",
447 "cell_type": "code",
448 "collapsed": false,
448 "collapsed": false,
449 "input": [
449 "input": [
450 "v = %R print(summary(X)); X\n",
450 "v = %R print(summary(X)); X\n",
451 "print('v:', v)"
451 "print('v:', v)"
452 ],
452 ],
453 "language": "python",
453 "language": "python",
454 "metadata": {},
454 "metadata": {},
455 "outputs": [
455 "outputs": [
456 {
456 {
457 "output_type": "display_data",
457 "output_type": "display_data",
458 "text": [
458 "text": [
459 " Min. 1st Qu. Median Mean 3rd Qu. Max. \n",
459 " Min. 1st Qu. Median Mean 3rd Qu. Max. \n",
460 " 0 1 2 2 3 4 \n"
460 " 0 1 2 2 3 4 \n"
461 ]
461 ]
462 },
462 },
463 {
463 {
464 "output_type": "stream",
464 "output_type": "stream",
465 "stream": "stdout",
465 "stream": "stdout",
466 "text": [
466 "text": [
467 "v: [0 1 2 3 4]\n"
467 "v: [0 1 2 3 4]\n"
468 ]
468 ]
469 }
469 }
470 ],
470 ],
471 "prompt_number": 13
471 "prompt_number": 13
472 },
472 },
473 {
473 {
474 "cell_type": "markdown",
474 "cell_type": "markdown",
475 "metadata": {},
475 "metadata": {},
476 "source": [
476 "source": [
477 "The return value can be suppressed by a trailing ';' or an -n argument.\n"
477 "The return value can be suppressed by a trailing ';' or an -n argument.\n"
478 ]
478 ]
479 },
479 },
480 {
480 {
481 "cell_type": "code",
481 "cell_type": "code",
482 "collapsed": true,
482 "collapsed": true,
483 "input": [
483 "input": [
484 "%R -n X"
484 "%R -n X"
485 ],
485 ],
486 "language": "python",
486 "language": "python",
487 "metadata": {},
487 "metadata": {},
488 "outputs": [],
488 "outputs": [],
489 "prompt_number": 14
489 "prompt_number": 14
490 },
490 },
491 {
491 {
492 "cell_type": "code",
492 "cell_type": "code",
493 "collapsed": true,
493 "collapsed": true,
494 "input": [
494 "input": [
495 "%R X; "
495 "%R X; "
496 ],
496 ],
497 "language": "python",
497 "language": "python",
498 "metadata": {},
498 "metadata": {},
499 "outputs": [],
499 "outputs": [],
500 "prompt_number": 15
500 "prompt_number": 15
501 },
501 },
502 {
502 {
503 "cell_type": "heading",
503 "cell_type": "heading",
504 "level": 2,
504 "level": 2,
505 "metadata": {},
505 "metadata": {},
506 "source": [
506 "source": [
507 "Cell level magic"
507 "Cell level magic"
508 ]
508 ]
509 },
509 },
510 {
510 {
511 "cell_type": "markdown",
511 "cell_type": "markdown",
512 "metadata": {},
512 "metadata": {},
513 "source": [
513 "source": [
514 "Often, we will want to do more than a simple linear regression model. There may be several lines of R code that we want to \n",
514 "Often, we will want to do more than a simple linear regression model. There may be several lines of R code that we want to \n",
515 "use before returning to python. This is the cell-level magic.\n",
515 "use before returning to python. This is the cell-level magic.\n",
516 "\n",
516 "\n",
517 "\n",
517 "\n",
518 "For the cell level magic, inputs can be passed via the -i or --inputs argument in the line. These variables are copied \n",
518 "For the cell level magic, inputs can be passed via the -i or --inputs argument in the line. These variables are copied \n",
519 "from the shell namespace to R's namespace using rpy2.robjects.r.assign. It would be nice not to have to copy these into R: rnumpy ( http://bitbucket.org/njs/rnumpy/wiki/API ) has done some work to limit or at least make transparent the number of copies of an array. This seems like a natural thing to try to build on. Arrays can be output from R via the -o or --outputs argument in the line. All other arguments are sent to R's png function, which is the graphics device used to create the plots.\n",
519 "from the shell namespace to R's namespace using rpy2.robjects.r.assign. It would be nice not to have to copy these into R: rnumpy ( http://bitbucket.org/njs/rnumpy/wiki/API ) has done some work to limit or at least make transparent the number of copies of an array. This seems like a natural thing to try to build on. Arrays can be output from R via the -o or --outputs argument in the line. All other arguments are sent to R's png function, which is the graphics device used to create the plots.\n",
520 "\n",
520 "\n",
521 "We can redo the above calculations in one ipython cell. We might also want to add some output such as a summary\n",
521 "We can redo the above calculations in one ipython cell. We might also want to add some output such as a summary\n",
522 " from R or perhaps the standard plotting diagnostics of the lm."
522 " from R or perhaps the standard plotting diagnostics of the lm."
523 ]
523 ]
524 },
524 },
525 {
525 {
526 "cell_type": "code",
526 "cell_type": "code",
527 "collapsed": false,
527 "collapsed": false,
528 "input": [
528 "input": [
529 "%%R -i X,Y -o XYcoef\n",
529 "%%R -i X,Y -o XYcoef\n",
530 "XYlm = lm(Y~X)\n",
530 "XYlm = lm(Y~X)\n",
531 "XYcoef = coef(XYlm)\n",
531 "XYcoef = coef(XYlm)\n",
532 "print(summary(XYlm))\n",
532 "print(summary(XYlm))\n",
533 "par(mfrow=c(2,2))\n",
533 "par(mfrow=c(2,2))\n",
534 "plot(XYlm)"
534 "plot(XYlm)"
535 ],
535 ],
536 "language": "python",
536 "language": "python",
537 "metadata": {},
537 "metadata": {},
538 "outputs": [
538 "outputs": [
539 {
539 {
540 "output_type": "display_data",
540 "output_type": "display_data",
541 "text": [
541 "text": [
542 "\n",
542 "\n",
543 "Call:\n",
543 "Call:\n",
544 "lm(formula = Y ~ X)\n",
544 "lm(formula = Y ~ X)\n",
545 "\n",
545 "\n",
546 "Residuals:\n",
546 "Residuals:\n",
547 " 1 2 3 4 5 \n",
547 " 1 2 3 4 5 \n",
548 "-0.2 0.9 -1.0 0.1 0.2 \n",
548 "-0.2 0.9 -1.0 0.1 0.2 \n",
549 "\n",
549 "\n",
550 "Coefficients:\n",
550 "Coefficients:\n",
551 " Estimate Std. Error t value Pr(>|t|) \n",
551 " Estimate Std. Error t value Pr(>|t|) \n",
552 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
552 "(Intercept) 3.2000 0.6164 5.191 0.0139 *\n",
553 "X 0.9000 0.2517 3.576 0.0374 *\n",
553 "X 0.9000 0.2517 3.576 0.0374 *\n",
554 "---\n",
554 "---\n",
555 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1 \n",
555 "Signif. codes: 0 \u2018***\u2019 0.001 \u2018**\u2019 0.01 \u2018*\u2019 0.05 \u2018.\u2019 0.1 \u2018 \u2019 1 \n",
556 "\n",
556 "\n",
557 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
557 "Residual standard error: 0.7958 on 3 degrees of freedom\n",
558 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
558 "Multiple R-squared: 0.81,\tAdjusted R-squared: 0.7467 \n",
559 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739 \n",
559 "F-statistic: 12.79 on 1 and 3 DF, p-value: 0.03739 \n",
560 "\n"
560 "\n"
561 ]
561 ]
562 },
562 },
563 {
563 {
564 "output_type": "display_data",
564 "output_type": "display_data",
565 "png": "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\n"
565 "png": "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\n"
566 }
566 }
567 ],
567 ],
568 "prompt_number": 16
568 "prompt_number": 16
569 },
569 },
570 {
570 {
571 "cell_type": "heading",
571 "cell_type": "heading",
572 "level": 2,
572 "level": 2,
573 "metadata": {},
573 "metadata": {},
574 "source": [
574 "source": [
575 "Passing data back and forth"
575 "Passing data back and forth"
576 ]
576 ]
577 },
577 },
578 {
578 {
579 "cell_type": "markdown",
579 "cell_type": "markdown",
580 "metadata": {},
580 "metadata": {},
581 "source": [
581 "source": [
582 "Currently, data is passed through RMagics.pyconverter when going from python to R and RMagics.Rconverter when \n",
582 "Currently, data is passed through RMagics.pyconverter when going from python to R and RMagics.Rconverter when \n",
583 "going from R to python. These currently default to numpy.ndarray. Future work will involve writing better converters, most likely involving integration with http://pandas.sourceforge.net.\n",
583 "going from R to python. These currently default to numpy.ndarray. Future work will involve writing better converters, most likely involving integration with http://pandas.sourceforge.net.\n",
584 "\n",
584 "\n",
585 "Passing ndarrays into R seems to require a copy, though once an object is returned to python, this object is NOT copied, and it is possible to change its values.\n"
585 "Passing ndarrays into R seems to require a copy, though once an object is returned to python, this object is NOT copied, and it is possible to change its values.\n"
586 ]
586 ]
587 },
587 },
588 {
588 {
589 "cell_type": "code",
589 "cell_type": "code",
590 "collapsed": true,
590 "collapsed": true,
591 "input": [
591 "input": [
592 "seq1 = np.arange(10)"
592 "seq1 = np.arange(10)"
593 ],
593 ],
594 "language": "python",
594 "language": "python",
595 "metadata": {},
595 "metadata": {},
596 "outputs": [],
596 "outputs": [],
597 "prompt_number": 17
597 "prompt_number": 17
598 },
598 },
599 {
599 {
600 "cell_type": "code",
600 "cell_type": "code",
601 "collapsed": false,
601 "collapsed": false,
602 "input": [
602 "input": [
603 "%%R -i seq1 -o seq2\n",
603 "%%R -i seq1 -o seq2\n",
604 "seq2 = rep(seq1, 2)\n",
604 "seq2 = rep(seq1, 2)\n",
605 "print(seq2)"
605 "print(seq2)"
606 ],
606 ],
607 "language": "python",
607 "language": "python",
608 "metadata": {},
608 "metadata": {},
609 "outputs": [
609 "outputs": [
610 {
610 {
611 "output_type": "display_data",
611 "output_type": "display_data",
612 "text": [
612 "text": [
613 " [1] 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9\n"
613 " [1] 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9\n"
614 ]
614 ]
615 }
615 }
616 ],
616 ],
617 "prompt_number": 18
617 "prompt_number": 18
618 },
618 },
619 {
619 {
620 "cell_type": "code",
620 "cell_type": "code",
621 "collapsed": false,
621 "collapsed": false,
622 "input": [
622 "input": [
623 "seq2[::2] = 0\n",
623 "seq2[::2] = 0\n",
624 "seq2"
624 "seq2"
625 ],
625 ],
626 "language": "python",
626 "language": "python",
627 "metadata": {},
627 "metadata": {},
628 "outputs": [
628 "outputs": [
629 {
629 {
630 "output_type": "pyout",
630 "output_type": "pyout",
631 "prompt_number": 19,
631 "prompt_number": 19,
632 "text": [
632 "text": [
633 "array([0, 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 1, 0, 3, 0, 5, 0, 7, 0, 9], dtype=int32)"
633 "array([0, 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 1, 0, 3, 0, 5, 0, 7, 0, 9], dtype=int32)"
634 ]
634 ]
635 }
635 }
636 ],
636 ],
637 "prompt_number": 19
637 "prompt_number": 19
638 },
638 },
639 {
639 {
640 "cell_type": "code",
640 "cell_type": "code",
641 "collapsed": false,
641 "collapsed": false,
642 "input": [
642 "input": [
643 "%%R\n",
643 "%%R\n",
644 "print(seq2)"
644 "print(seq2)"
645 ],
645 ],
646 "language": "python",
646 "language": "python",
647 "metadata": {},
647 "metadata": {},
648 "outputs": [
648 "outputs": [
649 {
649 {
650 "output_type": "display_data",
650 "output_type": "display_data",
651 "text": [
651 "text": [
652 " [1] 0 1 0 3 0 5 0 7 0 9 0 1 0 3 0 5 0 7 0 9\n"
652 " [1] 0 1 0 3 0 5 0 7 0 9 0 1 0 3 0 5 0 7 0 9\n"
653 ]
653 ]
654 }
654 }
655 ],
655 ],
656 "prompt_number": 20
656 "prompt_number": 20
657 },
657 },
658 {
658 {
659 "cell_type": "markdown",
659 "cell_type": "markdown",
660 "metadata": {},
660 "metadata": {},
661 "source": [
661 "source": [
662 "Once the array data has been passed to R, modifring its contents does not modify R's copy of the data."
662 "Once the array data has been passed to R, modifring its contents does not modify R's copy of the data."
663 ]
663 ]
664 },
664 },
665 {
665 {
666 "cell_type": "code",
666 "cell_type": "code",
667 "collapsed": false,
667 "collapsed": false,
668 "input": [
668 "input": [
669 "seq1[0] = 200\n",
669 "seq1[0] = 200\n",
670 "%R print(seq1)"
670 "%R print(seq1)"
671 ],
671 ],
672 "language": "python",
672 "language": "python",
673 "metadata": {},
673 "metadata": {},
674 "outputs": [
674 "outputs": [
675 {
675 {
676 "output_type": "display_data",
676 "output_type": "display_data",
677 "text": [
677 "text": [
678 " [1] 0 1 2 3 4 5 6 7 8 9\n"
678 " [1] 0 1 2 3 4 5 6 7 8 9\n"
679 ]
679 ]
680 }
680 }
681 ],
681 ],
682 "prompt_number": 21
682 "prompt_number": 21
683 },
683 },
684 {
684 {
685 "cell_type": "markdown",
685 "cell_type": "markdown",
686 "metadata": {},
686 "metadata": {},
687 "source": [
687 "source": [
688 "But, if we pass data as both input and output, then the value of \"data\" in user_ns will be overwritten and the\n",
688 "But, if we pass data as both input and output, then the value of \"data\" in user_ns will be overwritten and the\n",
689 "new array will be a view of the data in R's copy."
689 "new array will be a view of the data in R's copy."
690 ]
690 ]
691 },
691 },
692 {
692 {
693 "cell_type": "code",
693 "cell_type": "code",
694 "collapsed": false,
694 "collapsed": false,
695 "input": [
695 "input": [
696 "print(seq1)\n",
696 "print(seq1)\n",
697 "%R -i seq1 -o seq1\n",
697 "%R -i seq1 -o seq1\n",
698 "print(seq1)\n",
698 "print(seq1)\n",
699 "seq1[0] = 200\n",
699 "seq1[0] = 200\n",
700 "%R print(seq1)\n",
700 "%R print(seq1)\n",
701 "seq1_view = %R seq1\n",
701 "seq1_view = %R seq1\n",
702 "assert(id(seq1_view.data) == id(seq1.data))"
702 "assert(id(seq1_view.data) == id(seq1.data))"
703 ],
703 ],
704 "language": "python",
704 "language": "python",
705 "metadata": {},
705 "metadata": {},
706 "outputs": [
706 "outputs": [
707 {
707 {
708 "output_type": "stream",
708 "output_type": "stream",
709 "stream": "stdout",
709 "stream": "stdout",
710 "text": [
710 "text": [
711 "[200 1 2 3 4 5 6 7 8 9]\n",
711 "[200 1 2 3 4 5 6 7 8 9]\n",
712 "[200 1 2 3 4 5 6 7 8 9]\n"
712 "[200 1 2 3 4 5 6 7 8 9]\n"
713 ]
713 ]
714 },
714 },
715 {
715 {
716 "output_type": "display_data",
716 "output_type": "display_data",
717 "text": [
717 "text": [
718 " [1] 200 1 2 3 4 5 6 7 8 9\n"
718 " [1] 200 1 2 3 4 5 6 7 8 9\n"
719 ]
719 ]
720 }
720 }
721 ],
721 ],
722 "prompt_number": 22
722 "prompt_number": 22
723 },
723 },
724 {
724 {
725 "cell_type": "heading",
725 "cell_type": "heading",
726 "level": 2,
726 "level": 2,
727 "metadata": {},
727 "metadata": {},
728 "source": [
728 "source": [
729 "Exception handling\n"
729 "Exception handling\n"
730 ]
730 ]
731 },
731 },
732 {
732 {
733 "cell_type": "markdown",
733 "cell_type": "markdown",
734 "metadata": {},
734 "metadata": {},
735 "source": [
735 "source": [
736 "Exceptions are handled by passing back rpy2's exception and the line that triggered it."
736 "Exceptions are handled by passing back rpy2's exception and the line that triggered it."
737 ]
737 ]
738 },
738 },
739 {
739 {
740 "cell_type": "code",
740 "cell_type": "code",
741 "collapsed": false,
741 "collapsed": false,
742 "input": [
742 "input": [
743 "try:\n",
743 "try:\n",
744 " %R -n nosuchvar\n",
744 " %R -n nosuchvar\n",
745 "except Exception as e:\n",
745 "except Exception as e:\n",
746 " print(e)\n",
746 " print(e)\n",
747 " pass"
747 " pass"
748 ],
748 ],
749 "language": "python",
749 "language": "python",
750 "metadata": {},
750 "metadata": {},
751 "outputs": [
751 "outputs": [
752 {
752 {
753 "output_type": "stream",
753 "output_type": "stream",
754 "stream": "stdout",
754 "stream": "stdout",
755 "text": [
755 "text": [
756 "parsing and evaluating line \"nosuchvar\".\n",
756 "parsing and evaluating line \"nosuchvar\".\n",
757 "R error message: \"Error in eval(expr, envir, enclos) : object 'nosuchvar' not found\n",
757 "R error message: \"Error in eval(expr, envir, enclos) : object 'nosuchvar' not found\n",
758 "\"\n",
758 "\"\n",
759 " R stdout:\"Error in eval(expr, envir, enclos) : object 'nosuchvar' not found\n",
759 " R stdout:\"Error in eval(expr, envir, enclos) : object 'nosuchvar' not found\n",
760 "\"\n",
760 "\"\n",
761 "\n"
761 "\n"
762 ]
762 ]
763 }
763 }
764 ],
764 ],
765 "prompt_number": 23
765 "prompt_number": 23
766 },
766 },
767 {
767 {
768 "cell_type": "heading",
768 "cell_type": "heading",
769 "level": 2,
769 "level": 2,
770 "metadata": {},
770 "metadata": {},
771 "source": [
771 "source": [
772 "Structured arrays and data frames\n"
772 "Structured arrays and data frames\n"
773 ]
773 ]
774 },
774 },
775 {
775 {
776 "cell_type": "markdown",
776 "cell_type": "markdown",
777 "metadata": {},
777 "metadata": {},
778 "source": [
778 "source": [
779 "In R, data frames play an important role as they allow array-like objects of mixed type with column names (and row names). In bumpy, the closest analogy is a structured array with named fields. In future work, it would be nice to use pandas to return full-fledged DataFrames from rpy2. In the mean time, structured arrays can be passed back and forth with the -d flag to %R, %Rpull, and %Rget"
779 "In R, data frames play an important role as they allow array-like objects of mixed type with column names (and row names). In bumpy, the closest analogy is a structured array with named fields. In future work, it would be nice to use pandas to return full-fledged DataFrames from rpy2. In the mean time, structured arrays can be passed back and forth with the -d flag to %R, %Rpull, and %Rget"
780 ]
780 ]
781 },
781 },
782 {
782 {
783 "cell_type": "code",
783 "cell_type": "code",
784 "collapsed": true,
784 "collapsed": true,
785 "input": [
785 "input": [
786 "datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],\n",
786 "datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],\n",
787 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])\n"
787 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])\n"
788 ],
788 ],
789 "language": "python",
789 "language": "python",
790 "metadata": {},
790 "metadata": {},
791 "outputs": [],
791 "outputs": [],
792 "prompt_number": 24
792 "prompt_number": 24
793 },
793 },
794 {
794 {
795 "cell_type": "code",
795 "cell_type": "code",
796 "collapsed": true,
796 "collapsed": true,
797 "input": [
797 "input": [
798 "%%R -i datapy -d datar\n",
798 "%%R -i datapy -d datar\n",
799 "datar = datapy"
799 "datar = datapy"
800 ],
800 ],
801 "language": "python",
801 "language": "python",
802 "metadata": {},
802 "metadata": {},
803 "outputs": [],
803 "outputs": [],
804 "prompt_number": 25
804 "prompt_number": 25
805 },
805 },
806 {
806 {
807 "cell_type": "code",
807 "cell_type": "code",
808 "collapsed": false,
808 "collapsed": false,
809 "input": [
809 "input": [
810 "datar"
810 "datar"
811 ],
811 ],
812 "language": "python",
812 "language": "python",
813 "metadata": {},
813 "metadata": {},
814 "outputs": [
814 "outputs": [
815 {
815 {
816 "output_type": "pyout",
816 "output_type": "pyout",
817 "prompt_number": 26,
817 "prompt_number": 26,
818 "text": [
818 "text": [
819 "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], \n",
819 "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], \n",
820 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])"
820 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])"
821 ]
821 ]
822 }
822 }
823 ],
823 ],
824 "prompt_number": 26
824 "prompt_number": 26
825 },
825 },
826 {
826 {
827 "cell_type": "code",
827 "cell_type": "code",
828 "collapsed": false,
828 "collapsed": false,
829 "input": [
829 "input": [
830 "%R datar2 = datapy\n",
830 "%R datar2 = datapy\n",
831 "%Rpull -d datar2\n",
831 "%Rpull -d datar2\n",
832 "datar2"
832 "datar2"
833 ],
833 ],
834 "language": "python",
834 "language": "python",
835 "metadata": {},
835 "metadata": {},
836 "outputs": [
836 "outputs": [
837 {
837 {
838 "output_type": "pyout",
838 "output_type": "pyout",
839 "prompt_number": 27,
839 "prompt_number": 27,
840 "text": [
840 "text": [
841 "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], \n",
841 "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], \n",
842 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])"
842 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])"
843 ]
843 ]
844 }
844 }
845 ],
845 ],
846 "prompt_number": 27
846 "prompt_number": 27
847 },
847 },
848 {
848 {
849 "cell_type": "code",
849 "cell_type": "code",
850 "collapsed": false,
850 "collapsed": false,
851 "input": [
851 "input": [
852 "%Rget -d datar2"
852 "%Rget -d datar2"
853 ],
853 ],
854 "language": "python",
854 "language": "python",
855 "metadata": {},
855 "metadata": {},
856 "outputs": [
856 "outputs": [
857 {
857 {
858 "output_type": "pyout",
858 "output_type": "pyout",
859 "prompt_number": 28,
859 "prompt_number": 28,
860 "text": [
860 "text": [
861 "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], \n",
861 "array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')], \n",
862 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])"
862 " dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])"
863 ]
863 ]
864 }
864 }
865 ],
865 ],
866 "prompt_number": 28
866 "prompt_number": 28
867 },
867 },
868 {
868 {
869 "cell_type": "markdown",
869 "cell_type": "markdown",
870 "metadata": {},
870 "metadata": {},
871 "source": [
871 "source": [
872 "For arrays without names, the -d argument has no effect because the R object has no colnames or names."
872 "For arrays without names, the -d argument has no effect because the R object has no colnames or names."
873 ]
873 ]
874 },
874 },
875 {
875 {
876 "cell_type": "code",
876 "cell_type": "code",
877 "collapsed": false,
877 "collapsed": false,
878 "input": [
878 "input": [
879 "Z = np.arange(6)\n",
879 "Z = np.arange(6)\n",
880 "%R -i Z\n",
880 "%R -i Z\n",
881 "%Rget -d Z"
881 "%Rget -d Z"
882 ],
882 ],
883 "language": "python",
883 "language": "python",
884 "metadata": {},
884 "metadata": {},
885 "outputs": [
885 "outputs": [
886 {
886 {
887 "output_type": "pyout",
887 "output_type": "pyout",
888 "prompt_number": 29,
888 "prompt_number": 29,
889 "text": [
889 "text": [
890 "array([0, 1, 2, 3, 4, 5], dtype=int32)"
890 "array([0, 1, 2, 3, 4, 5], dtype=int32)"
891 ]
891 ]
892 }
892 }
893 ],
893 ],
894 "prompt_number": 29
894 "prompt_number": 29
895 },
895 },
896 {
896 {
897 "cell_type": "markdown",
897 "cell_type": "markdown",
898 "metadata": {},
898 "metadata": {},
899 "source": [
899 "source": [
900 "For mixed-type data frames in R, if the -d flag is not used, then an array of a single type is returned and\n",
900 "For mixed-type data frames in R, if the -d flag is not used, then an array of a single type is returned and\n",
901 "its value is transposed. This would be nice to fix, but it seems something that should be fixed at the rpy2 level (See: https://bitbucket.org/lgautier/rpy2/issue/44/numpyrecarray-as-dataframe)"
901 "its value is transposed. This would be nice to fix, but it seems something that should be fixed at the rpy2 level (See: https://bitbucket.org/lgautier/rpy2/issue/44/numpyrecarray-as-dataframe)"
902 ]
902 ]
903 },
903 },
904 {
904 {
905 "cell_type": "code",
905 "cell_type": "code",
906 "collapsed": false,
906 "collapsed": false,
907 "input": [
907 "input": [
908 "%Rget datar2"
908 "%Rget datar2"
909 ],
909 ],
910 "language": "python",
910 "language": "python",
911 "metadata": {},
911 "metadata": {},
912 "outputs": [
912 "outputs": [
913 {
913 {
914 "output_type": "pyout",
914 "output_type": "pyout",
915 "prompt_number": 30,
915 "prompt_number": 30,
916 "text": [
916 "text": [
917 "array([['1', '2', '3'],\n",
917 "array([['1', '2', '3'],\n",
918 " ['2', '3', '2'],\n",
918 " ['2', '3', '2'],\n",
919 " ['a', 'b', 'c']], \n",
919 " ['a', 'b', 'c']], \n",
920 " dtype='|S1')"
920 " dtype='|S1')"
921 ]
921 ]
922 }
922 }
923 ],
923 ],
924 "prompt_number": 30
924 "prompt_number": 30
925 }
925 }
926 ],
926 ],
927 "metadata": {}
927 "metadata": {}
928 }
928 }
929 ]
929 ]
930 } No newline at end of file
930 }
@@ -1,512 +1,562 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": "Parallel MC Options"
3 "name": "",
4 "signature": "sha256:1b19dedc6473d4e886e549020c6710f2d14c17296168a02e7e7fa9673912b893"
4 },
5 },
5 "nbformat": 3,
6 "nbformat": 3,
6 "nbformat_minor": 0,
7 "nbformat_minor": 0,
7 "worksheets": [
8 "worksheets": [
8 {
9 {
9 "cells": [
10 "cells": [
10 {
11 {
11 "cell_type": "heading",
12 "cell_type": "heading",
12 "level": 1,
13 "level": 1,
13 "metadata": {},
14 "metadata": {},
14 "source": [
15 "source": [
15 "Parallel Monto-Carlo options pricing"
16 "Parallel Monto-Carlo options pricing"
16 ]
17 ]
17 },
18 },
18 {
19 {
19 "cell_type": "markdown",
20 "cell_type": "markdown",
20 "metadata": {},
21 "metadata": {},
21 "source": [
22 "source": [
22 "This notebook shows how to use `IPython.parallel` to do Monte-Carlo options pricing in parallel. We will compute the price of a large number of options for different strike prices and volatilities."
23 "This notebook shows how to use `IPython.parallel` to do Monte-Carlo options pricing in parallel. We will compute the price of a large number of options for different strike prices and volatilities."
23 ]
24 ]
24 },
25 },
25 {
26 {
26 "cell_type": "heading",
27 "cell_type": "heading",
27 "level": 2,
28 "level": 2,
28 "metadata": {},
29 "metadata": {},
29 "source": [
30 "source": [
30 "Problem setup"
31 "Problem setup"
31 ]
32 ]
32 },
33 },
33 {
34 {
34 "cell_type": "code",
35 "cell_type": "code",
35 "collapsed": false,
36 "collapsed": false,
36 "input": [
37 "input": [
37 "%pylab inline"
38 "%matplotlib inline\n",
39 "import matplotlib.pyplot as plt"
38 ],
40 ],
39 "language": "python",
41 "language": "python",
40 "metadata": {},
42 "metadata": {},
41 "outputs": [
43 "outputs": [],
42 {
44 "prompt_number": 1
43 "output_type": "stream",
44 "stream": "stdout",
45 "text": [
46 "\n",
47 "Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline].\n",
48 "For more information, type 'help(pylab)'.\n"
49 ]
50 }
51 ],
52 "prompt_number": 4
53 },
45 },
54 {
46 {
55 "cell_type": "code",
47 "cell_type": "code",
56 "collapsed": true,
48 "collapsed": true,
57 "input": [
49 "input": [
58 "import sys\n",
50 "import sys\n",
59 "import time\n",
51 "import time\n",
60 "from IPython.parallel import Client\n",
52 "from IPython.parallel import Client\n",
61 "import numpy as np"
53 "import numpy as np"
62 ],
54 ],
63 "language": "python",
55 "language": "python",
64 "metadata": {},
56 "metadata": {},
65 "outputs": [],
57 "outputs": [],
66 "prompt_number": 5
58 "prompt_number": 2
67 },
59 },
68 {
60 {
69 "cell_type": "markdown",
61 "cell_type": "markdown",
70 "metadata": {},
62 "metadata": {},
71 "source": [
63 "source": [
72 "Here are the basic parameters for our computation."
64 "Here are the basic parameters for our computation."
73 ]
65 ]
74 },
66 },
75 {
67 {
76 "cell_type": "code",
68 "cell_type": "code",
77 "collapsed": true,
69 "collapsed": true,
78 "input": [
70 "input": [
79 "price = 100.0 # Initial price\n",
71 "price = 100.0 # Initial price\n",
80 "rate = 0.05 # Interest rate\n",
72 "rate = 0.05 # Interest rate\n",
81 "days = 260 # Days to expiration\n",
73 "days = 260 # Days to expiration\n",
82 "paths = 10000 # Number of MC paths\n",
74 "paths = 10000 # Number of MC paths\n",
83 "n_strikes = 6 # Number of strike values\n",
75 "n_strikes = 6 # Number of strike values\n",
84 "min_strike = 90.0 # Min strike price\n",
76 "min_strike = 90.0 # Min strike price\n",
85 "max_strike = 110.0 # Max strike price\n",
77 "max_strike = 110.0 # Max strike price\n",
86 "n_sigmas = 5 # Number of volatility values\n",
78 "n_sigmas = 5 # Number of volatility values\n",
87 "min_sigma = 0.1 # Min volatility\n",
79 "min_sigma = 0.1 # Min volatility\n",
88 "max_sigma = 0.4 # Max volatility"
80 "max_sigma = 0.4 # Max volatility"
89 ],
81 ],
90 "language": "python",
82 "language": "python",
91 "metadata": {},
83 "metadata": {},
92 "outputs": [],
84 "outputs": [],
93 "prompt_number": 6
85 "prompt_number": 3
94 },
86 },
95 {
87 {
96 "cell_type": "code",
88 "cell_type": "code",
97 "collapsed": true,
89 "collapsed": true,
98 "input": [
90 "input": [
99 "strike_vals = np.linspace(min_strike, max_strike, n_strikes)\n",
91 "strike_vals = np.linspace(min_strike, max_strike, n_strikes)\n",
100 "sigma_vals = np.linspace(min_sigma, max_sigma, n_sigmas)"
92 "sigma_vals = np.linspace(min_sigma, max_sigma, n_sigmas)"
101 ],
93 ],
102 "language": "python",
94 "language": "python",
103 "metadata": {},
95 "metadata": {},
104 "outputs": [],
96 "outputs": [],
105 "prompt_number": 7
97 "prompt_number": 4
106 },
98 },
107 {
99 {
108 "cell_type": "code",
100 "cell_type": "code",
109 "collapsed": false,
101 "collapsed": false,
110 "input": [
102 "input": [
111 "print \"Strike prices: \", strike_vals\n",
103 "print \"Strike prices: \", strike_vals\n",
112 "print \"Volatilities: \", sigma_vals"
104 "print \"Volatilities: \", sigma_vals"
113 ],
105 ],
114 "language": "python",
106 "language": "python",
115 "metadata": {},
107 "metadata": {},
116 "outputs": [
108 "outputs": [
117 {
109 {
118 "output_type": "stream",
110 "output_type": "stream",
119 "stream": "stdout",
111 "stream": "stdout",
120 "text": [
112 "text": [
121 "Strike prices: [ 90. 94. 98. 102. 106. 110.]\n",
113 "Strike prices: [ 90. 94. 98. 102. 106. 110.]\n",
122 "Volatilities: [ 0.1 0.175 0.25 0.325 0.4 ]\n"
114 "Volatilities: [ 0.1 0.175 0.25 0.325 0.4 ]\n"
123 ]
115 ]
124 }
116 }
125 ],
117 ],
126 "prompt_number": 8
118 "prompt_number": 5
127 },
119 },
128 {
120 {
129 "cell_type": "heading",
121 "cell_type": "heading",
130 "level": 2,
122 "level": 2,
131 "metadata": {},
123 "metadata": {},
132 "source": [
124 "source": [
133 "Monte-Carlo option pricing function"
125 "Monte-Carlo option pricing function"
134 ]
126 ]
135 },
127 },
136 {
128 {
137 "cell_type": "markdown",
129 "cell_type": "markdown",
138 "metadata": {},
130 "metadata": {},
139 "source": [
131 "source": [
140 "The following function computes the price of a single option. It returns the call and put prices for both European and Asian style options."
132 "The following function computes the price of a single option. It returns the call and put prices for both European and Asian style options."
141 ]
133 ]
142 },
134 },
143 {
135 {
144 "cell_type": "code",
136 "cell_type": "code",
145 "collapsed": false,
137 "collapsed": false,
146 "input": [
138 "input": [
147 "def price_option(S=100.0, K=100.0, sigma=0.25, r=0.05, days=260, paths=10000):\n",
139 "def price_option(S=100.0, K=100.0, sigma=0.25, r=0.05, days=260, paths=10000):\n",
148 " \"\"\"\n",
140 " \"\"\"\n",
149 " Price European and Asian options using a Monte Carlo method.\n",
141 " Price European and Asian options using a Monte Carlo method.\n",
150 "\n",
142 "\n",
151 " Parameters\n",
143 " Parameters\n",
152 " ----------\n",
144 " ----------\n",
153 " S : float\n",
145 " S : float\n",
154 " The initial price of the stock.\n",
146 " The initial price of the stock.\n",
155 " K : float\n",
147 " K : float\n",
156 " The strike price of the option.\n",
148 " The strike price of the option.\n",
157 " sigma : float\n",
149 " sigma : float\n",
158 " The volatility of the stock.\n",
150 " The volatility of the stock.\n",
159 " r : float\n",
151 " r : float\n",
160 " The risk free interest rate.\n",
152 " The risk free interest rate.\n",
161 " days : int\n",
153 " days : int\n",
162 " The number of days until the option expires.\n",
154 " The number of days until the option expires.\n",
163 " paths : int\n",
155 " paths : int\n",
164 " The number of Monte Carlo paths used to price the option.\n",
156 " The number of Monte Carlo paths used to price the option.\n",
165 "\n",
157 "\n",
166 " Returns\n",
158 " Returns\n",
167 " -------\n",
159 " -------\n",
168 " A tuple of (E. call, E. put, A. call, A. put) option prices.\n",
160 " A tuple of (E. call, E. put, A. call, A. put) option prices.\n",
169 " \"\"\"\n",
161 " \"\"\"\n",
170 " import numpy as np\n",
162 " import numpy as np\n",
171 " from math import exp,sqrt\n",
163 " from math import exp,sqrt\n",
172 " \n",
164 " \n",
173 " h = 1.0/days\n",
165 " h = 1.0/days\n",
174 " const1 = exp((r-0.5*sigma**2)*h)\n",
166 " const1 = exp((r-0.5*sigma**2)*h)\n",
175 " const2 = sigma*sqrt(h)\n",
167 " const2 = sigma*sqrt(h)\n",
176 " stock_price = S*np.ones(paths, dtype='float64')\n",
168 " stock_price = S*np.ones(paths, dtype='float64')\n",
177 " stock_price_sum = np.zeros(paths, dtype='float64')\n",
169 " stock_price_sum = np.zeros(paths, dtype='float64')\n",
178 " for j in range(days):\n",
170 " for j in range(days):\n",
179 " growth_factor = const1*np.exp(const2*np.random.standard_normal(paths))\n",
171 " growth_factor = const1*np.exp(const2*np.random.standard_normal(paths))\n",
180 " stock_price = stock_price*growth_factor\n",
172 " stock_price = stock_price*growth_factor\n",
181 " stock_price_sum = stock_price_sum + stock_price\n",
173 " stock_price_sum = stock_price_sum + stock_price\n",
182 " stock_price_avg = stock_price_sum/days\n",
174 " stock_price_avg = stock_price_sum/days\n",
183 " zeros = np.zeros(paths, dtype='float64')\n",
175 " zeros = np.zeros(paths, dtype='float64')\n",
184 " r_factor = exp(-r*h*days)\n",
176 " r_factor = exp(-r*h*days)\n",
185 " euro_put = r_factor*np.mean(np.maximum(zeros, K-stock_price))\n",
177 " euro_put = r_factor*np.mean(np.maximum(zeros, K-stock_price))\n",
186 " asian_put = r_factor*np.mean(np.maximum(zeros, K-stock_price_avg))\n",
178 " asian_put = r_factor*np.mean(np.maximum(zeros, K-stock_price_avg))\n",
187 " euro_call = r_factor*np.mean(np.maximum(zeros, stock_price-K))\n",
179 " euro_call = r_factor*np.mean(np.maximum(zeros, stock_price-K))\n",
188 " asian_call = r_factor*np.mean(np.maximum(zeros, stock_price_avg-K))\n",
180 " asian_call = r_factor*np.mean(np.maximum(zeros, stock_price_avg-K))\n",
189 " return (euro_call, euro_put, asian_call, asian_put)"
181 " return (euro_call, euro_put, asian_call, asian_put)"
190 ],
182 ],
191 "language": "python",
183 "language": "python",
192 "metadata": {},
184 "metadata": {},
193 "outputs": [],
185 "outputs": [],
194 "prompt_number": 9
186 "prompt_number": 6
195 },
187 },
196 {
188 {
197 "cell_type": "markdown",
189 "cell_type": "markdown",
198 "metadata": {},
190 "metadata": {},
199 "source": [
191 "source": [
200 "We can time a single call of this function using the `%timeit` magic:"
192 "We can time a single call of this function using the `%timeit` magic:"
201 ]
193 ]
202 },
194 },
203 {
195 {
204 "cell_type": "code",
196 "cell_type": "code",
205 "collapsed": false,
197 "collapsed": false,
206 "input": [
198 "input": [
207 "%timeit -n1 -r1 print price_option(S=100.0, K=100.0, sigma=0.25, r=0.05, days=260, paths=10000)"
199 "%timeit -n1 -r1 print price_option(S=100.0, K=100.0, sigma=0.25, r=0.05, days=260, paths=10000)"
208 ],
200 ],
209 "language": "python",
201 "language": "python",
210 "metadata": {},
202 "metadata": {},
211 "outputs": [
203 "outputs": [
212 {
204 {
213 "output_type": "stream",
205 "output_type": "stream",
214 "stream": "stdout",
206 "stream": "stdout",
215 "text": [
207 "text": [
216 "(12.217720657772686, 7.4170971244322672, 6.8120985432589185, 4.3727039632512152)\n",
208 "(12.478072469211625, 7.5692079226372924, 6.9498346596114704, 4.5592719279729934)\n",
217 "1 loops, best of 1: 236 ms per loop\n"
209 "1 loops, best of 1: 111 ms per loop\n"
218 ]
210 ]
219 }
211 }
220 ],
212 ],
221 "prompt_number": 24
213 "prompt_number": 7
222 },
214 },
223 {
215 {
224 "cell_type": "markdown",
216 "cell_type": "markdown",
225 "metadata": {},
217 "metadata": {},
226 "source": [
218 "source": [
227 "## Parallel computation across strike prices and volatilities"
219 "## Parallel computation across strike prices and volatilities"
228 ]
220 ]
229 },
221 },
230 {
222 {
231 "cell_type": "markdown",
223 "cell_type": "markdown",
232 "metadata": {},
224 "metadata": {},
233 "source": [
225 "source": [
234 "The Client is used to setup the calculation and works with all engines."
226 "The Client is used to setup the calculation and works with all engines."
235 ]
227 ]
236 },
228 },
237 {
229 {
238 "cell_type": "code",
230 "cell_type": "code",
239 "collapsed": true,
231 "collapsed": true,
240 "input": [
232 "input": [
241 "c = Client(profile=\"default\")"
233 "rc = Client()"
242 ],
234 ],
243 "language": "python",
235 "language": "python",
244 "metadata": {},
236 "metadata": {},
245 "outputs": [],
237 "outputs": [],
246 "prompt_number": 12
238 "prompt_number": 8
247 },
239 },
248 {
240 {
249 "cell_type": "markdown",
241 "cell_type": "markdown",
250 "metadata": {},
242 "metadata": {},
251 "source": [
243 "source": [
252 "A `LoadBalancedView` is an interface to the engines that provides dynamic load\n",
244 "A `LoadBalancedView` is an interface to the engines that provides dynamic load\n",
253 "balancing at the expense of not knowing which engine will execute the code."
245 "balancing at the expense of not knowing which engine will execute the code."
254 ]
246 ]
255 },
247 },
256 {
248 {
257 "cell_type": "code",
249 "cell_type": "code",
258 "collapsed": true,
250 "collapsed": true,
259 "input": [
251 "input": [
260 "view = c.load_balanced_view()"
252 "view = rc.load_balanced_view()"
261 ],
253 ],
262 "language": "python",
254 "language": "python",
263 "metadata": {},
255 "metadata": {},
264 "outputs": [],
256 "outputs": [],
265 "prompt_number": 13
257 "prompt_number": 9
266 },
258 },
267 {
259 {
268 "cell_type": "markdown",
260 "cell_type": "markdown",
269 "metadata": {},
261 "metadata": {},
270 "source": [
262 "source": [
271 "Submit tasks for each (strike, sigma) pair. Again, we use the `%%timeit` magic to time the entire computation."
263 "Submit tasks for each (strike, sigma) pair. Again, we use the `%%timeit` magic to time the entire computation."
272 ]
264 ]
273 },
265 },
274 {
266 {
275 "cell_type": "code",
267 "cell_type": "code",
268 "collapsed": false,
269 "input": [
270 "async_results = []"
271 ],
272 "language": "python",
273 "metadata": {},
274 "outputs": [],
275 "prompt_number": 16
276 },
277 {
278 "cell_type": "code",
276 "collapsed": true,
279 "collapsed": true,
277 "input": [
280 "input": [
278 "%%timeit -n1 -r1\n",
281 "%%timeit -n1 -r1\n",
279 "\n",
282 "\n",
280 "async_results = []\n",
281 "for strike in strike_vals:\n",
283 "for strike in strike_vals:\n",
282 " for sigma in sigma_vals:\n",
284 " for sigma in sigma_vals:\n",
283 " # This line submits the tasks for parallel computation.\n",
285 " # This line submits the tasks for parallel computation.\n",
284 " ar = view.apply_async(price_option, price, strike, sigma, rate, days, paths)\n",
286 " ar = view.apply_async(price_option, price, strike, sigma, rate, days, paths)\n",
285 " async_results.append(ar)\n",
287 " async_results.append(ar)\n",
286 "\n",
288 "\n",
287 "c.wait(async_results) # Wait until all tasks are done."
289 "rc.wait(async_results) # Wait until all tasks are done."
288 ],
290 ],
289 "language": "python",
291 "language": "python",
290 "metadata": {},
292 "metadata": {},
291 "outputs": [
293 "outputs": [
292 {
294 {
293 "output_type": "stream",
295 "output_type": "stream",
294 "stream": "stdout",
296 "stream": "stdout",
295 "text": [
297 "text": [
296 "1 loops, best of 1: 3.75 s per loop\n"
298 "1 loops, best of 1: 810 ms per loop\n"
297 ]
299 ]
298 }
300 }
299 ],
301 ],
300 "prompt_number": 16
302 "prompt_number": 17
301 },
303 },
302 {
304 {
303 "cell_type": "code",
305 "cell_type": "code",
304 "collapsed": false,
306 "collapsed": false,
305 "input": [
307 "input": [
306 "len(async_results)"
308 "len(async_results)"
307 ],
309 ],
308 "language": "python",
310 "language": "python",
309 "metadata": {},
311 "metadata": {},
310 "outputs": [
312 "outputs": [
311 {
313 {
314 "metadata": {},
312 "output_type": "pyout",
315 "output_type": "pyout",
313 "prompt_number": 18,
316 "prompt_number": 18,
314 "text": [
317 "text": [
315 "30"
318 "30"
316 ]
319 ]
317 }
320 }
318 ],
321 ],
319 "prompt_number": 18
322 "prompt_number": 18
320 },
323 },
321 {
324 {
322 "cell_type": "markdown",
325 "cell_type": "markdown",
323 "metadata": {},
326 "metadata": {},
324 "source": [
327 "source": [
325 "## Process and visualize results"
328 "## Process and visualize results"
326 ]
329 ]
327 },
330 },
328 {
331 {
329 "cell_type": "markdown",
332 "cell_type": "markdown",
330 "metadata": {},
333 "metadata": {},
331 "source": [
334 "source": [
332 "Retrieve the results using the `get` method:"
335 "Retrieve the results using the `get` method:"
333 ]
336 ]
334 },
337 },
335 {
338 {
336 "cell_type": "code",
339 "cell_type": "code",
337 "collapsed": true,
340 "collapsed": true,
338 "input": [
341 "input": [
339 "results = [ar.get() for ar in async_results]"
342 "results = [ar.get() for ar in async_results]"
340 ],
343 ],
341 "language": "python",
344 "language": "python",
342 "metadata": {},
345 "metadata": {},
343 "outputs": [],
346 "outputs": [],
344 "prompt_number": 19
347 "prompt_number": 19
345 },
348 },
346 {
349 {
347 "cell_type": "markdown",
350 "cell_type": "markdown",
348 "metadata": {},
351 "metadata": {},
349 "source": [
352 "source": [
350 "Assemble the result into a structured NumPy array."
353 "Assemble the result into a structured NumPy array."
351 ]
354 ]
352 },
355 },
353 {
356 {
354 "cell_type": "code",
357 "cell_type": "code",
355 "collapsed": true,
358 "collapsed": true,
356 "input": [
359 "input": [
357 "prices = np.empty(n_strikes*n_sigmas,\n",
360 "prices = np.empty(n_strikes*n_sigmas,\n",
358 " dtype=[('ecall',float),('eput',float),('acall',float),('aput',float)]\n",
361 " dtype=[('ecall',float),('eput',float),('acall',float),('aput',float)]\n",
359 ")\n",
362 ")\n",
360 "\n",
363 "\n",
361 "for i, price in enumerate(results):\n",
364 "for i, price in enumerate(results):\n",
362 " prices[i] = tuple(price)\n",
365 " prices[i] = tuple(price)\n",
363 "\n",
366 "\n",
364 "prices.shape = (n_strikes, n_sigmas)"
367 "prices.shape = (n_strikes, n_sigmas)"
365 ],
368 ],
366 "language": "python",
369 "language": "python",
367 "metadata": {},
370 "metadata": {},
368 "outputs": [],
371 "outputs": [],
369 "prompt_number": 20
372 "prompt_number": 20
370 },
373 },
371 {
374 {
372 "cell_type": "markdown",
375 "cell_type": "markdown",
373 "metadata": {},
376 "metadata": {},
374 "source": [
377 "source": [
375 "Plot the value of the European call in (volatility, strike) space."
378 "Plot the value of the European call in (volatility, strike) space."
376 ]
379 ]
377 },
380 },
378 {
381 {
379 "cell_type": "code",
382 "cell_type": "code",
380 "collapsed": false,
383 "collapsed": false,
381 "input": [
384 "input": [
382 "plt.figure()\n",
385 "plt.figure()\n",
383 "plt.contourf(sigma_vals, strike_vals, prices['ecall'])\n",
386 "plt.contourf(sigma_vals, strike_vals, prices['ecall'])\n",
384 "plt.axis('tight')\n",
387 "plt.axis('tight')\n",
385 "plt.colorbar()\n",
388 "plt.colorbar()\n",
386 "plt.title('European Call')\n",
389 "plt.title('European Call')\n",
387 "plt.xlabel(\"Volatility\")\n",
390 "plt.xlabel(\"Volatility\")\n",
388 "plt.ylabel(\"Strike Price\")"
391 "plt.ylabel(\"Strike Price\")"
389 ],
392 ],
390 "language": "python",
393 "language": "python",
391 "metadata": {},
394 "metadata": {},
392 "outputs": [
395 "outputs": [
393 {
396 {
397 "metadata": {},
394 "output_type": "pyout",
398 "output_type": "pyout",
395 "prompt_number": 21,
399 "prompt_number": 21,
396 "text": [
400 "text": [
397 "<matplotlib.text.Text at 0x10ab98690>"
401 "<matplotlib.text.Text at 0x1100a3290>"
398 ]
402 ]
399 },
403 },
400 {
404 {
405 "metadata": {
406 "png": {
407 "height": 407,
408 "width": 563
409 }
410 },
401 "output_type": "display_data",
411 "output_type": "display_data",
402 "png": "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\n"
412 "png": "iVBORw0KGgoAAAANSUhEUgAABGcAAAMvCAYAAAB/e73nAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAWJQAAFiUBSVIk8AAAIABJREFUeJzs3Xm4LGdd7+3vzkAgzCAgMhgIiIKCYQyRIYYAMijTeQwc\nDRAEQXyRQURBD5GjoExCZJR5UDE8ckBAICSQGGRUmafDwQwMBhPAQCIh097vH9WL3VlZQ6/u6q6q\n7vu+rn3V6tXVVbVWcmH2x189lQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCi7R79ef0G7x009v6xC7wmAGAC+3R9AQCwIIdn719O\nd/LHX2SZxO2S/GmSDyf5epIfJvlBkm8kef/ovTst6Fr2zPg+ALBg+3V9AQDQke3+grprtI+/yLKV\nn0lyXJIj131/T5p/h35i9OfIJM9I8pUkf5nk5Qu8RgCg58QZAFbRa5L83YT7nj7PC2HQfjnJ3ya5\n8uj1fyR5W5JPJPlOkqsmuWGSX0xyRJIDk/xUkmdHnAEAAGAFHZ69tyo9rdtLYQncPskFaf59ujRN\ncDlgi/2vmeRZSc5L8t05XdPav9+v2+C9g8bef+aczg8ATMmaMwAAO7N/kuOzN8Y8OckfJrlwi8/8\nV5r1iw5J8rG5Xh0AMDjiDADszCOzdwLh7tvse8Zov5M3eX/903VukuQvknwxzWKylyQ5cYPPXTHJ\nE5J8MMl/JrlotD0xyW+liQebOSiXXex4V5IHJXlrmoVsL0xydpJ/SHM7ziQOSvK8JJ9KEyEuTHOL\nzzuS/I9tPntUklckOTXN4rkXpPm5v5fks0leneSu2xzjlNHPs3YL2o+n+dk+keTcNIvzfnl0jdea\n8GfayiPS/LNKknenWUNmUl9Nct913zsgyZOSvDnJvyQ5J83v8KIk307y0SR/luSm018yAAAAdO/w\ntHNb0yOz91aWu22z7xmjfT+4yftr13N8mnBw8dj3Lh1tP7nuMz+XJkLs3mDftT//N8nNNznnQWP7\nvS3JZ9Z9dv2fp2/zMz41TUjY6npOSLP+yka+usE5139+d5JXpglJGzlltM/Xk/xxmhiz2c/z1STX\n2+Zn2s6Hx67zDjMeK2nWpdnoWtf/Hn6Y5JgtjuO2JgAYKAsCA0D3ymj7/TQLzJ6aZl2Saya52th+\nP5nkn5JcI83TgN6ZZjrlP5NcP82Uyn3ShJkPJfn5JN/a4rwPGm2/nOQtaSZVkiZkPS7NRMezk3w6\nyXs3+PwfZ+9f9L+S5A1JvpAmMt0kyf9M8gtJ7jl67yEbHOPS0WdOHV3Ht9JMzVw9yW3S/G5unuQ3\nk3w+yUu3+HluMLqeS9L8Xt6V5KzR9x+T5I5ppk9enORhWxxnK1cZHSdpJn3+ZcrjrHdRkn9N88/t\njDS/h4uSXDvJoWmu95pJXpUm2H2mpfMCAADAwhyevZMDr05yjzSPN97uz03WHeeRaX9yZneSv07y\nY9sc74Sxcz98k30eP3bMv9/g/YPG3v/2Fse5W/ZO8nx2g/d/IZf9fW72//B5ydh+h23w/oGbfG7N\nFZN8bvT5L22yzylj5zgxyS022OcKY8e5KE3gmsahY+ea9Ilf29knWy8mnCQHZ+8CxK/YZB+TMwAA\nAPTa4dn69p3N/hy77jiPTPtx5m0TXP/Pju3/lm32fdfYNR687r2DMvlf0v9mbN9br3vvvaPvfzpb\nr2F3YJLzR/set835NvNn2fvzbBRzThm9/7VtjvP7Y8c5YspruX/2/k5eNOUxpvXR0Xk/scn74gwA\nDJTbmgBYVXta3m8W35tgn/uMfb3RX77HvTbJ/dKs0XLvJC+f8rrekb23/xyavRM0V00zVZQkb0rz\nF/7N/CDNAse3T/Okos38TJJfTnMr082TXDfNbTwHpJl6WXOt0TE3cskWx0+SM0fbXUmus82+m7n6\n2NfnTXmMzeyTZvHjI9OsLXRQmuu8Wprfw9p/t7WxqDEA0CPiDACr6A/SLMA7JLcZbfekWZtkK+Pv\n32bTvbb35bGvxydwbptk39HXLxj9mcR1N/jeLZO8LJs/+Wp9HJvlSZP/Nfb1drcRbeb7Y19vtsjx\nNO6fZrJo/W10a8Z/D562CQBLRpwBgGG49mi7O5eNDBs5Z4PPTWP8POMTI+sjy3bTRWtPWbrCuu/f\nOs1CwGuLHv9w9PozaW5R+naa6ZSHJvn1yS55Sxe2cIzx3+1PtHC8pLlVbnwa6ttpbtX6UppFh7+T\nZlroz3P528sAgCUgzgAAm9l/7OvxsLHv2NfPS/L+CY93wbrXL8neMPM3SZ6UJkSsd8cNvteVL6cJ\nZPukWRR5VldL8pejry9J8ow0EzQXb7DvH7RwPgCgh8QZAJjeIm8v+fbYOX9s7PVGrjf29UaxY1LX\n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\neVGSc5O8M8n3k9w9yTOT3KOUckSt9eINPnpekr/a5LBnTv0DwJSEGegPYQbaY2oGdsbUDOzMThpC\nKeUKSU5I0wz+PcnfJbkoyR2TPDnJMaWUw2utn53lmpYiziS5UZqKtWmQWVNKuUGSP09yTpLb11q/\nPvr+riRvSfKrSR6b5KUbfPx7tdantXXRMAthBvpDmIH2CDOwM8IMTGXihpDk0WnCzFtrrQ8df6OU\n8tQkz0vTGO47ywUtxZoztdZTaq371Fr3TXLENrsfleY2pleuhZnRMfYkecbo5THzuVKY3enfOk+Y\ngR4RZqA9wgzsjDAD09lhQ7j1aPuWDd575Wh701mvaSnizDq7tnl/bV2Yj65/o9Z6WpKzk9ymlHLF\nti8MZiXKQL8IM9AeYQZ2RpiB1mzXEL4w2h5TSll/99HBo+3l+sJOLcttTTuxVrTO3uT9bya5TpKb\nJPnSuvduUEq5MM3v7fwk/y/J25McV2s9fw7XCj8izEC/CDPQHmEGgB57dZKHJPmVJJ8rpRyXpKYZ\ndnl1kq8l+aNZT7KMkzPbuWqa+8q+v8n7P0hTzq627vufSvM0p1elGV36UJJbJfmTJB8vpVx9LlcL\nEWagb4QZaI8wAztnagYWp9b6wyRHJjklyS2SvDzJt5J8NU1fuGOt9ZuznmcVJ2fWXLLJ9zccaaq1\n3m7990op10mzavPPJ3l6kj9o7epgRJiBfhFmoD3CDOycMAOLVUq5SpJ/SHLLNE9o+mGSByb5tTSx\n5p9KKaXW+vlZzrOKkzPnpQkwV9rk/QPH9ttSrfWcJE8avdxuESHYMWEG+kWYgfYIM7Bzwgx04nlJ\nfjHJ42qt/1pr/Xyt9U/TxJrfTHLzJCeUUq46y0lWcXLm9CSHJPnJXH5NmSS5QZLdo/0m8d3R9iqz\nXxrsJcxAvwgz0B5hBnZOmKGPrnDrG3R9CYtQ0iyN8v7xb46e+PyaUspDktw7yV2TvGfak6zi5MxH\nRtvLTbqUUm6eZjHgz9daL5jweIeMthuFHpiKMAP9IsxAe4QZ2DlhBjp1wGh7403e33fddiqrGGfe\nmuSiJI8opfwo85VS9kmzuG+SvHH8A6WUx5ZS7rb+QKWUGyZ5dpqK9pq5XTErRZiBfhFmoD3CDAAD\n9N40S6O8ZP2tS6WUI5McnuS/0iwYPLWluK1pFEkeOnq59pzxW5ZSnjr6+nO11hOSpNb6jVLKHyZ5\n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\neWCSH0xy/STfSvLpJH+c5Pha65WbvM85amKWeUw5R01TF38/X/fZRyc5OslHt/p7uvPU6rr2sgcw\nFqWUByT5cJL9kvx5krOS/HCSpyf5T6WU+9daz5zxsw5M8tIkN0tyeJr/6a/xF4gN7/mpJDXJJUne\nm+SrSe6T5LlJfqzd/zd2/ytjWZZ9TK3zziRnb7HOHwAjsshjKskbk9wiyd8neUuSK9Kcc56a5LGl\nlIfXWk/esH/nqYlZ9jG1jvPUBCz4eHplkgck+XiSdyS5MMl/THJEkocneViSp23Yv3PUxCz7mFrH\nOWoiFnxMbfzsZ6YJM8kWf093nlpt4szs3pTkOkkeU2t9/9qLpZSjkvzPJK9K8tgZP+vAJEdlxm+e\nSynXT/J7SS5Nclit9dPr1r0yyS8n+Y12yXgs7Zja4Nha61/N8T6GZ5HH1LFJ/mjjvxCVUl6U5MVJ\nXp3mX5TWXneemqalHVMb3+s8NQmLPJ5ek+TjtdZz1r9YSrljklOSPKWU8txa6zfb152jpmlpx9QG\nzlHTschj6t+VUn4iyeuTvD/Jj2+xjfPUitu37AGMQSnlnknunGb62fvXr6u1vj7Jl5I8ppRy41k+\nr9Z6Zq11X611vyS3m+Etj0py0+atV/1P2jomTVl9cinF7+dIDOCYYmI6OKZessXU3de2y3tteN15\namIGcEwxIR0cT3+y8Zvo1hlpzjcXJvnOutedoyZmAMcUE7PoY2rd5z4oyduTvC/JL26zqfPUivMb\nO5sHtMuTtlh/YppZSPeb47Nnue/PlvuvtV6Y5LNp/ke+wxz7ZzmWfUztZXuGqctjar3rt8uvz7p/\n56nRWvYxtZ7z1Ph1ejyVUm7Y3jPkf6f5++2RtdbLZ9m/c9RoLfuYWs85ahoWfkyVUu6U5vKkTyZ5\nXJpLene9f+ep1eCyptmszUT42hbr1yr7IQPY/2kdjYHFWvYxtd77SinXSTOF8itJPpLk1bXWz/Ww\nbxanr2Pqce3yI3vYv/PUOCz7mFrPeWr8OjueSimfSXLX9ssPJbnrJjeYdo6anmUfU+s5R03DQo+p\nUsqtk3wgzTHx6FrrpaWURe3feWqCzJyZzQ3a5be2WH9Ru7zhRPfP4g3h9/ScNCX/zUl+N8mfpLn5\n2VOSnNw+WYXx6PyYKqXcLskL0/zl83/0vX96t+xjKnGempIuj6fjkrwhyV+luSn+O9p/re5r/yzH\nso+pxDlqahZ2TLWXPn0gzayqR854E1/nqRVn5szufG+L1/uayrjs/bN4S/s9rbW+YONr7TWsICTM\nhQAADBlJREFUR6f5ZumNpZTb1Fq3m37J8HRyTJVSbpXkg0lulORnaq2n9Ll/lmppx5Tz1CQt/Hiq\ntf7O2s9LKfdJ8ndJ3l1KuWut9ZKu98/SLe2Yco6arD0dU+0x8J4kt0rykFrrl/rcP+Nl5sxsvt0u\nr7fF+utv2G5q+2fxBvl7Wmu9otZ6dJIzk9wyzaMDGYfOjqlSysFJ/ibNNNrn1Frf3Of+WZplH1Ob\ncp4arV7OEe3j2P86yQ/m6k//co6anmUfU1tt7xw1Xos6pm6Y5EFJPpfkaaWUV639SPLr7TaHtK+9\npIP9M1JmzszmjHZ52y3WH9QuT5/o/lm8of+enp/k4CTft6T9s3udHFPtvxi+N83shifXWt/W5/5Z\nqmUfUztxnhqXPs8R57fL9U9UcY6anmUfU7O85+A4R43Joo+pw5I8eJvPen6SbyR5UUf7Z2TEmdmc\n2C4fvnFFO23tgUkuT3Jyh/t/frv/N27Y/w3T3LDs/CT/3NH+WbxlH1NbKqVcP8kPpZlSud3N7xiW\nhR9TpZTHprmO/uIkR9Ra/3aH/TtPTcuyj6ntPsd5anx6+XOvlHKtXHUj1zPWrXKOmp5lH1Pbvcc5\napwWcky195fZ9AqVUspt0xxHf1dr3TgTy3lqxbmsaQa11k8lOTXJvUopR2xYfWSaivn+Wuu/Pwa0\nlHJ8KeW0UspvLmAIH0hyXpJHl1LusmHdC5MckOStrmcdj2UfU6WUu5VSntP+5WH96/vS3NDu+5L8\naa31gr3ui34s+pgqpbw0yTuTfCHJfWb4Jtp5amKWfUw5T03LIo+nUsoPl1JeU0q5xSa7+o0kd0py\nSq31E+ted46amGUfU85R09PT38+3u2+M89SKM3Nmds9K8pdJ3ltKeV+SL6Up4ocnOTdN5VzvNmme\nQX+Nk3wp5Qbt5yVXTY+8dSnll9ufn11rfefa9rXWi0opRyV5e5ITSynvTfL1JPdM8oA0f9E9Zs+/\nQvq2tGOq3eZ3k7yslPK3aQr+DdMcT/9Pks8n+YU9/epYhoUcU6WUhyR5QZp/8TsxyVFbPPrxE2vH\nlfPUZC3tmIrz1BQt6s+9A5I8L8kvlFI+nuSUJNdJcv8kd2w/67+uf4Nz1GQt7ZiKc9RULezv57vl\n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\n12+rtX6ng3EBACQxcwYARqfWelKSM9svH9IuT9hi2/cl+ZU0AebnkpxRSrk8yZdzVZj57VrrsbsY\nwi8muSjJndJcAnRp+/VfJ3lYkvdv8973JvnH9uevTfKNNDNb/jzNU5L26hr3u6m1fi1XXYL1lDS/\n9m+2Y7/fJttflKv+e7oRMADQOXEGAMZpfTz4apK/3GrDWuurkzwgzeVQX07y3TQ3/31PkiNqrb+8\nxVuvzFWPx17/eSe3n/feNJdTfTfJGUl+L8ldkvzWNmP5bpKHp4klX2nf+9UkH06yNmvmGvvcaUwb\n1m/mqDSXdn0hyWVJLkjyiSSnb7H92uufqrV+apv9AQDs2ZifpgAAsHDtE6k+n+QHkzyz1voHSx4S\nADBxZs4AAFzdI9OEmW9li8vFAAAWSZwBALi6o9rlCe39ZwAAOiXOAAC0SimHJPnxuBEwANAjcQYA\n4CpHprkn39/XWv9h2YMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAYnv8LTrFLgrpADnoAAAAASUVORK5CYII=\n",
413 "text": [
414 "<matplotlib.figure.Figure at 0x10ffc7c10>"
415 ]
403 }
416 }
404 ],
417 ],
405 "prompt_number": 21
418 "prompt_number": 21
406 },
419 },
407 {
420 {
408 "cell_type": "markdown",
421 "cell_type": "markdown",
409 "metadata": {},
422 "metadata": {},
410 "source": [
423 "source": [
411 "Plot the value of the Asian call in (volatility, strike) space."
424 "Plot the value of the Asian call in (volatility, strike) space."
412 ]
425 ]
413 },
426 },
414 {
427 {
415 "cell_type": "code",
428 "cell_type": "code",
416 "collapsed": false,
429 "collapsed": false,
417 "input": [
430 "input": [
418 "plt.figure()\n",
431 "plt.figure()\n",
419 "plt.contourf(sigma_vals, strike_vals, prices['acall'])\n",
432 "plt.contourf(sigma_vals, strike_vals, prices['acall'])\n",
420 "plt.axis('tight')\n",
433 "plt.axis('tight')\n",
421 "plt.colorbar()\n",
434 "plt.colorbar()\n",
422 "plt.title(\"Asian Call\")\n",
435 "plt.title(\"Asian Call\")\n",
423 "plt.xlabel(\"Volatility\")\n",
436 "plt.xlabel(\"Volatility\")\n",
424 "plt.ylabel(\"Strike Price\")"
437 "plt.ylabel(\"Strike Price\")"
425 ],
438 ],
426 "language": "python",
439 "language": "python",
427 "metadata": {},
440 "metadata": {},
428 "outputs": [
441 "outputs": [
429 {
442 {
443 "metadata": {},
430 "output_type": "pyout",
444 "output_type": "pyout",
431 "prompt_number": 22,
445 "prompt_number": 22,
432 "text": [
446 "text": [
433 "<matplotlib.text.Text at 0x1088bf150>"
447 "<matplotlib.text.Text at 0x11009b3d0>"
434 ]
448 ]
435 },
449 },
436 {
450 {
451 "metadata": {
452 "png": {
453 "height": 407,
454 "width": 562
455 }
456 },
437 "output_type": "display_data",
457 "output_type": "display_data",
438 "png": "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\ntm7dioMHDyI6OhpxcXHIyspCVVUVsrKyEB9v379WRERGdPfddwO4dcVGSUkJvvzyS8TFxTm8jknW\n8LA0MTERpaWl8PHxwVtvvYXY2FhxL6UjIrIiLy8PEydOxG+//YapU6di6tSpji8i6ygvL08ODQ2V\nQ0JC5CVLltS6vbi4WI6Pj5ebNGkiL1iwwKF9XUXJzO3atZMjIiLkyMhIOSYmRquRbc68atUquXPn\nznLnzp3l1NRU+T//+Y/d+xptXqM+x59++qncuXNnuUuXLvLjjz8uFxYW2r2vEWfW43m293kqLCyU\nGzRoIH/00UcO72skusY5MjJSzsvLk0tKSuSOHTvK586dq3F7aWmpvHv3bnn27Nm1QmdrXyPO3L59\ne/n8+fOazFmdrZm//fZb+ZdffpFlWZbfffddedSoUXbva7R5jfocX7582fK92WyWExIS7N7XiDPr\n8Tzb8zxdv35dTkpKkvv3718jzno9x0poes65uurXArZr185yLWB1/v7+6NatGxo1auTwvkab+TZZ\n4xc37Zm5e/fulvNk/fv3R15ent37Gmne24z4HDdr1qzG/b29ve3e12gz36bl82zv8/Tmm29i2LBh\n8Pf3d3hfo9EtztauBXT1vkoofVyTyYTk5GQMHjwYOTk5rhixFkdnXr58ueWKGj2eZyXzAsZ+jtev\nX4/27dsjLS0NK1ascGhfI8y8fPlyy3atn2d75j19+jQ2bNiA9PR0y4z27mtE/OAjDeXn56Nt27Yo\nLi7GgAEDEBsbizZt2ug9lsXWrVuxatUqfPvtt3qPYpe65jXyczxkyBAMGTIE69atw+DBg7Fv3z69\nR7Kp+sxDhgyxzGzE53n69Ol49dVXYTKZIN86ZavrPErpduQcExODw4cPW34+dOiQ3ZfRKdlXCaWP\n27ZtWwBAWFgYBg4ciM8++0z1Ge9k78zff/89Jk6ciJycHLRs2dKhfY0yL2Ds5/i2p556CmfOnEFV\nVRW6desmxH/L1WcGtH+e7Zn3u+++w4gRI9ChQwd8/PHHmDRpEnJycnTrhWJ6nvC+fZL+xIkT9Z6k\nf/nll62+IGhrX7U5O/OVK1fkS5cuybJ860XDTp06yT/99JMhZv7vf/8rh4SEyLt27XJ4XyPNa+Tn\n+OjRo/LNmzdlWZbljRs3yv369bN7X6PNrNfz7Mjz9Oyzz8off/yxU/saha5xNpvNcmhoqPzAAw/I\nixcvlmVZlpctWyYvW7ZMlmVZ/vnnn+XAwEC5RYsWcsuWLeWgoCC5oqLC6r5GnvnYsWNyly5d5C5d\nusjJycnyv/71L8PMPG7cONnPz0+OjIysdWmUHs+zs/Ma+TnOyMiQw8PD5cjISHns2LHygQMH6t3X\nyDPr9Tzbmre6O+Os13OshKZvQiEiIvvods6ZiIisY5yJiAyIcSYiMiDGmYjIgBhncrnk5GRs2bKl\nxrZFixZh0qRJdd6/ffv2uHDhQr1rvvLKKzV+7tmzJwCgpKQEERERAIA9e/Zg2rRpAG59StjOnTud\nmp9ID4wzuVxqairWrl1bY9u6deswcuTIOu9/+2239bnzb03m5+fXuk+3bt2wePFiAMC2bduEeecj\nEcA4kwaGDh2KjRs34vr16wBuHd2eOXMG165dw+OPP46ePXvinXfeqXPfIUOGoGvXrkhOTsb69esB\nAH/6059QVVWFqKgojB49GkDdfyrIbDZjwIAB+O9//4vMzEy88cYbiI6Oxo4dO3D//fdb5rl06RLu\nv/9+3LhxwxW/PpFT+Nka5HJ+fn6IjY3Fpk2bMHDgQKxduxbDhg3DH//4R2zevBmtWrVCSkoKevbs\nibCwsBr7ZmVlwdfXF5cuXULv3r0xZMgQvPrqq3jrrbdqfDZFfUfb7dq1w8SJE+Hj44OZM2cCAHr3\n7o2NGzdi0KBBWLt2LYYOHYoGDRq45gkgcgKPnEkT1U9trFu3DkOHDkVYWBhCQkLg6+uLYcOG1fnp\nZmvXrsWjjz6Knj174vjx4zhw4IBTjy/f8UE448ePx8qVKwEA7777LsaOHevUukSuwjiTJgYOHIiv\nvvoK+/btQ2VlZa0jXVmWa207fvw4li5dig8//BAHDhxAhw4dcPHiRace/861e/TogZKSEpjNZty4\ncQOdOnVyal0iV2GcSRPNmzdHUlISxo4di5EjRyI+Ph6HDx/GsWPHcPHiRaxfvx4DBw6ssc+ZM2fg\n7+8PPz8/5Ofno6ioyHKbv78/Kisr7X78du3a4dy5czW2jRkzBk8//TTS0tKU/XJELsA4k2ZSU1Nx\n4MABpKamwmQyITMzE1OmTEH//v0xbtw4ywei3z7K7dWrF9q1a4ewsDAsWrQIffr0saw1ZcoUJCQk\nWF4QrH5kXNf3ffv2xZ49exAVFWW5smPkyJG4ePEiUlNTXfuLEzmBH3xEHmv16tXYtm2b5a+SEBkJ\nr9YgjzRlyhTk5+fj888/13sUojrxyJmIyIB4zpmIyIAYZyIiA2KciYgMiHEmIjIgxpmIyIAYZyIi\nA/p/fJgkSzip6OsAAAAASUVORK5CYII=\n"
458 "png": "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\nPY495r2BPjrggAPulOTIJD+f5MZJvpjkj5I8s9b6o5Xrn3rqqScdcMABX05zL/MHJDkoza2z/irJ\nb9VaL1n5GgAAAKCfTj311G8ccMABH0zTBO6f5H5pLvD7/5L8Wq31zA6HBwAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAEt263oAQ1JKuVOSFyU5OMk+Sc5J8pEkL6m1fmOL77lvkq8mOaXWev9d\nrHu/JM9Lcs8kP57k7CTvT/KyWut5W9k+3epyTpVSjknyhF283e1rrf+xlXHQjVnNqVLKI5P8UpKf\nT7J/kusm+XaSjyd5ea31P9d4nf3UyHQ5p+ynxmeG8+k+SR6X5D5JbpNkryQXJPlCkrcleWut9epV\nXmcfNTJdzin7qHGax8/ny977xUlenOSTa/2cbj81PdfpegBDUUq5d5KPJdkjyd8nOSvJHZIcnuQR\npZR71VrP3OB77ZPkZUl+Oskhaf6y7/SDw4rX/HKSmuSSJB9I8p0kByX57SQPa7d//ua/MrrS9Zxa\n5t1Jvr7Gc3b8AzLLOZXkDUlukuSzSd6e5Ko0+5wnJnlMKeVBtdaTV2zffmpkup5Ty9hPjcCM59Mr\nktw7yaeTHJfkwiQ/k+TQJA9K8sAkT1qxffuokel6Ti1jHzUSM55TK9/7t9IEmWSNn9Ptp6ZJlNm4\nNya5XpJH1VqPX3qwlHJkkr9M8qokj9nge+2T5Mhs8JfmUspeSf4qyaVJ7ldr/cKy516R5LlJXtAu\nGY7O5tQKR9da/3ELr6N/Zjmnjk7yNyv/RaiU8qIkL0nyZ2n+BWnpcfupcepsTq18rf3UKMxyPr06\nyadrrWcvf7CUcvskpyR5Qinlt2utP2gft48ap87m1Ar2UeMxyzl1jVLKo5O8PsnxSR6+xjr2UxO1\ne9cDGIJSyj2S3CnNYWbHL3+u1vr6JN9M8qhSyk9u5P1qrWfWWnevte6R5NYbeMlDk+zbvHTHX87W\nS9OU1F8vpfh+DkQP5hQjM4c59YdrHKL7F+3ywBWP20+NTA/mFCMyh/n0tyt/eW6dkWZ/c2GSHy17\n3D5qZHowpxiZWc+pZe973yTvSvKhJM9aZ1X7qYnyDd2Ye7fLk9Z4/sQ0Rx3dcwvvvZHr+qy5/Vrr\nhUm+nOYv8O22sH260fWc2s769NM859Rye7XLcze6ffupwep6Ti1nPzV8c51PpZS922uC/F2an2+P\nqLVeuZHt20cNVtdzajn7qHGY+ZwqpdwxzWlIn0tyWJpTdze9ffupcXP60sYsHXnw3TWeX6rq+/dg\n+6fNaQzMVtdzarkPlVKul+ZQyW8n+USSP6u1fmUB22Z2FjWnDmuXn9jG9u2nhqHrObWc/dTwzW0+\nlVK+mOQu7acfSXKXVS4cbR81Pl3PqeXso8ZhpnOqlHKLJCekmROPrLVeWkqZ1fbtp0bEkTIbc8N2\necEaz1/ULvce6faZvT58T89OU+7fkuTPk/xtmouaPSHJye2dUhiOuc+pUsqtk7wwzQ+df7zo7bNw\nXc+pxH5qTOY5n45JclSSf0xzsfvj2n+dXtT26UbXcyqxjxqbmc2p9hSnE9IcRfWQDV6c135qohwp\nszlXrPH4og5Z7Hr7zF5n39Na6/NXPtaeo/riNL8kvaGUcsta63qHWdI/c5lTpZSbJflwkp9I8uRa\n6ymL3D6d6mxO2U+N0sznU631tUt/LqUclORfk7yvlHKXWusl894+netsTtlHjda25lQ7B96f5GZJ\nDq61fnOR22d4HCmzMT9slz+2xvN7rVhvbNtn9nr5Pa21XlVrfXGSM5PcNM0tABmGuc2pUsp+Sf45\nzeGyz6y1vmWR26czXc+pVdlPDdZC9hHtbdU/nuQ2ufbdvOyjxqfrObXW+vZRwzWrObV3kvsm+UqS\nJ5VSXrX0keQP2nX2bx/7wzlsn4FxpMzGnNEub7XG8zdvl6ePdPvMXt+/p+cl2S/JDTraPps3lznV\n/gvhB9IczfDrtdZ3LnL7dKrrObUr9lPDssh9xHntcvkdUuyjxqfrObWR1+wX+6ghmfWcul+S+6/z\nXs9Jcn6SF81p+wyEKLMxJ7bLB618oj087T5Jrkxy8hy3/5x2+29Ysf2901yI7Lwk/zGn7TN7Xc+p\nNZVS9krys2kOnVzvonb0y8znVCnlMWnOk784yaG11n/Zxfbtp8al6zm13vvYTw3PQv6/V0rZLTsu\n0HrGsqfso8an6zm13mvso4ZpJnOqvX7MqmeklFJulWYe/WutdeWRV/ZTE+X0pQ2otX4+yalJDiyl\nHLri6SPSVMvja63X3M6zlPLWUspppZSXz2AIJyT5XpJHllLuvOK5FybZM8k7nK86HF3PqVLKXUsp\nz2x/aFj++O5pLlR3gyTvrbV+f7vbYjFmPadKKS9L8u4kX0ty0AZ+ebafGpmu55T91LjMcj6VUu5Q\n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\nAABJRU5ErkJggg==\n",
459 "text": [
460 "<matplotlib.figure.Figure at 0x10ffc7210>"
461 ]
439 }
462 }
440 ],
463 ],
441 "prompt_number": 22
464 "prompt_number": 22
442 },
465 },
443 {
466 {
444 "cell_type": "markdown",
467 "cell_type": "markdown",
445 "metadata": {},
468 "metadata": {},
446 "source": [
469 "source": [
447 "Plot the value of the European put in (volatility, strike) space."
470 "Plot the value of the European put in (volatility, strike) space."
448 ]
471 ]
449 },
472 },
450 {
473 {
451 "cell_type": "code",
474 "cell_type": "code",
452 "collapsed": false,
475 "collapsed": false,
453 "input": [
476 "input": [
454 "plt.figure()\n",
477 "plt.figure()\n",
455 "plt.contourf(sigma_vals, strike_vals, prices['eput'])\n",
478 "plt.contourf(sigma_vals, strike_vals, prices['eput'])\n",
456 "plt.axis('tight')\n",
479 "plt.axis('tight')\n",
457 "plt.colorbar()\n",
480 "plt.colorbar()\n",
458 "plt.title(\"European Put\")\n",
481 "plt.title(\"European Put\")\n",
459 "plt.xlabel(\"Volatility\")\n",
482 "plt.xlabel(\"Volatility\")\n",
460 "plt.ylabel(\"Strike Price\")"
483 "plt.ylabel(\"Strike Price\")"
461 ],
484 ],
462 "language": "python",
485 "language": "python",
463 "metadata": {},
486 "metadata": {},
464 "outputs": [
487 "outputs": [
465 {
488 {
489 "metadata": {},
466 "output_type": "pyout",
490 "output_type": "pyout",
467 "prompt_number": 14,
491 "prompt_number": 23,
468 "text": [
492 "text": [
469 "&lt;matplotlib.text.Text at 0x106d34150&gt;"
493 "<matplotlib.text.Text at 0x1109ef450>"
470 ]
494 ]
471 },
495 },
472 {
496 {
497 "metadata": {
498 "png": {
499 "height": 407,
500 "width": 573
501 }
502 },
473 "output_type": "display_data",
503 "output_type": "display_data",
474 "png": "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\nQmCC\n"
504 "png": "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\neZ2V5HmL/RMAAAAAM3hEkjOTvLGU8qYkFyT5uSQnJNmb5LEbtj86yfWTHLnJvn43ya2TvLCUcu8k\n/9luf1KaT916xDz+AFsZ60TPxUl+KcnD04xqfTTJg5Pcqtb65Y0b11qfleS/J/n3JP93kt9IcsU0\nEz2/tD4MAQAAAP1Wa31vktskOSPJ7dPEmBskeVmSW9ZaP73hKfvaX5vt6z+S3CLJ6WkGQh7R7vt1\nSW5Ta13YZVsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3TAsg9glZRSbpjkKUnumOSI\nJHuTvC3JU2utn5tyn3uSfDLJ2bXWO+yw7fFJHp/k1kl+Isnnk5yR5I9qrRdO8/os1zLPqVLKy5I8\naIfdHVdr/Y9pjoPl6OqcKqXcM8mvJLlVkmOTXDHJF5O8M8nTaq3/ucXzvE8NzDLPKe9Tw9Ph+XS7\nJA9Icrsk10tyaJJvJflIklckOb3Wum+T53mPGphlnlPeo4ZpHt+fr9v3qUlOTfLerb5P9z5FFw5a\n9gGsilLKbZO8I8kVkvxDkvOT/HyShyY5qZRym1rreRPu64gkf5Tkp5KckOYNZL9vRjY8595JapLv\nJXljki8nuWWS30ly9/b1v7H7PxnLsuxzap3XJPnsFo/5j8kK6fKcSvLCJEcm+XCSv0nyozTvOQ9O\ncp9Syl1qrR/a8PrepwZm2efUOt6nBqDj8+kZSW6b5Kwkr05yUZKfTnJikrskuXOSh2x4fe9RA7Ps\nc2od71ED0fE5tXHfD08TeZItvk/3PkVXhJ7JvSjJlZLcq9b65rU7SymnJPnfSZ6Z5D4T7uuIJKdk\nwh/ESymHJnlBkkuSHF9r/ci6x56R5PeSPKm9ZXUs7Zza4MW11n+c4nn0T5fn1IuT/PXGf7kqpTwl\nyVOTPCvNv3St3e99apiWdk5tfK73qUHo8nx6dpKzaq2fX39nKeW4JGcneVAp5Xdqrd9s7/ceNUxL\nO6c28B41HF2eUz9WSvnlJM9L8uYk99hiG+9TdObAZR/AKiil3CzJDdOM2L15/WO11ucluSDJvUop\nPznJ/mqt59VaD6y1XiHJdSd4yt2S7Gmeetn/4VunpSm+v1ZK8fe5InpwTjEwczin/nCL8eTntrc3\n33C/96mB6cE5xYDM4Xx63cYfyFvnpnm/uSjJd9bd7z1qYHpwTjEwXZ9T6/Z7+yR/l+RNSR69zabe\np+iMk2Qyt21v37/F4+9LMx116yn2Pck6SVu+fq31oiT/X5o3hetP8fosx7LPqVm2p5/meU6td2h7\n+7VJX9/71Mpa9jm1nvep1TfX86mUcni7xsr/SfP97cm11ksneX3vUStr2efUet6jhqHzc6qUcoM0\nl2D9S5L7pblsedev732K3XLp1mTWJiS+ssXja/X/2B68/jlzOga6texzar03lVKulGZM9ItJ3p3k\nWbXWjy3gtenOos6p+7W3757h9b1PrYZln1PreZ9afXM7n0opH01y4/bLtyW58SaLe3uPGp5ln1Pr\neY8ahk7PqVLKtZO8Jc05cc9a6yWllK5e3/sU2zLRM5mrtLff2uLx77a3hw/09eleH/5OP5/mXxhe\nnuTPk7wuzcJzD0ryofYTclgdcz+nSinXTfLkNN/I/q9Fvz4Lt+xzKvE+NSTzPJ9eluT5Sf4xzQcS\nvLr9V/RFvT7LsexzKvEeNTSdnVPt5V1vSTPtddcJF1D2PkVnTPTszg+3uH9R45rLfn26t7S/01rr\nEzfe117ze2qaH7xeWEo5uta63Ygp/TOXc6qUcs0kb01y1SS/Xms9e5Gvz1It7ZzyPjVInZ9PtdY/\nW/t9KeWWSd6T5A2llBvXWr8379dn6ZZ2TnmPGqyZzqn2HDgjyTWT3LHWesEiXx8SEz2T+nZ7e8gW\njx+6YbuhvT7d6+Xfaa31R7XWU5Ocl+SoNB8nyWqY2zlVSrlOknelGRV+VK315Yt8fZZm2efUprxP\nrayFvEfUWj+U5J1JrpfLf4qb96jhWfY5tdX23qNWV1fn1OFJbp/kY0keUkp55tqvJE9otzm2ve8P\n5/D6YKJnQue2t8ds8fi12tvPDPT16V7f/04vTHKdJIct6fXZvbmcU+2/ZL4xzdTFr9Va/3aRr89S\nLfuc2on3qdWyyPeIC9vb9Z+M4z1qeJZ9Tk3ynOvEe9Qq6fqcOj7JHbbZ12OTfCPJU+b0+oyY0DOZ\n97W3d9n4QDuad7sklyb50Bxf/7Ht679ww+sfnmaxuAuT/MecXp/uLfuc2lIp5dAkP5dmbHS7hQfp\nl87PqVLKfdKsO3BxkhNrrf+8w+t7nxqWZZ9T2+3H+9TqWch/90opB+SyRXTPXfeQ96jhWfY5td1z\nvEetpk7OqXY9nk2vnCmlHJPmPHpPrXXjhJj3KTrj0q0J1Fr/NcnHk9y8lHLihodPTlNX31xr/fFH\n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\n",
505 "text": [
506 "<matplotlib.figure.Figure at 0x1109e0310>"
507 ]
475 }
508 }
476 ],
509 ],
477 "prompt_number": 14
510 "prompt_number": 23
478 },
511 },
479 {
512 {
480 "cell_type": "markdown",
513 "cell_type": "markdown",
481 "metadata": {},
514 "metadata": {},
482 "source": [
515 "source": [
483 "Plot the value of the Asian put in (volatility, strike) space."
516 "Plot the value of the Asian put in (volatility, strike) space."
484 ]
517 ]
485 },
518 },
486 {
519 {
487 "cell_type": "code",
520 "cell_type": "code",
488 "collapsed": false,
521 "collapsed": false,
489 "input": [
522 "input": [
490 "plt.figure()\n",
523 "plt.figure()\n",
491 "plt.contourf(sigma_vals, strike_vals, prices['aput'])\n",
524 "plt.contourf(sigma_vals, strike_vals, prices['aput'])\n",
492 "plt.axis('tight')\n",
525 "plt.axis('tight')\n",
493 "plt.colorbar()\n",
526 "plt.colorbar()\n",
494 "plt.title(\"Asian Put\")\n",
527 "plt.title(\"Asian Put\")\n",
495 "plt.xlabel(\"Volatility\")\n",
528 "plt.xlabel(\"Volatility\")\n",
496 "plt.ylabel(\"Strike Price\")"
529 "plt.ylabel(\"Strike Price\")"
497 ],
530 ],
498 "language": "python",
531 "language": "python",
499 "metadata": {},
532 "metadata": {},
500 "outputs": [
533 "outputs": [
501 {
534 {
535 "metadata": {},
536 "output_type": "pyout",
537 "prompt_number": 24,
538 "text": [
539 "<matplotlib.text.Text at 0x1109e3b10>"
540 ]
541 },
542 {
543 "metadata": {
544 "png": {
545 "height": 407,
546 "width": 562
547 }
548 },
502 "output_type": "display_data",
549 "output_type": "display_data",
503 "png": "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\nAeyS/5wqC8i5AAAAAElFTkSuQmCC\n"
550 "png": "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\nTCll91LKiUnenOTmSd6Z5MQkV01yTJKPlVKuteY1T0ryjiS3T/KuJH+T5Kdp/vDeX0q5yvx+BwAA\n/WBqBoBFKaXcLcnHkzwkyceSvC7JfyY5MskZpZT957EfQ5yU+b0kj0hyWpL7rUzFlFL2SPKyJE9I\n8sIkR7X336j9+vwkd1qpZaWU3ZK8JclvJ3lsklfN97cBANB9B+y7w8QMAIvwujTDGQ+utZ6ycmcp\n5egkf5nkpUkOm/VODG5SJsnD29tjVy9TqrVenuRPknwvyaNKKXu1Dx2eZrnSa1ePL9Var0jy9PbL\nI2e+1wAAPeUiwADMUynljkluk+TfVgeZJKm1vjrJeUkeXEr5xVnvyxCjzA2SXJHk7LUP1FovSTO2\ntFeSg9q779benrbO87+c5NtJbl9KudpM9hYAYCCEGQDmZOTP+a1T06wsususd2SIUeZrSXZLcrsR\nj1/Q3l6/vb1pe/vtDd7vgKnsHQDAgJmaAWAOJvk5P5nDz/lDvKbM8UnuneQ17QV635fk4iQ3THLf\nJPdon7eyfOmaaSZrRi12vjhNlPHdAwDAlLjWDAAzdM32dtzP+ckcfs4fXJSptZ5YSjkgyTOSnLTm\n4e8l+cmqf17tshFvudt29uezp//rdl4OAAAAC9GDn2dn8nP+Zgxx+VJqrcem+TjsxyU5NsnT0lxV\n+cZJvpNmMubz7dN/mOYP5Ooj3m7vVc8DAAAAltvKz+8L/zl/cJMyK2qt5yY5bvV97cdf3zbJOe3j\nSXNB4DskuUmazyxf60ZJfpZ1Lhw8zqGHHjq38gYAAADT0oOfZ1d+fr/JiMdv1N5+edY7MshJmTGO\naW9Xx5pT29v7rn1yKeXmSa6b5D9qrT+e8b4BAAAA2zfu5/zdk9w9yeVJzpj1jogySUope5ZSnp3k\nMUnOTPKyVQ+/LcmlSR7ZTtKsvGb3JM9rvzxhXvsKAAAAbF2t9VNJzkpyUCnlfmsePirNpMwptdbv\nznpfuj5ytCWllKOS3D/JV5Lsk+Q+af6lfzLJg2qt31rz/D9K8pI0H5f9niQ/SnKvNEudTk/yq7XW\nS+f2GwAAAAC2rJRyjyQfTDOs8t4k5yX55SSHprnW7N1rrf896/3YY9YbWEYHHnjgbZIcneTOSa6f\n5DNJnp/kCbXWH619/llnnXXagQce+Nk0n2V+7yQHp/norL9K8ge11p+sfQ0AAACwnM4666yvHnjg\nge9J0wTuleSeaS7w+/+SPLzWes4Cdw8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABW7Lbo\nHeiSUsptkjw7ySFJ9klyfpL3J3lOrfWrW3zP6yb5QpIza6332uC590zytCR3SfILSb6W5F1Jnldr\nvWAr22exFnlMlVKOT3LEBm93y1rrF7eyHyzGtI6pUsqDkvxmkjsnOSDJVZJ8I8mHkryg1vpfI17n\nPNUzizymnKf6Z4rH092TPCzJ3ZPcLMneSS5M8ukkb0xyYq31inVe5xzVM4s8ppyj+mkW35+veu9j\nkhyT5N9GfZ/uPDU8ey56B7qilHK3JP+UZI8k/5Dk3CS3SnJkkt8opdy11nrOhO+1T5LnJblekkPT\n/Me+yzcOa17zW0lqkp8keXeSbyU5OMmTkjyg3f73N/87Y1EWfUyt8rYkXxnxmBN/h0zzmEry2iT7\nJvlEkjcl+Vmac84jkxxWSrlvrfWMNdt3nuqZRR9TqzhP9cCUj6cXJ7lbktOTnJzkoiS/lOR+Se6b\n5D5JHrVm+85RPbPoY2oV56iemPIxtfa9/yBNkElGfJ/uPDVMoszkXpfkqkkeXGs9ZeXOUsrRSf4y\nyUuTHDbhe+2T5OhM+ENzKWXvJH+V5JIk96y1fnrVYy9O8tQkz2xv6Y6FHVNrHFdr/ectvI7lM81j\n6rgkf7v2b4RKKc9O8pwkf57mb5BW7nee6qeFHVNrX+s81QvTPJ5eluT0WuvXVt9ZSrllkjOTHFFK\neVKt9Qft/c5R/bSwY2oN56j+mOYx9XOllIckeXWSU5I8cMRznKcGavdF70AXlFLumOQ2acbMTln9\nWK311UnOS/LgUsovTvJ+tdZzaq2711r3SHLTCV7y60mu27x053+crWPTlNTfLaX48+yIJTim6JkZ\nHFPPHTGi+xft7UFr7nee6pklOKbokRkcT3+39ofn1tlpzjcXJfnRqvudo3pmCY4pembax9Sq971H\nkrcmeW+SJ455qvPUQPkDnczd2tvTRjx+apqpo7ts4b0nua7PyO3XWi9K8tk0/wHfYgvbZzEWfUxt\n5/ksp1keU6vt3d5+d9LtO0911qKPqdWcp7pvpsdTKWVHe02Qv0/z/e1RtdbLJ9m+c1RnLfqYWs05\nqh+mfkyVUm6dZhnSJ5Mcnmbp7qa37zzVb5YvTWZl8uDbIx5fqeoHLMH2Pz+jfWC6Fn1MrfbeUspV\n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\nST5QSnnRFnbrGUkemORWSfZpt3mtJHdL8mdJziilXHvV81eu+bISRX6WJm6s/rX2mi9buQbM+V5h\nAAAABa1JREFUFWtet/YaM2u3eVmaJWHnJ7lqmk92GuX329uTBRkAYBpEGQDohpXIcv9SyrVGPGfl\nAr+fqbV+PklKKQ9M80lMVyR5VZpplKskuWGS57b3/3H7CUWbcUaSZya5Y5Kr1VqvmuS6SR6TZmLm\nlkmetfLkWuu5tdarp5n6SZITa617r/n11U3uw4ZqrbdMclT75TnrbPPNtdafJln5tKbfW+99SinX\nSfKbaf59LcXHgwMA3Wf5EgB0w9uTvDrJXkl+K8nfrvOcw9vb1UuXXtzeHldrfeLKnbXWbyV5Tinl\nsjRx5vmllBMn+cjt9vX3Wue+C5K8oZ2QeVGS/53kyWuetohryUyyzb9O8tQkty6l3LXW+rE1jx+R\n5CpJPrfOYwAAW2JSBgA6oNb6vSSntF/usoSplHJQkpulWRb0lva+2ya5dZrpjheOeOuXJ/lxmuVM\n/2tKu/vp9vZGU3q/mau1fjHJR9IEnPWmhlbuMyUDAEyNSRkA6I6T0lzo9z6llOvWWs9f9djK0qWP\n1Fq/3v7zwe3t19uPjN5FrfWiUsqnk9w9yUFJ3jvpzpRSbp7kt5PcOclN01zs95rtr6SZLOmS16e5\nEPJvl1KetHKh4lLKPdMsx7ooyRsXuH8AQM+IMgDQHe9K8qMkv5CkJHlNkpRSdksTR5IrL126Xnv7\nrQ3e9xvt7fUn2YlSyh5JXpHkD3PlpUErF9i9LMkek7zXknl7kr9I8otpppH+pr1/9QV+f7iIHQMA\n+snyJQDoiFrrT5K8s/1y9RKmeyTZL82nG9U57MpzkxydJsh8KMkjk9w+yXVqrXskud8c9mHqaq2X\nZOckzGOSpJSyT5oA5gK/AMDUmZQBgG45Kckjkty9lLJfrfW87Fy69L41H9W8MiFzww3e8wbt7bc3\n2ng7lXN0++Vra61/uM7TFnEx32l5fZInJrlzKeXAJPdOcrU0n2h1xiJ3DADoH5MyANAtH0hyfpr/\nhx9eStk9yWHtY29e89xPtLfXb6//sotSyjXTfKz16uePc9001465IjuX92zGZe3tXlt47VZNvM1a\n65lJPpadF/xdWbpkSgYAmDpRBgA6pNZ6eZK3tV8+LMmhaULJhUnevea5n0tyVprA8KwRb/lHaSZB\nzk8TfDZyyap/vt6I59xhzOvPn+A507ayzeuXUia5bs7r29vHJrldmuv4rA1eAADbZvkSAHTPSWmW\nEN0xydPb+97RXhNlrf+bJtY8opTy4yQvqLWeW0rZN82Fep+ZZurlWbXWSzfacK31B6WU05PcJclL\nSinfTfMR2Hu09z0t468pc1p7e8tSyuOTnJjmU5rulOTUGV1I94wkl7f7+KJSyp+m+SSlWyX5Qa31\nC2uef3Kajwrf0X79llrrj2awXwDAwJmUAYCOqbWeluSc9stD2tuTRjz3vUn+OE14+f0kZ5dSLk/y\n9ewMMi+vtR63iV14YpKLk9w6zVKfS9qvP5TkPklOGfPadyf5j/af/yLJ99NMsvxDmk892q5drmdT\na/12di61OiLN7/0H7b7fZZ3nX5yd/z5d4BcAmBlRBgC6aXU0+FaSD456Yq31z5PcLc2yp68n+Wma\ni/q+K8n9aq1PHfHSK7LzY65Xv98Z7fu9O82yqZ8mOTvJXyW5bZKXjNmXnya5b5pI8o32td9K8k9J\nVqZkdtnmRvu05vH1HJ1mCdeXklya5HtJPp7kyyOev3L/p2qtnxqzPQCALevypyMAAExd+wlTX0hy\nsyR/UGv96wXvEgDQUyZlAACu7P5pgsyFGbEsDABgGkQZAIArO7q9Pam9vgwAwEyIMgAArVLKAUke\nGBf4BQDmQJQBANjpqDTX3PtErfXfF70zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo/1/MrL3Cbz9qMUAAAAASUVORK5CYII=\n",
551 "text": [
552 "<matplotlib.figure.Figure at 0x110dd2c50>"
553 ]
504 }
554 }
505 ],
555 ],
506 "prompt_number": 15
556 "prompt_number": 24
507 }
557 }
508 ],
558 ],
509 "metadata": {}
559 "metadata": {}
510 }
560 }
511 ]
561 ]
512 } No newline at end of file
562 }
@@ -1,49 +1,44 b''
1 """Example of how to use pylab to plot parallel data.
1 """Example of how to use matplotlib to plot parallel data.
2
2
3 The idea here is to run matplotlib is the same IPython session
3 The idea here is to run matplotlib is the same IPython session
4 as an ipython parallel Client. That way matplotlib
4 as an ipython parallel Client. That way matplotlib
5 can be used to plot parallel data that is gathered using
5 can be used to plot parallel data that is gathered using
6 a DirectView.
6 a DirectView.
7
7
8 To run this example, first start the IPython controller and 4
8 To run this example, first start the IPython controller and 4
9 engines::
9 engines::
10
10
11 ipcluster -n 4
11 ipcluster -n 4
12
12
13 Then start ipython in pylab mode::
13 Then start ipython with matplotlib integration mode::
14
14
15 ipython -pylab
15 ipython --matplotlib
16
16
17 Then a simple "run parallel_pylab.ipy" in IPython will run the
17 Then a simple "%run parallel_plot.ipy" in IPython will run the
18 example.
18 example.
19 """
19 """
20
20
21 import numpy as N
21 import matplotlib.pyplot as plt
22 from pylab import *
23 from IPython.parallel import Client
22 from IPython.parallel import Client
24
23
25 # load the parallel magic
26 %load_ext parallelmagic
27
28 # Get an IPython Client
24 # Get an IPython Client
29 rc = Client()
25 rc = Client()
30 v = rc[:]
26 v = rc[:]
31 v.activate()
32
27
33 # Create random arrays on the engines
28 # Create random arrays on the engines
34 # This is to simulate arrays that you have calculated in parallel
29 # This is to simulate arrays that you have calculated in parallel
35 # on the engines.
30 # on the engines.
36 # Anymore that length 10000 arrays, matplotlib starts to be slow
31 # Anymore that length 10000 arrays, matplotlib starts to be slow
37 %px import numpy as N
32 %px import numpy as np
38 %px x = N.random.standard_normal(10000)
33 %px x = np.random.standard_normal(10000)
39 %px y = N.random.standard_normal(10000)
34 %px y = np.random.standard_normal(10000)
40
35
41 print v.apply_async(lambda : x[0:10]).get_dict()
36 print v.apply_async(lambda : x[0:10]).get_dict()
42 print v.apply_async(lambda : y[0:10]).get_dict()
37 print v.apply_async(lambda : y[0:10]).get_dict()
43
38
44 # Bring back the data
39 # Bring back the data
45 x_local = v.gather('x', block=True)
40 x_local = v.gather('x', block=True)
46 y_local = v.gather('y', block=True)
41 y_local = v.gather('y', block=True)
47
42
48 # Make a scatter plot of the gathered data
43 # Make a scatter plot of the gathered data
49 plot(x_local, y_local,'ro')
44 plt.plot(x_local, y_local,'ro')
@@ -1,61 +1,60 b''
1 """An example of how to use IPython1 for plotting remote parallel data
1 """An example of how to use IPython1 for plotting remote parallel data
2
2
3 The two files plotting_frontend.py and plotting_backend.py go together.
3 The two files plotting_frontend.py and plotting_backend.py go together.
4
4
5 To run this example, first start the IPython controller and 4
5 To run this example, first start the IPython controller and 4
6 engines::
6 engines::
7
7
8 ipcluster start -n 4
8 ipcluster start -n 4
9
9
10 Then start ipython in pylab mode::
10 Then start ipython with matplotlib integration::
11
11
12 ipython -pylab
12 ipython --matplotlib
13
13
14 Then a simple "run plotting_frontend.py" in IPython will run the
14 Then a simple "run plotting_frontend.py" in IPython will run the
15 example. When this is done, all the variables (such as number, downx, etc.)
15 example. When this is done, all the variables (such as number, downx, etc.)
16 are available in IPython, so for example you can make additional plots.
16 are available in IPython, so for example you can make additional plots.
17 """
17 """
18 from __future__ import print_function
18 from __future__ import print_function
19
19
20 import numpy as N
20 import matplotlib.pyplot as plt
21 from pylab import *
22 from IPython.parallel import Client
21 from IPython.parallel import Client
23
22
24 # Connect to the cluster
23 # Connect to the cluster
25 rc = Client()
24 rc = Client()
26 view = rc[:]
25 view = rc[:]
27
26
28 # Run the simulation on all the engines
27 # Run the simulation on all the engines
29 view.run('plotting_backend.py')
28 view.run('plotting_backend.py')
30
29
31 # Bring back the data. These are all AsyncResult objects
30 # Bring back the data. These are all AsyncResult objects
32 number = view.pull('number')
31 number = view.pull('number')
33 d_number = view.pull('d_number')
32 d_number = view.pull('d_number')
34 downx = view.gather('downx')
33 downx = view.gather('downx')
35 downy = view.gather('downy')
34 downy = view.gather('downy')
36 downpx = view.gather('downpx')
35 downpx = view.gather('downpx')
37 downpy = view.gather('downpy')
36 downpy = view.gather('downpy')
38
37
39 # but we can still iterate through AsyncResults before they are done
38 # but we can still iterate through AsyncResults before they are done
40 print("number: ", sum(number))
39 print("number: ", sum(number))
41 print("downsampled number: ", sum(d_number))
40 print("downsampled number: ", sum(d_number))
42
41
43
42
44 # Make a scatter plot of the gathered data
43 # Make a scatter plot of the gathered data
45 # These calls to matplotlib could be replaced by calls to pygist or
44 # These calls to matplotlib could be replaced by calls to pygist or
46 # another plotting package.
45 # another plotting package.
47 figure(1)
46 plt.figure(1)
48 # wait for downx/y
47 # wait for downx/y
49 downx = downx.get()
48 downx = downx.get()
50 downy = downy.get()
49 downy = downy.get()
51 scatter(downx, downy)
50 plt.scatter(downx, downy)
52 xlabel('x')
51 plt.xlabel('x')
53 ylabel('y')
52 plt.ylabel('y')
54 figure(2)
53 plt.figure(2)
55 # wait for downpx/y
54 # wait for downpx/y
56 downpx = downpx.get()
55 downpx = downpx.get()
57 downpy = downpy.get()
56 downpy = downpy.get()
58 scatter(downpx, downpy)
57 plt.scatter(downpx, downpy)
59 xlabel('px')
58 plt.xlabel('px')
60 ylabel('py')
59 plt.ylabel('py')
61 show()
60 plt.show()
@@ -1,205 +1,205 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """
2 """
3 A simple python program of solving a 2D wave equation in parallel.
3 A simple python program of solving a 2D wave equation in parallel.
4 Domain partitioning and inter-processor communication
4 Domain partitioning and inter-processor communication
5 are done by an object of class MPIRectPartitioner2D
5 are done by an object of class MPIRectPartitioner2D
6 (which is a subclass of RectPartitioner2D and uses MPI via mpi4py)
6 (which is a subclass of RectPartitioner2D and uses MPI via mpi4py)
7
7
8 An example of running the program is (8 processors, 4x2 partition,
8 An example of running the program is (8 processors, 4x2 partition,
9 400x100 grid cells)::
9 400x100 grid cells)::
10
10
11 $ ipcluster start --engines=MPIExec -n 8 # start 8 engines with mpiexec
11 $ ipcluster start --engines=MPIExec -n 8 # start 8 engines with mpiexec
12 $ python parallelwave-mpi.py --grid 400 100 --partition 4 2
12 $ python parallelwave-mpi.py --grid 400 100 --partition 4 2
13
13
14 See also parallelwave-mpi, which runs the same program, but uses MPI
14 See also parallelwave-mpi, which runs the same program, but uses MPI
15 (via mpi4py) for the inter-engine communication.
15 (via mpi4py) for the inter-engine communication.
16
16
17 Authors
17 Authors
18 -------
18 -------
19
19
20 * Xing Cai
20 * Xing Cai
21 * Min Ragan-Kelley
21 * Min Ragan-Kelley
22
22
23 """
23 """
24
24
25 import sys
25 import sys
26 import time
26 import time
27
27
28 from numpy import exp, zeros, newaxis, sqrt
28 from numpy import exp, zeros, newaxis, sqrt
29
29
30 from IPython.external import argparse
30 from IPython.external import argparse
31 from IPython.parallel import Client, Reference
31 from IPython.parallel import Client, Reference
32
32
33 def setup_partitioner(index, num_procs, gnum_cells, parts):
33 def setup_partitioner(index, num_procs, gnum_cells, parts):
34 """create a partitioner in the engine namespace"""
34 """create a partitioner in the engine namespace"""
35 global partitioner
35 global partitioner
36 p = MPIRectPartitioner2D(my_id=index, num_procs=num_procs)
36 p = MPIRectPartitioner2D(my_id=index, num_procs=num_procs)
37 p.redim(global_num_cells=gnum_cells, num_parts=parts)
37 p.redim(global_num_cells=gnum_cells, num_parts=parts)
38 p.prepare_communication()
38 p.prepare_communication()
39 # put the partitioner into the global namespace:
39 # put the partitioner into the global namespace:
40 partitioner=p
40 partitioner=p
41
41
42 def setup_solver(*args, **kwargs):
42 def setup_solver(*args, **kwargs):
43 """create a WaveSolver in the engine namespace"""
43 """create a WaveSolver in the engine namespace"""
44 global solver
44 global solver
45 solver = WaveSolver(*args, **kwargs)
45 solver = WaveSolver(*args, **kwargs)
46
46
47 def wave_saver(u, x, y, t):
47 def wave_saver(u, x, y, t):
48 """save the wave log"""
48 """save the wave log"""
49 global u_hist
49 global u_hist
50 global t_hist
50 global t_hist
51 t_hist.append(t)
51 t_hist.append(t)
52 u_hist.append(1.0*u)
52 u_hist.append(1.0*u)
53
53
54
54
55 # main program:
55 # main program:
56 if __name__ == '__main__':
56 if __name__ == '__main__':
57
57
58 parser = argparse.ArgumentParser()
58 parser = argparse.ArgumentParser()
59 paa = parser.add_argument
59 paa = parser.add_argument
60 paa('--grid', '-g',
60 paa('--grid', '-g',
61 type=int, nargs=2, default=[100,100], dest='grid',
61 type=int, nargs=2, default=[100,100], dest='grid',
62 help="Cells in the grid, e.g. --grid 100 200")
62 help="Cells in the grid, e.g. --grid 100 200")
63 paa('--partition', '-p',
63 paa('--partition', '-p',
64 type=int, nargs=2, default=None,
64 type=int, nargs=2, default=None,
65 help="Process partition grid, e.g. --partition 4 2 for 4x2")
65 help="Process partition grid, e.g. --partition 4 2 for 4x2")
66 paa('-c',
66 paa('-c',
67 type=float, default=1.,
67 type=float, default=1.,
68 help="Wave speed (I think)")
68 help="Wave speed (I think)")
69 paa('-Ly',
69 paa('-Ly',
70 type=float, default=1.,
70 type=float, default=1.,
71 help="system size (in y)")
71 help="system size (in y)")
72 paa('-Lx',
72 paa('-Lx',
73 type=float, default=1.,
73 type=float, default=1.,
74 help="system size (in x)")
74 help="system size (in x)")
75 paa('-t', '--tstop',
75 paa('-t', '--tstop',
76 type=float, default=1.,
76 type=float, default=1.,
77 help="Time units to run")
77 help="Time units to run")
78 paa('--profile',
78 paa('--profile',
79 type=unicode, default=u'default',
79 type=unicode, default=u'default',
80 help="Specify the ipcluster profile for the client to connect to.")
80 help="Specify the ipcluster profile for the client to connect to.")
81 paa('--save',
81 paa('--save',
82 action='store_true',
82 action='store_true',
83 help="Add this flag to save the time/wave history during the run.")
83 help="Add this flag to save the time/wave history during the run.")
84 paa('--scalar',
84 paa('--scalar',
85 action='store_true',
85 action='store_true',
86 help="Also run with scalar interior implementation, to see vector speedup.")
86 help="Also run with scalar interior implementation, to see vector speedup.")
87
87
88 ns = parser.parse_args()
88 ns = parser.parse_args()
89 # set up arguments
89 # set up arguments
90 grid = ns.grid
90 grid = ns.grid
91 partition = ns.partition
91 partition = ns.partition
92 Lx = ns.Lx
92 Lx = ns.Lx
93 Ly = ns.Ly
93 Ly = ns.Ly
94 c = ns.c
94 c = ns.c
95 tstop = ns.tstop
95 tstop = ns.tstop
96 if ns.save:
96 if ns.save:
97 user_action = wave_saver
97 user_action = wave_saver
98 else:
98 else:
99 user_action = None
99 user_action = None
100
100
101 num_cells = 1.0*(grid[0]-1)*(grid[1]-1)
101 num_cells = 1.0*(grid[0]-1)*(grid[1]-1)
102 final_test = True
102 final_test = True
103
103
104 # create the Client
104 # create the Client
105 rc = Client(profile=ns.profile)
105 rc = Client(profile=ns.profile)
106 num_procs = len(rc.ids)
106 num_procs = len(rc.ids)
107
107
108 if partition is None:
108 if partition is None:
109 partition = [1,num_procs]
109 partition = [1,num_procs]
110
110
111 assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs)
111 assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs)
112
112
113 view = rc[:]
113 view = rc[:]
114 print "Running %s system on %s processes until %f"%(grid, partition, tstop)
114 print "Running %s system on %s processes until %f"%(grid, partition, tstop)
115
115
116 # functions defining initial/boundary/source conditions
116 # functions defining initial/boundary/source conditions
117 def I(x,y):
117 def I(x,y):
118 from numpy import exp
118 from numpy import exp
119 return 1.5*exp(-100*((x-0.5)**2+(y-0.5)**2))
119 return 1.5*exp(-100*((x-0.5)**2+(y-0.5)**2))
120 def f(x,y,t):
120 def f(x,y,t):
121 return 0.0
121 return 0.0
122 # from numpy import exp,sin
122 # from numpy import exp,sin
123 # return 10*exp(-(x - sin(100*t))**2)
123 # return 10*exp(-(x - sin(100*t))**2)
124 def bc(x,y,t):
124 def bc(x,y,t):
125 return 0.0
125 return 0.0
126
126
127 # initial imports, setup rank
127 # initial imports, setup rank
128 view.execute('\n'.join([
128 view.execute('\n'.join([
129 "from mpi4py import MPI",
129 "from mpi4py import MPI",
130 "import numpy",
130 "import numpy",
131 "mpi = MPI.COMM_WORLD",
131 "mpi = MPI.COMM_WORLD",
132 "my_id = MPI.COMM_WORLD.Get_rank()"]), block=True)
132 "my_id = MPI.COMM_WORLD.Get_rank()"]), block=True)
133
133
134 # initialize t_hist/u_hist for saving the state at each step (optional)
134 # initialize t_hist/u_hist for saving the state at each step (optional)
135 view['t_hist'] = []
135 view['t_hist'] = []
136 view['u_hist'] = []
136 view['u_hist'] = []
137
137
138 # set vector/scalar implementation details
138 # set vector/scalar implementation details
139 impl = {}
139 impl = {}
140 impl['ic'] = 'vectorized'
140 impl['ic'] = 'vectorized'
141 impl['inner'] = 'scalar'
141 impl['inner'] = 'scalar'
142 impl['bc'] = 'vectorized'
142 impl['bc'] = 'vectorized'
143
143
144 # execute some files so that the classes we need will be defined on the engines:
144 # execute some files so that the classes we need will be defined on the engines:
145 view.run('RectPartitioner.py')
145 view.run('RectPartitioner.py')
146 view.run('wavesolver.py')
146 view.run('wavesolver.py')
147
147
148 # setup remote partitioner
148 # setup remote partitioner
149 # note that Reference means that the argument passed to setup_partitioner will be the
149 # note that Reference means that the argument passed to setup_partitioner will be the
150 # object named 'my_id' in the engine's namespace
150 # object named 'my_id' in the engine's namespace
151 view.apply_sync(setup_partitioner, Reference('my_id'), num_procs, grid, partition)
151 view.apply_sync(setup_partitioner, Reference('my_id'), num_procs, grid, partition)
152 # wait for initial communication to complete
152 # wait for initial communication to complete
153 view.execute('mpi.barrier()')
153 view.execute('mpi.barrier()')
154 # setup remote solvers
154 # setup remote solvers
155 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
155 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
156
156
157 # lambda for calling solver.solve:
157 # lambda for calling solver.solve:
158 _solve = lambda *args, **kwargs: solver.solve(*args, **kwargs)
158 _solve = lambda *args, **kwargs: solver.solve(*args, **kwargs)
159
159
160 if ns.scalar:
160 if ns.scalar:
161 impl['inner'] = 'scalar'
161 impl['inner'] = 'scalar'
162 # run first with element-wise Python operations for each cell
162 # run first with element-wise Python operations for each cell
163 t0 = time.time()
163 t0 = time.time()
164 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
164 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
165 if final_test:
165 if final_test:
166 # this sum is performed element-wise as results finish
166 # this sum is performed element-wise as results finish
167 s = sum(ar)
167 s = sum(ar)
168 # the L2 norm (RMS) of the result:
168 # the L2 norm (RMS) of the result:
169 norm = sqrt(s/num_cells)
169 norm = sqrt(s/num_cells)
170 else:
170 else:
171 norm = -1
171 norm = -1
172 t1 = time.time()
172 t1 = time.time()
173 print 'scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
173 print 'scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
174
174
175 impl['inner'] = 'vectorized'
175 impl['inner'] = 'vectorized'
176 # setup new solvers
176 # setup new solvers
177 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
177 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
178 view.execute('mpi.barrier()')
178 view.execute('mpi.barrier()')
179
179
180 # run again with numpy vectorized inner-implementation
180 # run again with numpy vectorized inner-implementation
181 t0 = time.time()
181 t0 = time.time()
182 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
182 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
183 if final_test:
183 if final_test:
184 # this sum is performed element-wise as results finish
184 # this sum is performed element-wise as results finish
185 s = sum(ar)
185 s = sum(ar)
186 # the L2 norm (RMS) of the result:
186 # the L2 norm (RMS) of the result:
187 norm = sqrt(s/num_cells)
187 norm = sqrt(s/num_cells)
188 else:
188 else:
189 norm = -1
189 norm = -1
190 t1 = time.time()
190 t1 = time.time()
191 print 'vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
191 print 'vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
192
192
193 # if ns.save is True, then u_hist stores the history of u as a list
193 # if ns.save is True, then u_hist stores the history of u as a list
194 # If the partion scheme is Nx1, then u can be reconstructed via 'gather':
194 # If the partion scheme is Nx1, then u can be reconstructed via 'gather':
195 if ns.save and partition[-1] == 1:
195 if ns.save and partition[-1] == 1:
196 import pylab
196 import matplotlib.pyplot as plt
197 view.execute('u_last=u_hist[-1]')
197 view.execute('u_last=u_hist[-1]')
198 # map mpi IDs to IPython IDs, which may not match
198 # map mpi IDs to IPython IDs, which may not match
199 ranks = view['my_id']
199 ranks = view['my_id']
200 targets = range(len(ranks))
200 targets = range(len(ranks))
201 for idx in range(len(ranks)):
201 for idx in range(len(ranks)):
202 targets[idx] = ranks.index(idx)
202 targets[idx] = ranks.index(idx)
203 u_last = rc[targets].gather('u_last', block=True)
203 u_last = rc[targets].gather('u_last', block=True)
204 pylab.pcolor(u_last)
204 plt.pcolor(u_last)
205 pylab.show()
205 plt.show()
@@ -1,209 +1,209 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """
2 """
3 A simple python program of solving a 2D wave equation in parallel.
3 A simple python program of solving a 2D wave equation in parallel.
4 Domain partitioning and inter-processor communication
4 Domain partitioning and inter-processor communication
5 are done by an object of class ZMQRectPartitioner2D
5 are done by an object of class ZMQRectPartitioner2D
6 (which is a subclass of RectPartitioner2D and uses 0MQ via pyzmq)
6 (which is a subclass of RectPartitioner2D and uses 0MQ via pyzmq)
7
7
8 An example of running the program is (8 processors, 4x2 partition,
8 An example of running the program is (8 processors, 4x2 partition,
9 200x200 grid cells)::
9 200x200 grid cells)::
10
10
11 $ ipcluster start -n 8 # start 8 engines
11 $ ipcluster start -n 8 # start 8 engines
12 $ python parallelwave.py --grid 200 200 --partition 4 2
12 $ python parallelwave.py --grid 200 200 --partition 4 2
13
13
14 See also parallelwave-mpi, which runs the same program, but uses MPI
14 See also parallelwave-mpi, which runs the same program, but uses MPI
15 (via mpi4py) for the inter-engine communication.
15 (via mpi4py) for the inter-engine communication.
16
16
17 Authors
17 Authors
18 -------
18 -------
19
19
20 * Xing Cai
20 * Xing Cai
21 * Min Ragan-Kelley
21 * Min Ragan-Kelley
22
22
23 """
23 """
24 #
24 #
25 import sys
25 import sys
26 import time
26 import time
27
27
28 from numpy import exp, zeros, newaxis, sqrt
28 from numpy import exp, zeros, newaxis, sqrt
29
29
30 from IPython.external import argparse
30 from IPython.external import argparse
31 from IPython.parallel import Client, Reference
31 from IPython.parallel import Client, Reference
32
32
33 def setup_partitioner(comm, addrs, index, num_procs, gnum_cells, parts):
33 def setup_partitioner(comm, addrs, index, num_procs, gnum_cells, parts):
34 """create a partitioner in the engine namespace"""
34 """create a partitioner in the engine namespace"""
35 global partitioner
35 global partitioner
36 p = ZMQRectPartitioner2D(comm, addrs, my_id=index, num_procs=num_procs)
36 p = ZMQRectPartitioner2D(comm, addrs, my_id=index, num_procs=num_procs)
37 p.redim(global_num_cells=gnum_cells, num_parts=parts)
37 p.redim(global_num_cells=gnum_cells, num_parts=parts)
38 p.prepare_communication()
38 p.prepare_communication()
39 # put the partitioner into the global namespace:
39 # put the partitioner into the global namespace:
40 partitioner=p
40 partitioner=p
41
41
42 def setup_solver(*args, **kwargs):
42 def setup_solver(*args, **kwargs):
43 """create a WaveSolver in the engine namespace."""
43 """create a WaveSolver in the engine namespace."""
44 global solver
44 global solver
45 solver = WaveSolver(*args, **kwargs)
45 solver = WaveSolver(*args, **kwargs)
46
46
47 def wave_saver(u, x, y, t):
47 def wave_saver(u, x, y, t):
48 """save the wave state for each timestep."""
48 """save the wave state for each timestep."""
49 global u_hist
49 global u_hist
50 global t_hist
50 global t_hist
51 t_hist.append(t)
51 t_hist.append(t)
52 u_hist.append(1.0*u)
52 u_hist.append(1.0*u)
53
53
54
54
55 # main program:
55 # main program:
56 if __name__ == '__main__':
56 if __name__ == '__main__':
57
57
58 parser = argparse.ArgumentParser()
58 parser = argparse.ArgumentParser()
59 paa = parser.add_argument
59 paa = parser.add_argument
60 paa('--grid', '-g',
60 paa('--grid', '-g',
61 type=int, nargs=2, default=[100,100], dest='grid',
61 type=int, nargs=2, default=[100,100], dest='grid',
62 help="Cells in the grid, e.g. --grid 100 200")
62 help="Cells in the grid, e.g. --grid 100 200")
63 paa('--partition', '-p',
63 paa('--partition', '-p',
64 type=int, nargs=2, default=None,
64 type=int, nargs=2, default=None,
65 help="Process partition grid, e.g. --partition 4 2 for 4x2")
65 help="Process partition grid, e.g. --partition 4 2 for 4x2")
66 paa('-c',
66 paa('-c',
67 type=float, default=1.,
67 type=float, default=1.,
68 help="Wave speed (I think)")
68 help="Wave speed (I think)")
69 paa('-Ly',
69 paa('-Ly',
70 type=float, default=1.,
70 type=float, default=1.,
71 help="system size (in y)")
71 help="system size (in y)")
72 paa('-Lx',
72 paa('-Lx',
73 type=float, default=1.,
73 type=float, default=1.,
74 help="system size (in x)")
74 help="system size (in x)")
75 paa('-t', '--tstop',
75 paa('-t', '--tstop',
76 type=float, default=1.,
76 type=float, default=1.,
77 help="Time units to run")
77 help="Time units to run")
78 paa('--profile',
78 paa('--profile',
79 type=unicode, default=u'default',
79 type=unicode, default=u'default',
80 help="Specify the ipcluster profile for the client to connect to.")
80 help="Specify the ipcluster profile for the client to connect to.")
81 paa('--save',
81 paa('--save',
82 action='store_true',
82 action='store_true',
83 help="Add this flag to save the time/wave history during the run.")
83 help="Add this flag to save the time/wave history during the run.")
84 paa('--scalar',
84 paa('--scalar',
85 action='store_true',
85 action='store_true',
86 help="Also run with scalar interior implementation, to see vector speedup.")
86 help="Also run with scalar interior implementation, to see vector speedup.")
87
87
88 ns = parser.parse_args()
88 ns = parser.parse_args()
89 # set up arguments
89 # set up arguments
90 grid = ns.grid
90 grid = ns.grid
91 partition = ns.partition
91 partition = ns.partition
92 Lx = ns.Lx
92 Lx = ns.Lx
93 Ly = ns.Ly
93 Ly = ns.Ly
94 c = ns.c
94 c = ns.c
95 tstop = ns.tstop
95 tstop = ns.tstop
96 if ns.save:
96 if ns.save:
97 user_action = wave_saver
97 user_action = wave_saver
98 else:
98 else:
99 user_action = None
99 user_action = None
100
100
101 num_cells = 1.0*(grid[0]-1)*(grid[1]-1)
101 num_cells = 1.0*(grid[0]-1)*(grid[1]-1)
102 final_test = True
102 final_test = True
103
103
104 # create the Client
104 # create the Client
105 rc = Client(profile=ns.profile)
105 rc = Client(profile=ns.profile)
106 num_procs = len(rc.ids)
106 num_procs = len(rc.ids)
107
107
108 if partition is None:
108 if partition is None:
109 partition = [num_procs,1]
109 partition = [num_procs,1]
110 else:
110 else:
111 num_procs = min(num_procs, partition[0]*partition[1])
111 num_procs = min(num_procs, partition[0]*partition[1])
112
112
113 assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs)
113 assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs)
114
114
115 # construct the View:
115 # construct the View:
116 view = rc[:num_procs]
116 view = rc[:num_procs]
117 print("Running %s system on %s processes until %f"%(grid, partition, tstop))
117 print("Running %s system on %s processes until %f"%(grid, partition, tstop))
118
118
119 # functions defining initial/boundary/source conditions
119 # functions defining initial/boundary/source conditions
120 def I(x,y):
120 def I(x,y):
121 from numpy import exp
121 from numpy import exp
122 return 1.5*exp(-100*((x-0.5)**2+(y-0.5)**2))
122 return 1.5*exp(-100*((x-0.5)**2+(y-0.5)**2))
123 def f(x,y,t):
123 def f(x,y,t):
124 return 0.0
124 return 0.0
125 # from numpy import exp,sin
125 # from numpy import exp,sin
126 # return 10*exp(-(x - sin(100*t))**2)
126 # return 10*exp(-(x - sin(100*t))**2)
127 def bc(x,y,t):
127 def bc(x,y,t):
128 return 0.0
128 return 0.0
129
129
130 # initialize t_hist/u_hist for saving the state at each step (optional)
130 # initialize t_hist/u_hist for saving the state at each step (optional)
131 view['t_hist'] = []
131 view['t_hist'] = []
132 view['u_hist'] = []
132 view['u_hist'] = []
133
133
134 # set vector/scalar implementation details
134 # set vector/scalar implementation details
135 impl = {}
135 impl = {}
136 impl['ic'] = 'vectorized'
136 impl['ic'] = 'vectorized'
137 impl['inner'] = 'scalar'
137 impl['inner'] = 'scalar'
138 impl['bc'] = 'vectorized'
138 impl['bc'] = 'vectorized'
139
139
140 # execute some files so that the classes we need will be defined on the engines:
140 # execute some files so that the classes we need will be defined on the engines:
141 view.execute('import numpy')
141 view.execute('import numpy')
142 view.run('communicator.py')
142 view.run('communicator.py')
143 view.run('RectPartitioner.py')
143 view.run('RectPartitioner.py')
144 view.run('wavesolver.py')
144 view.run('wavesolver.py')
145
145
146 # scatter engine IDs
146 # scatter engine IDs
147 view.scatter('my_id', range(num_procs), flatten=True)
147 view.scatter('my_id', range(num_procs), flatten=True)
148
148
149 # create the engine connectors
149 # create the engine connectors
150 view.execute('com = EngineCommunicator()')
150 view.execute('com = EngineCommunicator()')
151
151
152 # gather the connection information into a single dict
152 # gather the connection information into a single dict
153 ar = view.apply_async(lambda : com.info)
153 ar = view.apply_async(lambda : com.info)
154 peers = ar.get_dict()
154 peers = ar.get_dict()
155 # print peers
155 # print peers
156 # this is a dict, keyed by engine ID, of the connection info for the EngineCommunicators
156 # this is a dict, keyed by engine ID, of the connection info for the EngineCommunicators
157
157
158 # setup remote partitioner
158 # setup remote partitioner
159 # note that Reference means that the argument passed to setup_partitioner will be the
159 # note that Reference means that the argument passed to setup_partitioner will be the
160 # object named 'com' in the engine's namespace
160 # object named 'com' in the engine's namespace
161 view.apply_sync(setup_partitioner, Reference('com'), peers, Reference('my_id'), num_procs, grid, partition)
161 view.apply_sync(setup_partitioner, Reference('com'), peers, Reference('my_id'), num_procs, grid, partition)
162 time.sleep(1)
162 time.sleep(1)
163 # convenience lambda to call solver.solve:
163 # convenience lambda to call solver.solve:
164 _solve = lambda *args, **kwargs: solver.solve(*args, **kwargs)
164 _solve = lambda *args, **kwargs: solver.solve(*args, **kwargs)
165
165
166 if ns.scalar:
166 if ns.scalar:
167 impl['inner'] = 'scalar'
167 impl['inner'] = 'scalar'
168 # setup remote solvers
168 # setup remote solvers
169 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly, partitioner=Reference('partitioner'), dt=0,implementation=impl)
169 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly, partitioner=Reference('partitioner'), dt=0,implementation=impl)
170
170
171 # run first with element-wise Python operations for each cell
171 # run first with element-wise Python operations for each cell
172 t0 = time.time()
172 t0 = time.time()
173 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
173 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
174 if final_test:
174 if final_test:
175 # this sum is performed element-wise as results finish
175 # this sum is performed element-wise as results finish
176 s = sum(ar)
176 s = sum(ar)
177 # the L2 norm (RMS) of the result:
177 # the L2 norm (RMS) of the result:
178 norm = sqrt(s/num_cells)
178 norm = sqrt(s/num_cells)
179 else:
179 else:
180 norm = -1
180 norm = -1
181 t1 = time.time()
181 t1 = time.time()
182 print('scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm))
182 print('scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm))
183
183
184 # run again with faster numpy-vectorized inner implementation:
184 # run again with faster numpy-vectorized inner implementation:
185 impl['inner'] = 'vectorized'
185 impl['inner'] = 'vectorized'
186 # setup remote solvers
186 # setup remote solvers
187 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
187 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
188
188
189 t0 = time.time()
189 t0 = time.time()
190
190
191 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
191 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test, user_action=user_action)
192 if final_test:
192 if final_test:
193 # this sum is performed element-wise as results finish
193 # this sum is performed element-wise as results finish
194 s = sum(ar)
194 s = sum(ar)
195 # the L2 norm (RMS) of the result:
195 # the L2 norm (RMS) of the result:
196 norm = sqrt(s/num_cells)
196 norm = sqrt(s/num_cells)
197 else:
197 else:
198 norm = -1
198 norm = -1
199 t1 = time.time()
199 t1 = time.time()
200 print('vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm))
200 print('vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm))
201
201
202 # if ns.save is True, then u_hist stores the history of u as a list
202 # if ns.save is True, then u_hist stores the history of u as a list
203 # If the partion scheme is Nx1, then u can be reconstructed via 'gather':
203 # If the partion scheme is Nx1, then u can be reconstructed via 'gather':
204 if ns.save and partition[-1] == 1:
204 if ns.save and partition[-1] == 1:
205 import pylab
205 import matplotlib.pyplot as plt
206 view.execute('u_last=u_hist[-1]')
206 view.execute('u_last=u_hist[-1]')
207 u_last = view.gather('u_last', block=True)
207 u_last = view.gather('u_last', block=True)
208 pylab.pcolor(u_last)
208 plt.pcolor(u_last)
209 pylab.show()
209 plt.show()
@@ -1,23 +1,23 b''
1 """Manual test for figure.show() in the inline matplotlib backend.
1 """Manual test for figure.show() in the inline matplotlib backend.
2
2
3 This script should be loaded for interactive use (via %load) into a qtconsole
3 This script should be loaded for interactive use (via %load) into a qtconsole
4 or notebook initialized with the pylab inline backend.
4 or notebook initialized with the inline backend.
5
5
6 Expected behavior: only *one* copy of the figure is shown.
6 Expected behavior: only *one* copy of the figure is shown.
7
7
8
8
9 For further details:
9 For further details:
10 https://github.com/ipython/ipython/issues/1612
10 https://github.com/ipython/ipython/issues/1612
11 https://github.com/matplotlib/matplotlib/issues/835
11 https://github.com/matplotlib/matplotlib/issues/835
12 """
12 """
13
13
14 import numpy as np
14 import numpy as np
15 import matplotlib.pyplot as plt
15 import matplotlib.pyplot as plt
16
16
17 plt.ioff()
17 plt.ioff()
18 x = np.random.uniform(-5, 5, size=(100))
18 x = np.random.uniform(-5, 5, size=(100))
19 y = np.random.uniform(-5, 5, size=(100))
19 y = np.random.uniform(-5, 5, size=(100))
20 f = plt.figure()
20 f = plt.figure()
21 plt.scatter(x, y)
21 plt.scatter(x, y)
22 plt.plot(y)
22 plt.plot(y)
23 f.show()
23 f.show()
@@ -1,680 +1,680 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module defines the things that are used in setup.py for building IPython
3 This module defines the things that are used in setup.py for building IPython
4
4
5 This includes:
5 This includes:
6
6
7 * The basic arguments to setup
7 * The basic arguments to setup
8 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
9 * A function for checking dependencies.
9 * A function for checking dependencies.
10 """
10 """
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import errno
23 import errno
24 import os
24 import os
25 import sys
25 import sys
26
26
27 from distutils.command.build_py import build_py
27 from distutils.command.build_py import build_py
28 from distutils.command.build_scripts import build_scripts
28 from distutils.command.build_scripts import build_scripts
29 from distutils.command.install import install
29 from distutils.command.install import install
30 from distutils.command.install_scripts import install_scripts
30 from distutils.command.install_scripts import install_scripts
31 from distutils.cmd import Command
31 from distutils.cmd import Command
32 from glob import glob
32 from glob import glob
33 from subprocess import call
33 from subprocess import call
34
34
35 from setupext import install_data_ext
35 from setupext import install_data_ext
36
36
37 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
38 # Useful globals and utility functions
38 # Useful globals and utility functions
39 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
40
40
41 # A few handy globals
41 # A few handy globals
42 isfile = os.path.isfile
42 isfile = os.path.isfile
43 pjoin = os.path.join
43 pjoin = os.path.join
44 repo_root = os.path.dirname(os.path.abspath(__file__))
44 repo_root = os.path.dirname(os.path.abspath(__file__))
45
45
46 def oscmd(s):
46 def oscmd(s):
47 print(">", s)
47 print(">", s)
48 os.system(s)
48 os.system(s)
49
49
50 # Py3 compatibility hacks, without assuming IPython itself is installed with
50 # Py3 compatibility hacks, without assuming IPython itself is installed with
51 # the full py3compat machinery.
51 # the full py3compat machinery.
52
52
53 try:
53 try:
54 execfile
54 execfile
55 except NameError:
55 except NameError:
56 def execfile(fname, globs, locs=None):
56 def execfile(fname, globs, locs=None):
57 locs = locs or globs
57 locs = locs or globs
58 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
58 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
59
59
60 # A little utility we'll need below, since glob() does NOT allow you to do
60 # A little utility we'll need below, since glob() does NOT allow you to do
61 # exclusion on multiple endings!
61 # exclusion on multiple endings!
62 def file_doesnt_endwith(test,endings):
62 def file_doesnt_endwith(test,endings):
63 """Return true if test is a file and its name does NOT end with any
63 """Return true if test is a file and its name does NOT end with any
64 of the strings listed in endings."""
64 of the strings listed in endings."""
65 if not isfile(test):
65 if not isfile(test):
66 return False
66 return False
67 for e in endings:
67 for e in endings:
68 if test.endswith(e):
68 if test.endswith(e):
69 return False
69 return False
70 return True
70 return True
71
71
72 #---------------------------------------------------------------------------
72 #---------------------------------------------------------------------------
73 # Basic project information
73 # Basic project information
74 #---------------------------------------------------------------------------
74 #---------------------------------------------------------------------------
75
75
76 # release.py contains version, authors, license, url, keywords, etc.
76 # release.py contains version, authors, license, url, keywords, etc.
77 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
77 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
78
78
79 # Create a dict with the basic information
79 # Create a dict with the basic information
80 # This dict is eventually passed to setup after additional keys are added.
80 # This dict is eventually passed to setup after additional keys are added.
81 setup_args = dict(
81 setup_args = dict(
82 name = name,
82 name = name,
83 version = version,
83 version = version,
84 description = description,
84 description = description,
85 long_description = long_description,
85 long_description = long_description,
86 author = author,
86 author = author,
87 author_email = author_email,
87 author_email = author_email,
88 url = url,
88 url = url,
89 download_url = download_url,
89 download_url = download_url,
90 license = license,
90 license = license,
91 platforms = platforms,
91 platforms = platforms,
92 keywords = keywords,
92 keywords = keywords,
93 classifiers = classifiers,
93 classifiers = classifiers,
94 cmdclass = {'install_data': install_data_ext},
94 cmdclass = {'install_data': install_data_ext},
95 )
95 )
96
96
97
97
98 #---------------------------------------------------------------------------
98 #---------------------------------------------------------------------------
99 # Find packages
99 # Find packages
100 #---------------------------------------------------------------------------
100 #---------------------------------------------------------------------------
101
101
102 def find_packages():
102 def find_packages():
103 """
103 """
104 Find all of IPython's packages.
104 Find all of IPython's packages.
105 """
105 """
106 excludes = ['deathrow', 'quarantine']
106 excludes = ['deathrow', 'quarantine']
107 packages = []
107 packages = []
108 for dir,subdirs,files in os.walk('IPython'):
108 for dir,subdirs,files in os.walk('IPython'):
109 package = dir.replace(os.path.sep, '.')
109 package = dir.replace(os.path.sep, '.')
110 if any(package.startswith('IPython.'+exc) for exc in excludes):
110 if any(package.startswith('IPython.'+exc) for exc in excludes):
111 # package is to be excluded (e.g. deathrow)
111 # package is to be excluded (e.g. deathrow)
112 continue
112 continue
113 if '__init__.py' not in files:
113 if '__init__.py' not in files:
114 # not a package
114 # not a package
115 continue
115 continue
116 packages.append(package)
116 packages.append(package)
117 return packages
117 return packages
118
118
119 #---------------------------------------------------------------------------
119 #---------------------------------------------------------------------------
120 # Find package data
120 # Find package data
121 #---------------------------------------------------------------------------
121 #---------------------------------------------------------------------------
122
122
123 def find_package_data():
123 def find_package_data():
124 """
124 """
125 Find IPython's package_data.
125 Find IPython's package_data.
126 """
126 """
127 # This is not enough for these things to appear in an sdist.
127 # This is not enough for these things to appear in an sdist.
128 # We need to muck with the MANIFEST to get this to work
128 # We need to muck with the MANIFEST to get this to work
129
129
130 # exclude components from the walk,
130 # exclude components from the walk,
131 # we will build the components separately
131 # we will build the components separately
132 excludes = ['components']
132 excludes = ['components']
133
133
134 # add 'static/' prefix to exclusions, and tuplify for use in startswith
134 # add 'static/' prefix to exclusions, and tuplify for use in startswith
135 excludes = tuple([pjoin('static', ex) for ex in excludes])
135 excludes = tuple([pjoin('static', ex) for ex in excludes])
136
136
137 # walk notebook resources:
137 # walk notebook resources:
138 cwd = os.getcwd()
138 cwd = os.getcwd()
139 os.chdir(os.path.join('IPython', 'html'))
139 os.chdir(os.path.join('IPython', 'html'))
140 static_data = []
140 static_data = []
141 for parent, dirs, files in os.walk('static'):
141 for parent, dirs, files in os.walk('static'):
142 if parent.startswith(excludes):
142 if parent.startswith(excludes):
143 continue
143 continue
144 for f in files:
144 for f in files:
145 static_data.append(pjoin(parent, f))
145 static_data.append(pjoin(parent, f))
146 components = pjoin("static", "components")
146 components = pjoin("static", "components")
147 # select the components we actually need to install
147 # select the components we actually need to install
148 # (there are lots of resources we bundle for sdist-reasons that we don't actually use)
148 # (there are lots of resources we bundle for sdist-reasons that we don't actually use)
149 static_data.extend([
149 static_data.extend([
150 pjoin(components, "backbone", "backbone-min.js"),
150 pjoin(components, "backbone", "backbone-min.js"),
151 pjoin(components, "bootstrap", "bootstrap", "js", "bootstrap.min.js"),
151 pjoin(components, "bootstrap", "bootstrap", "js", "bootstrap.min.js"),
152 pjoin(components, "font-awesome", "font", "*.*"),
152 pjoin(components, "font-awesome", "font", "*.*"),
153 pjoin(components, "highlight.js", "build", "highlight.pack.js"),
153 pjoin(components, "highlight.js", "build", "highlight.pack.js"),
154 pjoin(components, "jquery", "jquery.min.js"),
154 pjoin(components, "jquery", "jquery.min.js"),
155 pjoin(components, "jquery-ui", "ui", "minified", "jquery-ui.min.js"),
155 pjoin(components, "jquery-ui", "ui", "minified", "jquery-ui.min.js"),
156 pjoin(components, "jquery-ui", "themes", "smoothness", "jquery-ui.min.css"),
156 pjoin(components, "jquery-ui", "themes", "smoothness", "jquery-ui.min.css"),
157 pjoin(components, "marked", "lib", "marked.js"),
157 pjoin(components, "marked", "lib", "marked.js"),
158 pjoin(components, "requirejs", "require.js"),
158 pjoin(components, "requirejs", "require.js"),
159 pjoin(components, "underscore", "underscore-min.js"),
159 pjoin(components, "underscore", "underscore-min.js"),
160 ])
160 ])
161
161
162 # Ship all of Codemirror's CSS and JS
162 # Ship all of Codemirror's CSS and JS
163 for parent, dirs, files in os.walk(pjoin(components, 'codemirror')):
163 for parent, dirs, files in os.walk(pjoin(components, 'codemirror')):
164 for f in files:
164 for f in files:
165 if f.endswith(('.js', '.css')):
165 if f.endswith(('.js', '.css')):
166 static_data.append(pjoin(parent, f))
166 static_data.append(pjoin(parent, f))
167
167
168 os.chdir(os.path.join('tests',))
168 os.chdir(os.path.join('tests',))
169 js_tests = glob('casperjs/*.*') + glob('casperjs/*/*')
169 js_tests = glob('*.js') + glob('*/*.js')
170
170
171 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
171 os.chdir(os.path.join(cwd, 'IPython', 'nbconvert'))
172 nbconvert_templates = [os.path.join(dirpath, '*.*')
172 nbconvert_templates = [os.path.join(dirpath, '*.*')
173 for dirpath, _, _ in os.walk('templates')]
173 for dirpath, _, _ in os.walk('templates')]
174
174
175 os.chdir(cwd)
175 os.chdir(cwd)
176
176
177 package_data = {
177 package_data = {
178 'IPython.config.profile' : ['README*', '*/*.py'],
178 'IPython.config.profile' : ['README*', '*/*.py'],
179 'IPython.core.tests' : ['*.png', '*.jpg'],
179 'IPython.core.tests' : ['*.png', '*.jpg'],
180 'IPython.lib.tests' : ['*.wav'],
180 'IPython.lib.tests' : ['*.wav'],
181 'IPython.testing.plugin' : ['*.txt'],
181 'IPython.testing.plugin' : ['*.txt'],
182 'IPython.html' : ['templates/*'] + static_data,
182 'IPython.html' : ['templates/*'] + static_data,
183 'IPython.html.tests' : js_tests,
183 'IPython.html.tests' : js_tests,
184 'IPython.qt.console' : ['resources/icon/*.svg'],
184 'IPython.qt.console' : ['resources/icon/*.svg'],
185 'IPython.nbconvert' : nbconvert_templates +
185 'IPython.nbconvert' : nbconvert_templates +
186 ['tests/files/*.*', 'exporters/tests/files/*.*'],
186 ['tests/files/*.*', 'exporters/tests/files/*.*'],
187 'IPython.nbconvert.filters' : ['marked.js'],
187 'IPython.nbconvert.filters' : ['marked.js'],
188 'IPython.nbformat' : ['tests/*.ipynb']
188 'IPython.nbformat' : ['tests/*.ipynb']
189 }
189 }
190
190
191 # verify that package_data makes sense
191 # verify that package_data makes sense
192 for pkg, data in package_data.items():
192 for pkg, data in package_data.items():
193 pkg_root = pjoin(*pkg.split('.'))
193 pkg_root = pjoin(*pkg.split('.'))
194 for d in data:
194 for d in data:
195 path = pjoin(pkg_root, d)
195 path = pjoin(pkg_root, d)
196 if '*' in path:
196 if '*' in path:
197 assert len(glob(path)) > 0, "No files match pattern %s" % path
197 assert len(glob(path)) > 0, "No files match pattern %s" % path
198 else:
198 else:
199 assert os.path.exists(path), "Missing package data: %s" % path
199 assert os.path.exists(path), "Missing package data: %s" % path
200
200
201 return package_data
201 return package_data
202
202
203
203
204 #---------------------------------------------------------------------------
204 #---------------------------------------------------------------------------
205 # Find data files
205 # Find data files
206 #---------------------------------------------------------------------------
206 #---------------------------------------------------------------------------
207
207
208 def make_dir_struct(tag,base,out_base):
208 def make_dir_struct(tag,base,out_base):
209 """Make the directory structure of all files below a starting dir.
209 """Make the directory structure of all files below a starting dir.
210
210
211 This is just a convenience routine to help build a nested directory
211 This is just a convenience routine to help build a nested directory
212 hierarchy because distutils is too stupid to do this by itself.
212 hierarchy because distutils is too stupid to do this by itself.
213
213
214 XXX - this needs a proper docstring!
214 XXX - this needs a proper docstring!
215 """
215 """
216
216
217 # we'll use these a lot below
217 # we'll use these a lot below
218 lbase = len(base)
218 lbase = len(base)
219 pathsep = os.path.sep
219 pathsep = os.path.sep
220 lpathsep = len(pathsep)
220 lpathsep = len(pathsep)
221
221
222 out = []
222 out = []
223 for (dirpath,dirnames,filenames) in os.walk(base):
223 for (dirpath,dirnames,filenames) in os.walk(base):
224 # we need to strip out the dirpath from the base to map it to the
224 # we need to strip out the dirpath from the base to map it to the
225 # output (installation) path. This requires possibly stripping the
225 # output (installation) path. This requires possibly stripping the
226 # path separator, because otherwise pjoin will not work correctly
226 # path separator, because otherwise pjoin will not work correctly
227 # (pjoin('foo/','/bar') returns '/bar').
227 # (pjoin('foo/','/bar') returns '/bar').
228
228
229 dp_eff = dirpath[lbase:]
229 dp_eff = dirpath[lbase:]
230 if dp_eff.startswith(pathsep):
230 if dp_eff.startswith(pathsep):
231 dp_eff = dp_eff[lpathsep:]
231 dp_eff = dp_eff[lpathsep:]
232 # The output path must be anchored at the out_base marker
232 # The output path must be anchored at the out_base marker
233 out_path = pjoin(out_base,dp_eff)
233 out_path = pjoin(out_base,dp_eff)
234 # Now we can generate the final filenames. Since os.walk only produces
234 # Now we can generate the final filenames. Since os.walk only produces
235 # filenames, we must join back with the dirpath to get full valid file
235 # filenames, we must join back with the dirpath to get full valid file
236 # paths:
236 # paths:
237 pfiles = [pjoin(dirpath,f) for f in filenames]
237 pfiles = [pjoin(dirpath,f) for f in filenames]
238 # Finally, generate the entry we need, which is a pari of (output
238 # Finally, generate the entry we need, which is a pari of (output
239 # path, files) for use as a data_files parameter in install_data.
239 # path, files) for use as a data_files parameter in install_data.
240 out.append((out_path, pfiles))
240 out.append((out_path, pfiles))
241
241
242 return out
242 return out
243
243
244
244
245 def find_data_files():
245 def find_data_files():
246 """
246 """
247 Find IPython's data_files.
247 Find IPython's data_files.
248
248
249 Just man pages at this point.
249 Just man pages at this point.
250 """
250 """
251
251
252 manpagebase = pjoin('share', 'man', 'man1')
252 manpagebase = pjoin('share', 'man', 'man1')
253
253
254 # Simple file lists can be made by hand
254 # Simple file lists can be made by hand
255 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
255 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
256 if not manpages:
256 if not manpages:
257 # When running from a source tree, the manpages aren't gzipped
257 # When running from a source tree, the manpages aren't gzipped
258 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
258 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
259
259
260 # And assemble the entire output list
260 # And assemble the entire output list
261 data_files = [ (manpagebase, manpages) ]
261 data_files = [ (manpagebase, manpages) ]
262
262
263 return data_files
263 return data_files
264
264
265
265
266 def make_man_update_target(manpage):
266 def make_man_update_target(manpage):
267 """Return a target_update-compliant tuple for the given manpage.
267 """Return a target_update-compliant tuple for the given manpage.
268
268
269 Parameters
269 Parameters
270 ----------
270 ----------
271 manpage : string
271 manpage : string
272 Name of the manpage, must include the section number (trailing number).
272 Name of the manpage, must include the section number (trailing number).
273
273
274 Example
274 Example
275 -------
275 -------
276
276
277 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
277 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
278 ('docs/man/ipython.1.gz',
278 ('docs/man/ipython.1.gz',
279 ['docs/man/ipython.1'],
279 ['docs/man/ipython.1'],
280 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
280 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
281 """
281 """
282 man_dir = pjoin('docs', 'man')
282 man_dir = pjoin('docs', 'man')
283 manpage_gz = manpage + '.gz'
283 manpage_gz = manpage + '.gz'
284 manpath = pjoin(man_dir, manpage)
284 manpath = pjoin(man_dir, manpage)
285 manpath_gz = pjoin(man_dir, manpage_gz)
285 manpath_gz = pjoin(man_dir, manpage_gz)
286 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
286 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
287 locals() )
287 locals() )
288 return (manpath_gz, [manpath], gz_cmd)
288 return (manpath_gz, [manpath], gz_cmd)
289
289
290 # The two functions below are copied from IPython.utils.path, so we don't need
290 # The two functions below are copied from IPython.utils.path, so we don't need
291 # to import IPython during setup, which fails on Python 3.
291 # to import IPython during setup, which fails on Python 3.
292
292
293 def target_outdated(target,deps):
293 def target_outdated(target,deps):
294 """Determine whether a target is out of date.
294 """Determine whether a target is out of date.
295
295
296 target_outdated(target,deps) -> 1/0
296 target_outdated(target,deps) -> 1/0
297
297
298 deps: list of filenames which MUST exist.
298 deps: list of filenames which MUST exist.
299 target: single filename which may or may not exist.
299 target: single filename which may or may not exist.
300
300
301 If target doesn't exist or is older than any file listed in deps, return
301 If target doesn't exist or is older than any file listed in deps, return
302 true, otherwise return false.
302 true, otherwise return false.
303 """
303 """
304 try:
304 try:
305 target_time = os.path.getmtime(target)
305 target_time = os.path.getmtime(target)
306 except os.error:
306 except os.error:
307 return 1
307 return 1
308 for dep in deps:
308 for dep in deps:
309 dep_time = os.path.getmtime(dep)
309 dep_time = os.path.getmtime(dep)
310 if dep_time > target_time:
310 if dep_time > target_time:
311 #print "For target",target,"Dep failed:",dep # dbg
311 #print "For target",target,"Dep failed:",dep # dbg
312 #print "times (dep,tar):",dep_time,target_time # dbg
312 #print "times (dep,tar):",dep_time,target_time # dbg
313 return 1
313 return 1
314 return 0
314 return 0
315
315
316
316
317 def target_update(target,deps,cmd):
317 def target_update(target,deps,cmd):
318 """Update a target with a given command given a list of dependencies.
318 """Update a target with a given command given a list of dependencies.
319
319
320 target_update(target,deps,cmd) -> runs cmd if target is outdated.
320 target_update(target,deps,cmd) -> runs cmd if target is outdated.
321
321
322 This is just a wrapper around target_outdated() which calls the given
322 This is just a wrapper around target_outdated() which calls the given
323 command if target is outdated."""
323 command if target is outdated."""
324
324
325 if target_outdated(target,deps):
325 if target_outdated(target,deps):
326 os.system(cmd)
326 os.system(cmd)
327
327
328 #---------------------------------------------------------------------------
328 #---------------------------------------------------------------------------
329 # Find scripts
329 # Find scripts
330 #---------------------------------------------------------------------------
330 #---------------------------------------------------------------------------
331
331
332 def find_entry_points():
332 def find_entry_points():
333 """Find IPython's scripts.
333 """Find IPython's scripts.
334
334
335 if entry_points is True:
335 if entry_points is True:
336 return setuptools entry_point-style definitions
336 return setuptools entry_point-style definitions
337 else:
337 else:
338 return file paths of plain scripts [default]
338 return file paths of plain scripts [default]
339
339
340 suffix is appended to script names if entry_points is True, so that the
340 suffix is appended to script names if entry_points is True, so that the
341 Python 3 scripts get named "ipython3" etc.
341 Python 3 scripts get named "ipython3" etc.
342 """
342 """
343 ep = [
343 ep = [
344 'ipython%s = IPython:start_ipython',
344 'ipython%s = IPython:start_ipython',
345 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
345 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
346 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
346 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
347 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
347 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
348 'iptest%s = IPython.testing.iptestcontroller:main',
348 'iptest%s = IPython.testing.iptestcontroller:main',
349 ]
349 ]
350 suffix = str(sys.version_info[0])
350 suffix = str(sys.version_info[0])
351 return [e % '' for e in ep] + [e % suffix for e in ep]
351 return [e % '' for e in ep] + [e % suffix for e in ep]
352
352
353 script_src = """#!{executable}
353 script_src = """#!{executable}
354 # This script was automatically generated by setup.py
354 # This script was automatically generated by setup.py
355 if __name__ == '__main__':
355 if __name__ == '__main__':
356 from {mod} import {func}
356 from {mod} import {func}
357 {func}()
357 {func}()
358 """
358 """
359
359
360 class build_scripts_entrypt(build_scripts):
360 class build_scripts_entrypt(build_scripts):
361 def run(self):
361 def run(self):
362 self.mkpath(self.build_dir)
362 self.mkpath(self.build_dir)
363 outfiles = []
363 outfiles = []
364 for script in find_entry_points():
364 for script in find_entry_points():
365 name, entrypt = script.split('=')
365 name, entrypt = script.split('=')
366 name = name.strip()
366 name = name.strip()
367 entrypt = entrypt.strip()
367 entrypt = entrypt.strip()
368 outfile = os.path.join(self.build_dir, name)
368 outfile = os.path.join(self.build_dir, name)
369 outfiles.append(outfile)
369 outfiles.append(outfile)
370 print('Writing script to', outfile)
370 print('Writing script to', outfile)
371
371
372 mod, func = entrypt.split(':')
372 mod, func = entrypt.split(':')
373 with open(outfile, 'w') as f:
373 with open(outfile, 'w') as f:
374 f.write(script_src.format(executable=sys.executable,
374 f.write(script_src.format(executable=sys.executable,
375 mod=mod, func=func))
375 mod=mod, func=func))
376
376
377 return outfiles, outfiles
377 return outfiles, outfiles
378
378
379 class install_lib_symlink(Command):
379 class install_lib_symlink(Command):
380 user_options = [
380 user_options = [
381 ('install-dir=', 'd', "directory to install to"),
381 ('install-dir=', 'd', "directory to install to"),
382 ]
382 ]
383
383
384 def initialize_options(self):
384 def initialize_options(self):
385 self.install_dir = None
385 self.install_dir = None
386
386
387 def finalize_options(self):
387 def finalize_options(self):
388 self.set_undefined_options('symlink',
388 self.set_undefined_options('symlink',
389 ('install_lib', 'install_dir'),
389 ('install_lib', 'install_dir'),
390 )
390 )
391
391
392 def run(self):
392 def run(self):
393 if sys.platform == 'win32':
393 if sys.platform == 'win32':
394 raise Exception("This doesn't work on Windows.")
394 raise Exception("This doesn't work on Windows.")
395 pkg = os.path.join(os.getcwd(), 'IPython')
395 pkg = os.path.join(os.getcwd(), 'IPython')
396 dest = os.path.join(self.install_dir, 'IPython')
396 dest = os.path.join(self.install_dir, 'IPython')
397 if os.path.islink(dest):
397 if os.path.islink(dest):
398 print('removing existing symlink at %s' % dest)
398 print('removing existing symlink at %s' % dest)
399 os.unlink(dest)
399 os.unlink(dest)
400 print('symlinking %s -> %s' % (pkg, dest))
400 print('symlinking %s -> %s' % (pkg, dest))
401 os.symlink(pkg, dest)
401 os.symlink(pkg, dest)
402
402
403 class unsymlink(install):
403 class unsymlink(install):
404 def run(self):
404 def run(self):
405 dest = os.path.join(self.install_lib, 'IPython')
405 dest = os.path.join(self.install_lib, 'IPython')
406 if os.path.islink(dest):
406 if os.path.islink(dest):
407 print('removing symlink at %s' % dest)
407 print('removing symlink at %s' % dest)
408 os.unlink(dest)
408 os.unlink(dest)
409 else:
409 else:
410 print('No symlink exists at %s' % dest)
410 print('No symlink exists at %s' % dest)
411
411
412 class install_symlinked(install):
412 class install_symlinked(install):
413 def run(self):
413 def run(self):
414 if sys.platform == 'win32':
414 if sys.platform == 'win32':
415 raise Exception("This doesn't work on Windows.")
415 raise Exception("This doesn't work on Windows.")
416
416
417 # Run all sub-commands (at least those that need to be run)
417 # Run all sub-commands (at least those that need to be run)
418 for cmd_name in self.get_sub_commands():
418 for cmd_name in self.get_sub_commands():
419 self.run_command(cmd_name)
419 self.run_command(cmd_name)
420
420
421 # 'sub_commands': a list of commands this command might have to run to
421 # 'sub_commands': a list of commands this command might have to run to
422 # get its work done. See cmd.py for more info.
422 # get its work done. See cmd.py for more info.
423 sub_commands = [('install_lib_symlink', lambda self:True),
423 sub_commands = [('install_lib_symlink', lambda self:True),
424 ('install_scripts_sym', lambda self:True),
424 ('install_scripts_sym', lambda self:True),
425 ]
425 ]
426
426
427 class install_scripts_for_symlink(install_scripts):
427 class install_scripts_for_symlink(install_scripts):
428 """Redefined to get options from 'symlink' instead of 'install'.
428 """Redefined to get options from 'symlink' instead of 'install'.
429
429
430 I love distutils almost as much as I love setuptools.
430 I love distutils almost as much as I love setuptools.
431 """
431 """
432 def finalize_options(self):
432 def finalize_options(self):
433 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
433 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
434 self.set_undefined_options('symlink',
434 self.set_undefined_options('symlink',
435 ('install_scripts', 'install_dir'),
435 ('install_scripts', 'install_dir'),
436 ('force', 'force'),
436 ('force', 'force'),
437 ('skip_build', 'skip_build'),
437 ('skip_build', 'skip_build'),
438 )
438 )
439
439
440 #---------------------------------------------------------------------------
440 #---------------------------------------------------------------------------
441 # Verify all dependencies
441 # Verify all dependencies
442 #---------------------------------------------------------------------------
442 #---------------------------------------------------------------------------
443
443
444 def check_for_dependencies():
444 def check_for_dependencies():
445 """Check for IPython's dependencies.
445 """Check for IPython's dependencies.
446
446
447 This function should NOT be called if running under setuptools!
447 This function should NOT be called if running under setuptools!
448 """
448 """
449 from setupext.setupext import (
449 from setupext.setupext import (
450 print_line, print_raw, print_status,
450 print_line, print_raw, print_status,
451 check_for_sphinx, check_for_pygments,
451 check_for_sphinx, check_for_pygments,
452 check_for_nose, check_for_pexpect,
452 check_for_nose, check_for_pexpect,
453 check_for_pyzmq, check_for_readline,
453 check_for_pyzmq, check_for_readline,
454 check_for_jinja2, check_for_tornado
454 check_for_jinja2, check_for_tornado
455 )
455 )
456 print_line()
456 print_line()
457 print_raw("BUILDING IPYTHON")
457 print_raw("BUILDING IPYTHON")
458 print_status('python', sys.version)
458 print_status('python', sys.version)
459 print_status('platform', sys.platform)
459 print_status('platform', sys.platform)
460 if sys.platform == 'win32':
460 if sys.platform == 'win32':
461 print_status('Windows version', sys.getwindowsversion())
461 print_status('Windows version', sys.getwindowsversion())
462
462
463 print_raw("")
463 print_raw("")
464 print_raw("OPTIONAL DEPENDENCIES")
464 print_raw("OPTIONAL DEPENDENCIES")
465
465
466 check_for_sphinx()
466 check_for_sphinx()
467 check_for_pygments()
467 check_for_pygments()
468 check_for_nose()
468 check_for_nose()
469 if os.name == 'posix':
469 if os.name == 'posix':
470 check_for_pexpect()
470 check_for_pexpect()
471 check_for_pyzmq()
471 check_for_pyzmq()
472 check_for_tornado()
472 check_for_tornado()
473 check_for_readline()
473 check_for_readline()
474 check_for_jinja2()
474 check_for_jinja2()
475
475
476 #---------------------------------------------------------------------------
476 #---------------------------------------------------------------------------
477 # VCS related
477 # VCS related
478 #---------------------------------------------------------------------------
478 #---------------------------------------------------------------------------
479
479
480 # utils.submodule has checks for submodule status
480 # utils.submodule has checks for submodule status
481 execfile(pjoin('IPython','utils','submodule.py'), globals())
481 execfile(pjoin('IPython','utils','submodule.py'), globals())
482
482
483 class UpdateSubmodules(Command):
483 class UpdateSubmodules(Command):
484 """Update git submodules
484 """Update git submodules
485
485
486 IPython's external javascript dependencies live in a separate repo.
486 IPython's external javascript dependencies live in a separate repo.
487 """
487 """
488 description = "Update git submodules"
488 description = "Update git submodules"
489 user_options = []
489 user_options = []
490
490
491 def initialize_options(self):
491 def initialize_options(self):
492 pass
492 pass
493
493
494 def finalize_options(self):
494 def finalize_options(self):
495 pass
495 pass
496
496
497 def run(self):
497 def run(self):
498 failure = False
498 failure = False
499 try:
499 try:
500 self.spawn('git submodule init'.split())
500 self.spawn('git submodule init'.split())
501 self.spawn('git submodule update --recursive'.split())
501 self.spawn('git submodule update --recursive'.split())
502 except Exception as e:
502 except Exception as e:
503 failure = e
503 failure = e
504 print(e)
504 print(e)
505
505
506 if not check_submodule_status(repo_root) == 'clean':
506 if not check_submodule_status(repo_root) == 'clean':
507 print("submodules could not be checked out")
507 print("submodules could not be checked out")
508 sys.exit(1)
508 sys.exit(1)
509
509
510
510
511 def git_prebuild(pkg_dir, build_cmd=build_py):
511 def git_prebuild(pkg_dir, build_cmd=build_py):
512 """Return extended build or sdist command class for recording commit
512 """Return extended build or sdist command class for recording commit
513
513
514 records git commit in IPython.utils._sysinfo.commit
514 records git commit in IPython.utils._sysinfo.commit
515
515
516 for use in IPython.utils.sysinfo.sys_info() calls after installation.
516 for use in IPython.utils.sysinfo.sys_info() calls after installation.
517
517
518 Also ensures that submodules exist prior to running
518 Also ensures that submodules exist prior to running
519 """
519 """
520
520
521 class MyBuildPy(build_cmd):
521 class MyBuildPy(build_cmd):
522 ''' Subclass to write commit data into installation tree '''
522 ''' Subclass to write commit data into installation tree '''
523 def run(self):
523 def run(self):
524 build_cmd.run(self)
524 build_cmd.run(self)
525 # this one will only fire for build commands
525 # this one will only fire for build commands
526 if hasattr(self, 'build_lib'):
526 if hasattr(self, 'build_lib'):
527 self._record_commit(self.build_lib)
527 self._record_commit(self.build_lib)
528
528
529 def make_release_tree(self, base_dir, files):
529 def make_release_tree(self, base_dir, files):
530 # this one will fire for sdist
530 # this one will fire for sdist
531 build_cmd.make_release_tree(self, base_dir, files)
531 build_cmd.make_release_tree(self, base_dir, files)
532 self._record_commit(base_dir)
532 self._record_commit(base_dir)
533
533
534 def _record_commit(self, base_dir):
534 def _record_commit(self, base_dir):
535 import subprocess
535 import subprocess
536 proc = subprocess.Popen('git rev-parse --short HEAD',
536 proc = subprocess.Popen('git rev-parse --short HEAD',
537 stdout=subprocess.PIPE,
537 stdout=subprocess.PIPE,
538 stderr=subprocess.PIPE,
538 stderr=subprocess.PIPE,
539 shell=True)
539 shell=True)
540 repo_commit, _ = proc.communicate()
540 repo_commit, _ = proc.communicate()
541 repo_commit = repo_commit.strip().decode("ascii")
541 repo_commit = repo_commit.strip().decode("ascii")
542
542
543 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
543 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
544 if os.path.isfile(out_pth) and not repo_commit:
544 if os.path.isfile(out_pth) and not repo_commit:
545 # nothing to write, don't clobber
545 # nothing to write, don't clobber
546 return
546 return
547
547
548 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
548 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
549
549
550 # remove to avoid overwriting original via hard link
550 # remove to avoid overwriting original via hard link
551 try:
551 try:
552 os.remove(out_pth)
552 os.remove(out_pth)
553 except (IOError, OSError):
553 except (IOError, OSError):
554 pass
554 pass
555 with open(out_pth, 'w') as out_file:
555 with open(out_pth, 'w') as out_file:
556 out_file.writelines([
556 out_file.writelines([
557 '# GENERATED BY setup.py\n',
557 '# GENERATED BY setup.py\n',
558 'commit = "%s"\n' % repo_commit,
558 'commit = "%s"\n' % repo_commit,
559 ])
559 ])
560 return require_submodules(MyBuildPy)
560 return require_submodules(MyBuildPy)
561
561
562
562
563 def require_submodules(command):
563 def require_submodules(command):
564 """decorator for instructing a command to check for submodules before running"""
564 """decorator for instructing a command to check for submodules before running"""
565 class DecoratedCommand(command):
565 class DecoratedCommand(command):
566 def run(self):
566 def run(self):
567 if not check_submodule_status(repo_root) == 'clean':
567 if not check_submodule_status(repo_root) == 'clean':
568 print("submodules missing! Run `setup.py submodule` and try again")
568 print("submodules missing! Run `setup.py submodule` and try again")
569 sys.exit(1)
569 sys.exit(1)
570 command.run(self)
570 command.run(self)
571 return DecoratedCommand
571 return DecoratedCommand
572
572
573 #---------------------------------------------------------------------------
573 #---------------------------------------------------------------------------
574 # bdist related
574 # bdist related
575 #---------------------------------------------------------------------------
575 #---------------------------------------------------------------------------
576
576
577 def get_bdist_wheel():
577 def get_bdist_wheel():
578 """Construct bdist_wheel command for building wheels
578 """Construct bdist_wheel command for building wheels
579
579
580 Constructs py2-none-any tag, instead of py2.7-none-any
580 Constructs py2-none-any tag, instead of py2.7-none-any
581 """
581 """
582 class RequiresWheel(Command):
582 class RequiresWheel(Command):
583 description = "Dummy command for missing bdist_wheel"
583 description = "Dummy command for missing bdist_wheel"
584 user_options = []
584 user_options = []
585
585
586 def initialize_options(self):
586 def initialize_options(self):
587 pass
587 pass
588
588
589 def finalize_options(self):
589 def finalize_options(self):
590 pass
590 pass
591
591
592 def run(self):
592 def run(self):
593 print("bdist_wheel requires the wheel package")
593 print("bdist_wheel requires the wheel package")
594 sys.exit(1)
594 sys.exit(1)
595
595
596 if 'setuptools' not in sys.modules:
596 if 'setuptools' not in sys.modules:
597 return RequiresWheel
597 return RequiresWheel
598 else:
598 else:
599 try:
599 try:
600 from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info
600 from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info
601 except ImportError:
601 except ImportError:
602 return RequiresWheel
602 return RequiresWheel
603
603
604 class bdist_wheel_tag(bdist_wheel):
604 class bdist_wheel_tag(bdist_wheel):
605
605
606 def get_tag(self):
606 def get_tag(self):
607 return ('py%i' % sys.version_info[0], 'none', 'any')
607 return ('py%i' % sys.version_info[0], 'none', 'any')
608
608
609 def add_requirements(self, metadata_path):
609 def add_requirements(self, metadata_path):
610 """transform platform-dependent requirements"""
610 """transform platform-dependent requirements"""
611 pkg_info = read_pkg_info(metadata_path)
611 pkg_info = read_pkg_info(metadata_path)
612 # pkg_info is an email.Message object (?!)
612 # pkg_info is an email.Message object (?!)
613 # we have to remove the unconditional 'readline' and/or 'pyreadline' entries
613 # we have to remove the unconditional 'readline' and/or 'pyreadline' entries
614 # and transform them to conditionals
614 # and transform them to conditionals
615 requires = pkg_info.get_all('Requires-Dist')
615 requires = pkg_info.get_all('Requires-Dist')
616 del pkg_info['Requires-Dist']
616 del pkg_info['Requires-Dist']
617 def _remove_startswith(lis, prefix):
617 def _remove_startswith(lis, prefix):
618 """like list.remove, but with startswith instead of =="""
618 """like list.remove, but with startswith instead of =="""
619 found = False
619 found = False
620 for idx, item in enumerate(lis):
620 for idx, item in enumerate(lis):
621 if item.startswith(prefix):
621 if item.startswith(prefix):
622 found = True
622 found = True
623 break
623 break
624 if found:
624 if found:
625 lis.pop(idx)
625 lis.pop(idx)
626
626
627 for pkg in ("readline", "pyreadline"):
627 for pkg in ("readline", "pyreadline"):
628 _remove_startswith(requires, pkg)
628 _remove_startswith(requires, pkg)
629 requires.append("readline; sys.platform == 'darwin'")
629 requires.append("readline; sys.platform == 'darwin'")
630 requires.append("pyreadline (>=2.0); sys.platform == 'win32'")
630 requires.append("pyreadline (>=2.0); sys.platform == 'win32'")
631 for r in requires:
631 for r in requires:
632 pkg_info['Requires-Dist'] = r
632 pkg_info['Requires-Dist'] = r
633 write_pkg_info(metadata_path, pkg_info)
633 write_pkg_info(metadata_path, pkg_info)
634
634
635 return bdist_wheel_tag
635 return bdist_wheel_tag
636
636
637 #---------------------------------------------------------------------------
637 #---------------------------------------------------------------------------
638 # Notebook related
638 # Notebook related
639 #---------------------------------------------------------------------------
639 #---------------------------------------------------------------------------
640
640
641 class CompileCSS(Command):
641 class CompileCSS(Command):
642 """Recompile Notebook CSS
642 """Recompile Notebook CSS
643
643
644 Regenerate the compiled CSS from LESS sources.
644 Regenerate the compiled CSS from LESS sources.
645
645
646 Requires various dev dependencies, such as fabric and lessc.
646 Requires various dev dependencies, such as fabric and lessc.
647 """
647 """
648 description = "Recompile Notebook CSS"
648 description = "Recompile Notebook CSS"
649 user_options = []
649 user_options = []
650
650
651 def initialize_options(self):
651 def initialize_options(self):
652 pass
652 pass
653
653
654 def finalize_options(self):
654 def finalize_options(self):
655 pass
655 pass
656
656
657 def run(self):
657 def run(self):
658 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
658 call("fab css", shell=True, cwd=pjoin(repo_root, "IPython", "html"))
659
659
660 class JavascriptVersion(Command):
660 class JavascriptVersion(Command):
661 """write the javascript version to notebook javascript"""
661 """write the javascript version to notebook javascript"""
662 description = "Write IPython version to javascript"
662 description = "Write IPython version to javascript"
663 user_options = []
663 user_options = []
664
664
665 def initialize_options(self):
665 def initialize_options(self):
666 pass
666 pass
667
667
668 def finalize_options(self):
668 def finalize_options(self):
669 pass
669 pass
670
670
671 def run(self):
671 def run(self):
672 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
672 nsfile = pjoin(repo_root, "IPython", "html", "static", "base", "js", "namespace.js")
673 with open(nsfile) as f:
673 with open(nsfile) as f:
674 lines = f.readlines()
674 lines = f.readlines()
675 with open(nsfile, 'w') as f:
675 with open(nsfile, 'w') as f:
676 for line in lines:
676 for line in lines:
677 if line.startswith("IPython.version"):
677 if line.startswith("IPython.version"):
678 line = 'IPython.version = "{0}";\n'.format(version)
678 line = 'IPython.version = "{0}";\n'.format(version)
679 f.write(line)
679 f.write(line)
680
680
@@ -1,108 +0,0 b''
1 {
2 "metadata": {
3 "name": "Pylab Switching"
4 },
5 "nbformat": 3,
6 "nbformat_minor": 0,
7 "worksheets": [
8 {
9 "cells": [
10 {
11 "cell_type": "code",
12 "collapsed": false,
13 "input": [
14 "# Should pop up a GUI window\n",
15 "%pylab qt\n",
16 "plot([1,2,3])"
17 ],
18 "language": "python",
19 "metadata": {},
20 "outputs": [
21 {
22 "output_type": "stream",
23 "stream": "stdout",
24 "text": [
25 "\n",
26 "Welcome to pylab, a matplotlib-based Python environment [backend: Qt4Agg].\n",
27 "For more information, type 'help(pylab)'.\n"
28 ]
29 },
30 {
31 "output_type": "pyout",
32 "prompt_number": 3,
33 "text": [
34 "[<matplotlib.lines.Line2D at 0x4566850>]"
35 ]
36 }
37 ],
38 "prompt_number": 3
39 },
40 {
41 "cell_type": "code",
42 "collapsed": false,
43 "input": [
44 "# Should make an inline figure\n",
45 "%pylab inline\n",
46 "plot([1,2,3])"
47 ],
48 "language": "python",
49 "metadata": {},
50 "outputs": [
51 {
52 "output_type": "stream",
53 "stream": "stdout",
54 "text": [
55 "\n",
56 "Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline].\n",
57 "For more information, type 'help(pylab)'.\n"
58 ]
59 },
60 {
61 "output_type": "pyout",
62 "prompt_number": 4,
63 "text": [
64 "[<matplotlib.lines.Line2D at 0x4830ad0>]"
65 ]
66 },
67 {
68 "output_type": "display_data",
69 "png": "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\n"
70 }
71 ],
72 "prompt_number": 4
73 },
74 {
75 "cell_type": "code",
76 "collapsed": false,
77 "input": [
78 "# New GUI window--should *NOT* have the visual settings of inline\n",
79 "%pylab qt\n",
80 "plot([1,2,3])"
81 ],
82 "language": "python",
83 "metadata": {},
84 "outputs": [
85 {
86 "output_type": "stream",
87 "stream": "stdout",
88 "text": [
89 "\n",
90 "Welcome to pylab, a matplotlib-based Python environment [backend: Qt4Agg].\n",
91 "For more information, type 'help(pylab)'.\n"
92 ]
93 },
94 {
95 "output_type": "pyout",
96 "prompt_number": 11,
97 "text": [
98 "[<matplotlib.lines.Line2D at 0x5253850>]"
99 ]
100 }
101 ],
102 "prompt_number": 11
103 }
104 ],
105 "metadata": {}
106 }
107 ]
108 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now