##// END OF EJS Templates
Finish up demo api/docs, manual improvements, other fixes. Manual work...
fperez -
Show More
@@ -1,7 +1,7 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Magic functions for InteractiveShell.
3 3
4 $Id: Magic.py 907 2005-09-24 00:59:56Z fperez $"""
4 $Id: Magic.py 908 2005-09-26 16:05:48Z fperez $"""
5 5
6 6 #*****************************************************************************
7 7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
@@ -69,20 +69,6 b' def on_off(tag):'
69 69 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
70 70 return ['OFF','ON'][tag]
71 71
72 def get_py_filename(name):
73 """Return a valid python filename in the current directory.
74
75 If the given name is not a file, it adds '.py' and searches again.
76 Raises IOError with an informative message if the file isn't found."""
77
78 name = os.path.expanduser(name)
79 if not os.path.isfile(name) and not name.endswith('.py'):
80 name += '.py'
81 if os.path.isfile(name):
82 return name
83 else:
84 raise IOError,'File `%s` not found.' % name
85
86 72
87 73 #****************************************************************************
88 74 # Utility classes
@@ -2459,16 +2445,8 b' Defaulting color scheme to \'NoColor\'"""'
2459 2445 This magic is similar to the cat utility, but it will assume the file
2460 2446 to be Python source and will show it with syntax highlighting. """
2461 2447
2462 try:
2463 filename = get_py_filename(parameter_s)
2464 except IndexError:
2465 warn('you must provide at least a filename.')
2466 return
2467 fobj=open(filename,'r')
2468 source = fobj.read()
2469 fobj.close()
2470 colorize = Parser().format
2471 colorized_src = colorize(source,'str',self.shell.rc['colors'])
2472 page(colorized_src,screen_lines=self.shell.rc.screen_length)
2448 filename = get_py_filename(parameter_s)
2449 page(self.shell.colorize(file_read(filename)),
2450 screen_lines=self.shell.rc.screen_length)
2473 2451
2474 2452 # end Magic
@@ -1,6 +1,103 b''
1 1 """Module for interactive demos using IPython.
2 2
3 Sorry, but this uses Python 2.3 features, so it won't work in 2.2 environments.
3 This module implements a single class, Demo, for running Python scripts
4 interactively in IPython for demonstrations. With very simple markup (a few
5 tags in comments), you can control points where the script stops executing and
6 returns control to IPython.
7
8 The file is run in its own empty namespace (though you can pass it a string of
9 arguments as if in a command line environment, and it will see those as
10 sys.argv). But at each stop, the global IPython namespace is updated with the
11 current internal demo namespace, so you can work interactively with the data
12 accumulated so far.
13
14 By default, each block of code is printed (with syntax highlighting) before
15 executing it and you have to confirm execution. This is intended to show the
16 code to an audience first so you can discuss it, and only proceed with
17 execution once you agree. There are a few tags which allow you to modify this
18 behavior.
19
20 The supported tags are:
21
22 # <demo> --- stop ---
23
24 Defines block boundaries, the points where IPython stops execution of the
25 file and returns to the interactive prompt.
26
27 # <demo> silent
28
29 Make a block execute silently (and hence automatically). Typically used in
30 cases where you have some boilerplate or initialization code which you need
31 executed but do not want to be seen in the demo.
32
33 # <demo> auto
34
35 Make a block execute automatically, but still being printed. Useful for
36 simple code which does not warrant discussion, since it avoids the extra
37 manual confirmation.
38
39 # <demo> auto_all
40
41 This tag can _only_ be in the first block, and if given it overrides the
42 individual auto tags to make the whole demo fully automatic (no block asks
43 for confirmation). It can also be given at creation time (or the attribute
44 set later) to override what's in the file.
45
46 While _any_ python file can be run as a Demo instance, if there are no stop
47 tags the whole file will run in a single block (no different that calling
48 first %pycat and then %run). The minimal markup to make this useful is to
49 place a set of stop tags; the other tags are only there to let you fine-tune
50 the execution.
51
52 This is probably best explained with the simple example file below. You can
53 copy this into a file named ex_demo.py, and try running it via:
54
55 from IPython.demo import Demo
56 d = Demo('ex_demo.py')
57 d() <--- Call the d object (omit the parens if you have autocall on).
58
59 Each time you call the demo object, it runs the next block. The demo object
60 has a few useful methods for navigation, like again(), jump(), seek() and
61 back(). It can be reset for a new run via reset() or reloaded from disk (in
62 case you've edited the source) via reload(). See their docstrings below.
63
64 #################### EXAMPLE DEMO <ex_demo.py> ###############################
65 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
66
67 print 'Hello, welcome to an interactive IPython demo.'
68
69 # The mark below defines a block boundary, which is a point where IPython will
70 # stop execution and return to the interactive prompt.
71 # Note that in actual interactive execution,
72 # <demo> --- stop ---
73
74 x = 1
75 y = 2
76
77 # <demo> --- stop ---
78
79 # the mark below makes this block as silent
80 # <demo> silent
81
82 print 'This is a silent block, which gets executed but not printed.'
83
84 # <demo> --- stop ---
85 # <demo> auto
86 print 'This is an automatic block.'
87 print 'It is executed without asking for confirmation, but printed.'
88 z = x+y
89
90 print 'z=',x
91
92 # <demo> --- stop ---
93 # This is just another normal block.
94 print 'z is now:', z
95
96 print 'bye!'
97 ################### END EXAMPLE DEMO <ex_demo.py> ############################
98
99 WARNING: this module uses Python 2.3 features, so it won't work in 2.2
100 environments.
4 101 """
5 102 #*****************************************************************************
6 103 # Copyright (C) 2005 Fernando Perez. <Fernando.Perez@colorado.edu>
@@ -15,15 +112,28 b' import exceptions'
15 112 import re
16 113
17 114 from IPython.PyColorize import Parser
18 from IPython.genutils import marquee, shlex_split
115 from IPython.genutils import marquee, shlex_split, file_read
116
117 __all__ = ['Demo','DemoError']
19 118
20 119 class DemoError(exceptions.Exception): pass
21 120
121 def re_mark(mark):
122 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
123
22 124 class Demo:
23 def __init__(self,fname,arg_str='',mark_pause='# pause',
24 mark_silent='# silent',mark_auto='# auto',auto=False):
125
126 re_stop = re_mark('---\s?stop\s?---')
127 re_silent = re_mark('silent')
128 re_auto = re_mark('auto')
129 re_auto_all = re_mark('auto_all')
130
131 def __init__(self,fname,arg_str='',auto_all=None):
25 132 """Make a new demo object. To run the demo, simply call the object.
26 133
134 See the module docstring for full details and an example (you can use
135 IPython.Demo? in IPython to see it).
136
27 137 Inputs:
28 138
29 139 - fname = filename.
@@ -34,41 +144,24 b' class Demo:'
34 144 just like sys.argv, so the demo script can see a similar
35 145 environment.
36 146
37 - mark_pause ('# pause'): marks for pausing (block boundaries). The
38 marks are turned into regexps which match them as standalone in a
39 line, with all leading/trailing whitespace ignored.
40
41 - mark_silent('# silent'): mark blocks as silent, which means that
42 they are executed without printing their content to screen. Silent
43 blocks are always automatically executed.
44
45 - mark_auto ('# auto'): mark individual blocks as automatically
46 executed (without asking for confirmation).
47
48 - auto(False): global flag to run all blocks automatically without
147 - auto_all(None): global flag to run all blocks automatically without
49 148 confirmation. This attribute overrides the block-level tags and
50 149 applies to the whole demo. It is an attribute of the object, and
51 150 can be changed at runtime simply by reassigning it to a boolean
52 151 value.
53 152 """
54 153
55 self.fname = fname
56 self.sys_argv = [fname] + shlex_split(arg_str)
57 self.mark_pause = mark_pause
58 self.mark_silent = mark_silent
59 self.re_pause = re.compile(r'^\s*%s\s*$' % mark_pause,re.MULTILINE)
60 self.re_silent = re.compile(r'^\s*%s\s*$' % mark_silent,re.MULTILINE)
61 self.re_auto = re.compile(r'^\s*%s\s*$' % mark_auto,re.MULTILINE)
62 self.auto = auto
63
154 self.fname = fname
155 self.sys_argv = [fname] + shlex_split(arg_str)
156 self.auto_all = auto_all
157
64 158 # get a few things from ipython. While it's a bit ugly design-wise,
65 159 # it ensures that things like color scheme and the like are always in
66 160 # sync with the ipython mode being used. This class is only meant to
67 161 # be used inside ipython anyways, so it's OK.
68 self.ip_showtb = __IPYTHON__.showtraceback
69 self.ip_ns = __IPYTHON__.user_ns
70 self.ip_colors = __IPYTHON__.rc['colors']
71 self.colorize = Parser().format
162 self.ip_showtb = __IPYTHON__.showtraceback
163 self.ip_ns = __IPYTHON__.user_ns
164 self.ip_colorize = __IPYTHON__.pycolorize
72 165
73 166 # load user data and initialize data structures
74 167 self.reload()
@@ -76,42 +169,44 b' class Demo:'
76 169 def reload(self):
77 170 """Reload source from disk and initialize state."""
78 171 # read data and parse into blocks
79 fobj = file(self.fname,'r')
80 self.src = fobj.read()
81 fobj.close()
82 src_blocks = [b.strip() for b in self.re_pause.split(self.src) if b]
83 self._silent = [bool(self.re_silent.findall(b)) for b in src_blocks]
84 self._auto = [bool(self.re_auto.findall(b)) for b in src_blocks]
85 # strip out the 'auto' markers
86 src_b = []
172 self.src = file_read(self.fname)
173 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
174 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
175 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
176
177 # if auto_all is not given (def. None), we read it from the file
178 if self.auto_all is None:
179 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
180 else:
181 self.auto_all = bool(self.auto_all)
182
183 # Clean the sources from all markup so it doesn't get displayed when
184 # running the demo
185 src_blocks = []
87 186 auto_strip = lambda s: self.re_auto.sub('',s)
88 for i,b in enumerate(src_blocks):
187 for i,b in enumerate(src_b):
89 188 if self._auto[i]:
90 src_b.append(auto_strip(b))
189 src_blocks.append(auto_strip(b))
91 190 else:
92 src_b.append(b)
93 self.nblocks = len(src_b)
94 self.src_blocks = src_b
95
96 # try to colorize blocks
97 col_scheme = self.ip_colors
98 self.src_blocks_colored = [self.colorize(s_blk,'str',col_scheme)
99 for s_blk in self.src_blocks]
191 src_blocks.append(b)
192 # remove the auto_all marker
193 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
194
195 self.nblocks = len(src_blocks)
196 self.src_blocks = src_blocks
197
198 # also build syntax-highlighted source
199 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
200
100 201 # ensure clean namespace and seek offset
101 202 self.reset()
102 203
103 204 def reset(self):
104 205 """Reset the namespace and seek pointer to restart the demo"""
105 self.user_ns = {}
106 self.finished = False
206 self.user_ns = {}
207 self.finished = False
107 208 self.block_index = 0
108 209
109 def again(self):
110 """Repeat the last block"""
111 self.block_index -= 1
112 self.finished = False
113 self()
114
115 210 def _validate_index(self,index):
116 211 if index<0 or index>=self.nblocks:
117 212 raise ValueError('invalid block index %s' % index)
@@ -122,6 +217,19 b' class Demo:'
122 217 self.block_index = index
123 218 self.finished = False
124 219
220 def back(self,num=1):
221 """Move the seek pointer back num blocks (default is 1)."""
222 self.seek(self.block_index-num)
223
224 def jump(self,num):
225 """Jump a given number of blocks relative to the current one."""
226 self.seek(self.block_index+num)
227
228 def again(self):
229 """Move the seek pointer back one block and re-execute."""
230 self.back(1)
231 self()
232
125 233 def show(self,index=None):
126 234 """Show a single block on screen"""
127 235 if index is None:
@@ -173,7 +281,7 b' class Demo:'
173 281 (index,self.nblocks-index-1))
174 282 else:
175 283 self.show(index)
176 if self.auto or self._auto[index]:
284 if self.auto_all or self._auto[index]:
177 285 print marquee('output')
178 286 else:
179 287 print marquee('Press <q> to quit, <Enter> to execute...'),
@@ -5,7 +5,7 b' General purpose utilities.'
5 5 This is a grab-bag of stuff I find useful in most programs I write. Some of
6 6 these things are also convenient when working at the command line.
7 7
8 $Id: genutils.py 897 2005-09-22 09:32:46Z fperez $"""
8 $Id: genutils.py 908 2005-09-26 16:05:48Z fperez $"""
9 9
10 10 #*****************************************************************************
11 11 # Copyright (C) 2001-2004 Fernando Perez. <fperez@colorado.edu>
@@ -439,6 +439,21 b' def mutex_opts(dict,ex_op):'
439 439 'Options '+op1+' and '+op2+' are mutually exclusive.'
440 440
441 441 #-----------------------------------------------------------------------------
442 def get_py_filename(name):
443 """Return a valid python filename in the current directory.
444
445 If the given name is not a file, it adds '.py' and searches again.
446 Raises IOError with an informative message if the file isn't found."""
447
448 name = os.path.expanduser(name)
449 if not os.path.isfile(name) and not name.endswith('.py'):
450 name += '.py'
451 if os.path.isfile(name):
452 return name
453 else:
454 raise IOError,'File `%s` not found.' % name
455
456 #-----------------------------------------------------------------------------
442 457 def filefind(fname,alt_dirs = None):
443 458 """Return the given filename either in the current directory, if it
444 459 exists, or in a specified list of directories.
@@ -467,6 +482,14 b' def filefind(fname,alt_dirs = None):'
467 482 ' not found in current or supplied directories:' + `alt_dirs`
468 483
469 484 #----------------------------------------------------------------------------
485 def file_read(filename):
486 """Read a file and close it. Returns the file source."""
487 fobj=open(filename,'r');
488 source = fobj.read();
489 fobj.close()
490 return source
491
492 #----------------------------------------------------------------------------
470 493 def target_outdated(target,deps):
471 494 """Determine whether a target is out of date.
472 495
@@ -937,7 +960,7 b' def ask_yes_no(prompt,default=None):'
937 960 return answers[ans]
938 961
939 962 #----------------------------------------------------------------------------
940 def marquee(txt='',width=80,mark='*'):
963 def marquee(txt='',width=78,mark='*'):
941 964 """Return the input string centered in a 'marquee'."""
942 965 if not txt:
943 966 return (mark*width)[:width]
@@ -6,7 +6,7 b' Requires Python 2.1 or newer.'
6 6
7 7 This file contains all the classes and helper functions specific to IPython.
8 8
9 $Id: iplib.py 894 2005-09-22 07:16:18Z fperez $
9 $Id: iplib.py 908 2005-09-26 16:05:48Z fperez $
10 10 """
11 11
12 12 #*****************************************************************************
@@ -61,6 +61,7 b' from IPython.Struct import Struct'
61 61 from IPython.Itpl import Itpl,itpl,printpl,ItplNS,itplns
62 62 from IPython.FakeModule import FakeModule
63 63 from IPython.background_jobs import BackgroundJobManager
64 from IPython.PyColorize import Parser
64 65 from IPython.genutils import *
65 66
66 67 # Global pointer to the running
@@ -661,6 +662,10 b' class InteractiveShell(code.InteractiveConsole, Logger, Magic):'
661 662 # magic code via this pointer instead of the current mixin salad.
662 663 Magic.set_shell(self,self)
663 664
665 # Python source parser/formatter for syntax highlighting
666 pyformat = Parser().format
667 self.pycolorize = lambda src: pyformat(src,'str',self.rc['colors'])
668
664 669 # hooks holds pointers used for user-side customizations
665 670 self.hooks = Struct()
666 671
@@ -1,3 +1,10 b''
1 2005-09-24 Fernando Perez <Fernando.Perez@colorado.edu>
2
3 * IPython/demo.py: finish demo module, fully documented now.
4
5 * IPython/genutils.py (file_read): simple little utility to read a
6 file and ensure it's closed afterwards.
7
1 8 2005-09-23 Fernando Perez <Fernando.Perez@colorado.edu>
2 9
3 10 * IPython/demo.py (Demo.__init__): added support for individually
@@ -2,15 +2,45 b''
2 2 \lyxformat 221
3 3 \textclass article
4 4 \begin_preamble
5 \usepackage{ae,aecompl}
6 \usepackage{hyperref}
5 %\usepackage{ae,aecompl}
6 \usepackage{color}
7
8 % A few colors to replace the defaults for certain link types
9 \definecolor{orange}{cmyk}{0,0.4,0.8,0.2}
10 \definecolor{darkorange}{rgb}{.71,0.21,0.01}
11 \definecolor{darkred}{rgb}{.52,0.08,0.01}
12 \definecolor{darkgreen}{rgb}{.12,.54,.11}
13
14 % Use and configure listings package for nicely formatted code
15 \usepackage{listings}
16 \lstset{
17 language=Python,
18 basicstyle=\small\ttfamily,
19 commentstyle=\ttfamily\color{blue},
20 stringstyle=\ttfamily\color{darkorange},
21 showstringspaces=false,
22 breaklines=true,
23 postbreak = \space\dots
24 }
25
26 \usepackage[%pdftex, % needed for pdflatex
27 breaklinks=true, % so long urls are correctly broken across lines
28 colorlinks=true,
29 urlcolor=blue,
30 linkcolor=darkred,
31 citecolor=darkgreen,
32 ]{hyperref}
33
7 34 \usepackage{html}
35
36 % This helps prevent overly long lines that stretch beyond the margins
37 \sloppy
8 38 \end_preamble
9 39 \language english
10 40 \inputencoding latin1
11 \fontscheme default
41 \fontscheme palatino
12 42 \graphics default
13 \paperfontsize default
43 \paperfontsize 10
14 44 \spacing single
15 45 \papersize Default
16 46 \paperpackage a4
@@ -19,9 +49,9 b''
19 49 \use_natbib 0
20 50 \use_numerical_citations 0
21 51 \paperorientation portrait
22 \leftmargin 1.25in
52 \leftmargin 1.1in
23 53 \topmargin 1in
24 \rightmargin 1.25in
54 \rightmargin 1.1in
25 55 \bottommargin 1in
26 56 \secnumdepth 3
27 57 \tocdepth 3
@@ -433,8 +463,8 b' IPython is generously hosted at'
433 463 \end_inset
434 464
435 465 by the SciPy project.
436 This site offers downloads, CVS access, mailing lists and a bug tracking
437 system.
466 This site offers downloads, subversion access, mailing lists and a bug
467 tracking system.
438 468 I am very grateful to Enthought (
439 469 \begin_inset LatexCommand \htmlurl{http://www.enthought.com}
440 470
@@ -2271,6 +2301,19 b' Use'
2271 2301 While IPython doesn't support true multiline editing, this command allows
2272 2302 you to call an editor on the spot, and IPython will execute the code you
2273 2303 type in there as if it were typed interactively.
2304 \layout Itemize
2305
2306 Use the IPython.demo.Demo class to load any Python script as an interactive
2307 demo.
2308 With a minimal amount of simple markup, you can control the execution of
2309 the script, stopping as needed.
2310 See sec.\SpecialChar ~
2311
2312 \begin_inset LatexCommand \ref{sec:interactive-demos}
2313
2314 \end_inset
2315
2316 for more.
2274 2317 \layout Standard
2275 2318
2276 2319 If you have your own favorite tip on using IPython efficiently for a certain
@@ -3577,9 +3620,13 b' example-magic.py'
3577 3620 \layout Standard
3578 3621
3579 3622
3580 \begin_inset Include \verbatiminput{examples/example-magic.py}
3581 preview false
3623 \begin_inset ERT
3624 status Open
3625
3626 \layout Standard
3582 3627
3628 \backslash
3629 lstinputlisting{examples/example-magic.py}
3583 3630 \end_inset
3584 3631
3585 3632
@@ -5323,9 +5370,13 b' directory contains lots of comments on all of these options.'
5323 5370 \layout Standard
5324 5371
5325 5372
5326 \begin_inset Include \verbatiminput{../IPython/UserConfig/ipythonrc}
5327 preview false
5373 \begin_inset ERT
5374 status Open
5328 5375
5376 \layout Standard
5377
5378 \backslash
5379 lstinputlisting{../IPython/UserConfig/ipythonrc}
5329 5380 \end_inset
5330 5381
5331 5382
@@ -6021,9 +6072,13 b' example-embed.py'
6021 6072 \layout Standard
6022 6073
6023 6074
6024 \begin_inset Include \verbatiminput{examples/example-embed.py}
6025 preview false
6075 \begin_inset ERT
6076 status Open
6026 6077
6078 \layout Standard
6079
6080 \backslash
6081 lstinputlisting{examples/example-embed.py}
6027 6082 \end_inset
6028 6083
6029 6084
@@ -6034,9 +6089,13 b' Once you understand how the system functions, you can use the following'
6034 6089 \layout Standard
6035 6090
6036 6091
6037 \begin_inset Include \verbatiminput{examples/example-embed-short.py}
6038 preview false
6092 \begin_inset ERT
6093 status Open
6039 6094
6095 \layout Standard
6096
6097 \backslash
6098 lstinputlisting{examples/example-embed-short.py}
6040 6099 \end_inset
6041 6100
6042 6101
@@ -7648,6 +7707,30 b' This is obviously a brute force way of avoiding race conditions with the'
7648 7707 \layout Section
7649 7708
7650 7709
7710 \begin_inset LatexCommand \label{sec:interactive-demos}
7711
7712 \end_inset
7713
7714 Interactive demos with IPython
7715 \layout Standard
7716
7717 IPython ships with
7718 \layout Standard
7719
7720
7721 \begin_inset ERT
7722 status Open
7723
7724 \layout Standard
7725
7726 \backslash
7727 lstinputlisting{examples/example-demo.py}
7728 \end_inset
7729
7730
7731 \layout Section
7732
7733
7651 7734 \begin_inset LatexCommand \label{sec:matplotlib-support}
7652 7735
7653 7736 \end_inset
@@ -7960,9 +8043,13 b' example-gnuplot.py'
7960 8043 \layout Standard
7961 8044
7962 8045
7963 \begin_inset Include \verbatiminput{examples/example-gnuplot.py}
7964 preview false
8046 \begin_inset ERT
8047 status Open
7965 8048
8049 \layout Standard
8050
8051 \backslash
8052 lstinputlisting{examples/example-gnuplot.py}
7966 8053 \end_inset
7967 8054
7968 8055
@@ -8311,7 +8398,39 b' IPython is mainly developed by Fernando P'
8311 8398 \family default
8312 8399 .
8313 8400 For all IPython-related requests, please contact Fernando.
8314 User or development help should be requested via the IPython mailing lists:
8401
8402 \layout Standard
8403
8404 As of late 2005, the following developers have joined the core team:
8405 \layout List
8406 \labelwidthstring 00.00.0000
8407
8408 Robert\SpecialChar ~
8409 Kern
8410 \family typewriter
8411 <rkern-AT-enthought.com>
8412 \family default
8413 : co-mentored the 2005 Google Summer of Code project to develop python interacti
8414 ve notebooks (XML documents) and graphical interface.
8415 This project was awarded to the students Tzanko Matev
8416 \family typewriter
8417 <tsanko-AT-gmail.com>
8418 \family default
8419 and Toni Alatalo
8420 \family typewriter
8421 <antont-AT-an.org>
8422 \layout List
8423 \labelwidthstring 00.00.0000
8424
8425 Brian\SpecialChar ~
8426 Granger
8427 \family typewriter
8428 <bgranger-AT-scu.edu>
8429 \family default
8430 : extending IPython to allow support for interactive parallel computing.
8431 \layout Standard
8432
8433 User or development help should be requested via the IPython mailing lists:
8315 8434 \layout Description
8316 8435
8317 8436 User\SpecialChar ~
@@ -8800,16 +8919,6 b' Tretkowski'
8800 8919 \layout List
8801 8920 \labelwidthstring 00.00.0000
8802 8921
8803 Robert\SpecialChar ~
8804 Kern
8805 \family typewriter
8806 <rkern-AT-ucsd.edu>
8807 \family default
8808 help with OSX issues, much help in general with various Python topics,
8809 especially related to scientific computing.
8810 \layout List
8811 \labelwidthstring 00.00.0000
8812
8813 8922 George\SpecialChar ~
8814 8923 Sakkis <
8815 8924 \family typewriter
General Comments 0
You need to be logged in to leave comments. Login now