Show More
@@ -0,0 +1,123 b'' | |||
|
1 | # encoding: utf-8 | |
|
2 | ||
|
3 | """The IPython Core Notification Center. | |
|
4 | ||
|
5 | See docs/source/development/notification_blueprint.txt for an overview of the | |
|
6 | notification module. | |
|
7 | """ | |
|
8 | ||
|
9 | __docformat__ = "restructuredtext en" | |
|
10 | ||
|
11 | #----------------------------------------------------------------------------- | |
|
12 | # Copyright (C) 2008 The IPython Development Team | |
|
13 | # | |
|
14 | # Distributed under the terms of the BSD License. The full license is in | |
|
15 | # the file COPYING, distributed as part of this software. | |
|
16 | #----------------------------------------------------------------------------- | |
|
17 | ||
|
18 | ||
|
19 | class NotificationCenter(object): | |
|
20 | """Synchronous notification center | |
|
21 | ||
|
22 | Example | |
|
23 | ------- | |
|
24 | >>> import IPython.kernel.core.notification as notification | |
|
25 | >>> def callback(theType, theSender, args={}): | |
|
26 | ... print theType,theSender,args | |
|
27 | ... | |
|
28 | >>> notification.sharedCenter.add_observer(callback, 'NOTIFICATION_TYPE', None) | |
|
29 | >>> notification.sharedCenter.post_notification('NOTIFICATION_TYPE', object()) # doctest:+ELLIPSIS | |
|
30 | NOTIFICATION_TYPE ... | |
|
31 | ||
|
32 | """ | |
|
33 | def __init__(self): | |
|
34 | super(NotificationCenter, self).__init__() | |
|
35 | self._init_observers() | |
|
36 | ||
|
37 | ||
|
38 | def _init_observers(self): | |
|
39 | """Initialize observer storage""" | |
|
40 | ||
|
41 | self.registered_types = set() #set of types that are observed | |
|
42 | self.registered_senders = set() #set of senders that are observed | |
|
43 | self.observers = {} #map (type,sender) => callback (callable) | |
|
44 | ||
|
45 | ||
|
46 | def post_notification(self, theType, sender, **kwargs): | |
|
47 | """Post notification (type,sender,**kwargs) to all registered | |
|
48 | observers. | |
|
49 | ||
|
50 | Implementation | |
|
51 | -------------- | |
|
52 | * If no registered observers, performance is O(1). | |
|
53 | * Notificaiton order is undefined. | |
|
54 | * Notifications are posted synchronously. | |
|
55 | """ | |
|
56 | ||
|
57 | if(theType==None or sender==None): | |
|
58 | raise Exception("NotificationCenter.post_notification requires \ | |
|
59 | type and sender.") | |
|
60 | ||
|
61 | # If there are no registered observers for the type/sender pair | |
|
62 | if((theType not in self.registered_types and | |
|
63 | None not in self.registered_types) or | |
|
64 | (sender not in self.registered_senders and | |
|
65 | None not in self.registered_senders)): | |
|
66 | return | |
|
67 | ||
|
68 | for o in self._observers_for_notification(theType, sender): | |
|
69 | o(theType, sender, args=kwargs) | |
|
70 | ||
|
71 | ||
|
72 | def _observers_for_notification(self, theType, sender): | |
|
73 | """Find all registered observers that should recieve notification""" | |
|
74 | ||
|
75 | keys = ( | |
|
76 | (theType,sender), | |
|
77 | (theType, None), | |
|
78 | (None, sender), | |
|
79 | (None,None) | |
|
80 | ) | |
|
81 | ||
|
82 | ||
|
83 | obs = set() | |
|
84 | for k in keys: | |
|
85 | obs.update(self.observers.get(k, set())) | |
|
86 | ||
|
87 | return obs | |
|
88 | ||
|
89 | ||
|
90 | def add_observer(self, callback, theType, sender): | |
|
91 | """Add an observer callback to this notification center. | |
|
92 | ||
|
93 | The given callback will be called upon posting of notifications of | |
|
94 | the given type/sender and will receive any additional kwargs passed | |
|
95 | to post_notification. | |
|
96 | ||
|
97 | Parameters | |
|
98 | ---------- | |
|
99 | observerCallback : callable | |
|
100 | Callable. Must take at least two arguments:: | |
|
101 | observerCallback(type, sender, args={}) | |
|
102 | ||
|
103 | theType : hashable | |
|
104 | The notification type. If None, all notifications from sender | |
|
105 | will be posted. | |
|
106 | ||
|
107 | sender : hashable | |
|
108 | The notification sender. If None, all notifications of theType | |
|
109 | will be posted. | |
|
110 | """ | |
|
111 | assert(callback != None) | |
|
112 | self.registered_types.add(theType) | |
|
113 | self.registered_senders.add(sender) | |
|
114 | self.observers.setdefault((theType,sender), set()).add(callback) | |
|
115 | ||
|
116 | def remove_all_observers(self): | |
|
117 | """Removes all observers from this notification center""" | |
|
118 | ||
|
119 | self._init_observers() | |
|
120 | ||
|
121 | ||
|
122 | ||
|
123 | sharedCenter = NotificationCenter() No newline at end of file |
@@ -0,0 +1,171 b'' | |||
|
1 | # encoding: utf-8 | |
|
2 | ||
|
3 | """This file contains unittests for the notification.py module.""" | |
|
4 | ||
|
5 | __docformat__ = "restructuredtext en" | |
|
6 | ||
|
7 | #----------------------------------------------------------------------------- | |
|
8 | # Copyright (C) 2008 The IPython Development Team | |
|
9 | # | |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
|
11 | # the file COPYING, distributed as part of this software. | |
|
12 | #----------------------------------------------------------------------------- | |
|
13 | ||
|
14 | #----------------------------------------------------------------------------- | |
|
15 | # Imports | |
|
16 | #----------------------------------------------------------------------------- | |
|
17 | ||
|
18 | import unittest | |
|
19 | import IPython.kernel.core.notification as notification | |
|
20 | from nose.tools import timed | |
|
21 | ||
|
22 | # | |
|
23 | # Supporting test classes | |
|
24 | # | |
|
25 | ||
|
26 | class Observer(object): | |
|
27 | """docstring for Observer""" | |
|
28 | def __init__(self, expectedType, expectedSender, | |
|
29 | center=notification.sharedCenter, **kwargs): | |
|
30 | super(Observer, self).__init__() | |
|
31 | self.expectedType = expectedType | |
|
32 | self.expectedSender = expectedSender | |
|
33 | self.expectedKwArgs = kwargs | |
|
34 | self.recieved = False | |
|
35 | center.add_observer(self.callback, | |
|
36 | self.expectedType, | |
|
37 | self.expectedSender) | |
|
38 | ||
|
39 | ||
|
40 | def callback(self, theType, sender, args={}): | |
|
41 | """callback""" | |
|
42 | ||
|
43 | assert(theType == self.expectedType or | |
|
44 | self.expectedType == None) | |
|
45 | assert(sender == self.expectedSender or | |
|
46 | self.expectedSender == None) | |
|
47 | assert(args == self.expectedKwArgs) | |
|
48 | self.recieved = True | |
|
49 | ||
|
50 | ||
|
51 | def verify(self): | |
|
52 | """verify""" | |
|
53 | ||
|
54 | assert(self.recieved) | |
|
55 | ||
|
56 | def reset(self): | |
|
57 | """reset""" | |
|
58 | ||
|
59 | self.recieved = False | |
|
60 | ||
|
61 | ||
|
62 | ||
|
63 | class Notifier(object): | |
|
64 | """docstring for Notifier""" | |
|
65 | def __init__(self, theType, **kwargs): | |
|
66 | super(Notifier, self).__init__() | |
|
67 | self.theType = theType | |
|
68 | self.kwargs = kwargs | |
|
69 | ||
|
70 | def post(self, center=notification.sharedCenter): | |
|
71 | """fire""" | |
|
72 | ||
|
73 | center.post_notification(self.theType, self, | |
|
74 | **self.kwargs) | |
|
75 | ||
|
76 | ||
|
77 | # | |
|
78 | # Test Cases | |
|
79 | # | |
|
80 | ||
|
81 | class NotificationTests(unittest.TestCase): | |
|
82 | """docstring for NotificationTests""" | |
|
83 | ||
|
84 | def tearDown(self): | |
|
85 | notification.sharedCenter.remove_all_observers() | |
|
86 | ||
|
87 | def test_notification_delivered(self): | |
|
88 | """Test that notifications are delivered""" | |
|
89 | expectedType = 'EXPECTED_TYPE' | |
|
90 | sender = Notifier(expectedType) | |
|
91 | observer = Observer(expectedType, sender) | |
|
92 | ||
|
93 | sender.post() | |
|
94 | ||
|
95 | observer.verify() | |
|
96 | ||
|
97 | ||
|
98 | def test_type_specificity(self): | |
|
99 | """Test that observers are registered by type""" | |
|
100 | ||
|
101 | expectedType = 1 | |
|
102 | unexpectedType = "UNEXPECTED_TYPE" | |
|
103 | sender = Notifier(expectedType) | |
|
104 | unexpectedSender = Notifier(unexpectedType) | |
|
105 | observer = Observer(expectedType, sender) | |
|
106 | ||
|
107 | sender.post() | |
|
108 | unexpectedSender.post() | |
|
109 | ||
|
110 | observer.verify() | |
|
111 | ||
|
112 | ||
|
113 | def test_sender_specificity(self): | |
|
114 | """Test that observers are registered by sender""" | |
|
115 | ||
|
116 | expectedType = "EXPECTED_TYPE" | |
|
117 | sender1 = Notifier(expectedType) | |
|
118 | sender2 = Notifier(expectedType) | |
|
119 | observer = Observer(expectedType, sender1) | |
|
120 | ||
|
121 | sender1.post() | |
|
122 | sender2.post() | |
|
123 | ||
|
124 | observer.verify() | |
|
125 | ||
|
126 | ||
|
127 | def test_remove_all_observers(self): | |
|
128 | """White-box test for remove_all_observers""" | |
|
129 | ||
|
130 | for i in xrange(10): | |
|
131 | Observer('TYPE', None, center=notification.sharedCenter) | |
|
132 | ||
|
133 | self.assert_(len(notification.sharedCenter.observers[('TYPE',None)]) >= 10, | |
|
134 | "observers registered") | |
|
135 | ||
|
136 | notification.sharedCenter.remove_all_observers() | |
|
137 | ||
|
138 | self.assert_(len(notification.sharedCenter.observers) == 0, "observers removed") | |
|
139 | ||
|
140 | ||
|
141 | def test_any_sender(self): | |
|
142 | """test_any_sender""" | |
|
143 | ||
|
144 | expectedType = "EXPECTED_TYPE" | |
|
145 | sender1 = Notifier(expectedType) | |
|
146 | sender2 = Notifier(expectedType) | |
|
147 | observer = Observer(expectedType, None) | |
|
148 | ||
|
149 | ||
|
150 | sender1.post() | |
|
151 | observer.verify() | |
|
152 | ||
|
153 | observer.reset() | |
|
154 | sender2.post() | |
|
155 | observer.verify() | |
|
156 | ||
|
157 | ||
|
158 | @timed(.01) | |
|
159 | def test_post_performance(self): | |
|
160 | """Test that post_notification, even with many registered irrelevant | |
|
161 | observers is fast""" | |
|
162 | ||
|
163 | for i in xrange(10): | |
|
164 | Observer("UNRELATED_TYPE", None) | |
|
165 | ||
|
166 | o = Observer('EXPECTED_TYPE', None) | |
|
167 | ||
|
168 | notification.sharedCenter.post_notification('EXPECTED_TYPE', self) | |
|
169 | ||
|
170 | o.verify() | |
|
171 |
@@ -0,0 +1,233 b'' | |||
|
1 | # encoding: utf-8 | |
|
2 | ||
|
3 | """A parallelized version of Python's builtin map.""" | |
|
4 | ||
|
5 | __docformat__ = "restructuredtext en" | |
|
6 | ||
|
7 | #---------------------------------------------------------------------------- | |
|
8 | # Copyright (C) 2008 The IPython Development Team | |
|
9 | # | |
|
10 | # Distributed under the terms of the BSD License. The full license is in | |
|
11 | # the file COPYING, distributed as part of this software. | |
|
12 | #---------------------------------------------------------------------------- | |
|
13 | ||
|
14 | #---------------------------------------------------------------------------- | |
|
15 | # Imports | |
|
16 | #---------------------------------------------------------------------------- | |
|
17 | ||
|
18 | from types import FunctionType | |
|
19 | from zope.interface import Interface, implements | |
|
20 | from IPython.kernel.task import MapTask | |
|
21 | from IPython.kernel.twistedutil import DeferredList, gatherBoth | |
|
22 | from IPython.kernel.util import printer | |
|
23 | from IPython.kernel.error import collect_exceptions | |
|
24 | ||
|
25 | #---------------------------------------------------------------------------- | |
|
26 | # Code | |
|
27 | #---------------------------------------------------------------------------- | |
|
28 | ||
|
29 | class IMapper(Interface): | |
|
30 | """The basic interface for a Mapper. | |
|
31 | ||
|
32 | This defines a generic interface for mapping. The idea of this is | |
|
33 | similar to that of Python's builtin `map` function, which applies a function | |
|
34 | elementwise to a sequence. | |
|
35 | """ | |
|
36 | ||
|
37 | def map(func, *seqs): | |
|
38 | """Do map in parallel. | |
|
39 | ||
|
40 | Equivalent to map(func, *seqs) or: | |
|
41 | ||
|
42 | [func(seqs[0][0], seqs[1][0],...), func(seqs[0][1], seqs[1][1],...),...] | |
|
43 | ||
|
44 | :Parameters: | |
|
45 | func : FunctionType | |
|
46 | The function to apply to the sequence | |
|
47 | sequences : tuple of iterables | |
|
48 | A sequence of iterables that are used for sucessive function | |
|
49 | arguments. This work just like map | |
|
50 | """ | |
|
51 | ||
|
52 | class IMultiEngineMapperFactory(Interface): | |
|
53 | """ | |
|
54 | An interface for something that creates `IMapper` instances. | |
|
55 | """ | |
|
56 | ||
|
57 | def mapper(dist='b', targets='all', block=True): | |
|
58 | """ | |
|
59 | Create an `IMapper` implementer with a given set of arguments. | |
|
60 | ||
|
61 | The `IMapper` created using a multiengine controller is | |
|
62 | not load balanced. | |
|
63 | """ | |
|
64 | ||
|
65 | class ITaskMapperFactory(Interface): | |
|
66 | """ | |
|
67 | An interface for something that creates `IMapper` instances. | |
|
68 | """ | |
|
69 | ||
|
70 | def mapper(clear_before=False, clear_after=False, retries=0, | |
|
71 | recovery_task=None, depend=None, block=True): | |
|
72 | """ | |
|
73 | Create an `IMapper` implementer with a given set of arguments. | |
|
74 | ||
|
75 | The `IMapper` created using a task controller is load balanced. | |
|
76 | ||
|
77 | See the documentation for `IPython.kernel.task.BaseTask` for | |
|
78 | documentation on the arguments to this method. | |
|
79 | """ | |
|
80 | ||
|
81 | ||
|
82 | class MultiEngineMapper(object): | |
|
83 | """ | |
|
84 | A Mapper for `IMultiEngine` implementers. | |
|
85 | """ | |
|
86 | ||
|
87 | implements(IMapper) | |
|
88 | ||
|
89 | def __init__(self, multiengine, dist='b', targets='all', block=True): | |
|
90 | """ | |
|
91 | Create a Mapper for a multiengine. | |
|
92 | ||
|
93 | The value of all arguments are used for all calls to `map`. This | |
|
94 | class allows these arguemnts to be set for a series of map calls. | |
|
95 | ||
|
96 | :Parameters: | |
|
97 | multiengine : `IMultiEngine` implementer | |
|
98 | The multiengine to use for running the map commands | |
|
99 | dist : str | |
|
100 | The type of decomposition to use. Only block ('b') is | |
|
101 | supported currently | |
|
102 | targets : (str, int, tuple of ints) | |
|
103 | The engines to use in the map | |
|
104 | block : boolean | |
|
105 | Whether to block when the map is applied | |
|
106 | """ | |
|
107 | self.multiengine = multiengine | |
|
108 | self.dist = dist | |
|
109 | self.targets = targets | |
|
110 | self.block = block | |
|
111 | ||
|
112 | def map(self, func, *sequences): | |
|
113 | """ | |
|
114 | Apply func to *sequences elementwise. Like Python's builtin map. | |
|
115 | ||
|
116 | This version is not load balanced. | |
|
117 | """ | |
|
118 | max_len = max(len(s) for s in sequences) | |
|
119 | for s in sequences: | |
|
120 | if len(s)!=max_len: | |
|
121 | raise ValueError('all sequences must have equal length') | |
|
122 | assert isinstance(func, (str, FunctionType)), "func must be a fuction or str" | |
|
123 | return self.multiengine.raw_map(func, sequences, dist=self.dist, | |
|
124 | targets=self.targets, block=self.block) | |
|
125 | ||
|
126 | class TaskMapper(object): | |
|
127 | """ | |
|
128 | Make an `ITaskController` look like an `IMapper`. | |
|
129 | ||
|
130 | This class provides a load balanced version of `map`. | |
|
131 | """ | |
|
132 | ||
|
133 | def __init__(self, task_controller, clear_before=False, clear_after=False, retries=0, | |
|
134 | recovery_task=None, depend=None, block=True): | |
|
135 | """ | |
|
136 | Create a `IMapper` given a `TaskController` and arguments. | |
|
137 | ||
|
138 | The additional arguments are those that are common to all types of | |
|
139 | tasks and are described in the documentation for | |
|
140 | `IPython.kernel.task.BaseTask`. | |
|
141 | ||
|
142 | :Parameters: | |
|
143 | task_controller : an `IBlockingTaskClient` implementer | |
|
144 | The `TaskController` to use for calls to `map` | |
|
145 | """ | |
|
146 | self.task_controller = task_controller | |
|
147 | self.clear_before = clear_before | |
|
148 | self.clear_after = clear_after | |
|
149 | self.retries = retries | |
|
150 | self.recovery_task = recovery_task | |
|
151 | self.depend = depend | |
|
152 | self.block = block | |
|
153 | ||
|
154 | def map(self, func, *sequences): | |
|
155 | """ | |
|
156 | Apply func to *sequences elementwise. Like Python's builtin map. | |
|
157 | ||
|
158 | This version is load balanced. | |
|
159 | """ | |
|
160 | max_len = max(len(s) for s in sequences) | |
|
161 | for s in sequences: | |
|
162 | if len(s)!=max_len: | |
|
163 | raise ValueError('all sequences must have equal length') | |
|
164 | task_args = zip(*sequences) | |
|
165 | task_ids = [] | |
|
166 | dlist = [] | |
|
167 | for ta in task_args: | |
|
168 | task = MapTask(func, ta, clear_before=self.clear_before, | |
|
169 | clear_after=self.clear_after, retries=self.retries, | |
|
170 | recovery_task=self.recovery_task, depend=self.depend) | |
|
171 | dlist.append(self.task_controller.run(task)) | |
|
172 | dlist = gatherBoth(dlist, consumeErrors=1) | |
|
173 | dlist.addCallback(collect_exceptions,'map') | |
|
174 | if self.block: | |
|
175 | def get_results(task_ids): | |
|
176 | d = self.task_controller.barrier(task_ids) | |
|
177 | d.addCallback(lambda _: gatherBoth([self.task_controller.get_task_result(tid) for tid in task_ids], consumeErrors=1)) | |
|
178 | d.addCallback(collect_exceptions, 'map') | |
|
179 | return d | |
|
180 | dlist.addCallback(get_results) | |
|
181 | return dlist | |
|
182 | ||
|
183 | class SynchronousTaskMapper(object): | |
|
184 | """ | |
|
185 | Make an `IBlockingTaskClient` look like an `IMapper`. | |
|
186 | ||
|
187 | This class provides a load balanced version of `map`. | |
|
188 | """ | |
|
189 | ||
|
190 | def __init__(self, task_controller, clear_before=False, clear_after=False, retries=0, | |
|
191 | recovery_task=None, depend=None, block=True): | |
|
192 | """ | |
|
193 | Create a `IMapper` given a `IBlockingTaskClient` and arguments. | |
|
194 | ||
|
195 | The additional arguments are those that are common to all types of | |
|
196 | tasks and are described in the documentation for | |
|
197 | `IPython.kernel.task.BaseTask`. | |
|
198 | ||
|
199 | :Parameters: | |
|
200 | task_controller : an `IBlockingTaskClient` implementer | |
|
201 | The `TaskController` to use for calls to `map` | |
|
202 | """ | |
|
203 | self.task_controller = task_controller | |
|
204 | self.clear_before = clear_before | |
|
205 | self.clear_after = clear_after | |
|
206 | self.retries = retries | |
|
207 | self.recovery_task = recovery_task | |
|
208 | self.depend = depend | |
|
209 | self.block = block | |
|
210 | ||
|
211 | def map(self, func, *sequences): | |
|
212 | """ | |
|
213 | Apply func to *sequences elementwise. Like Python's builtin map. | |
|
214 | ||
|
215 | This version is load balanced. | |
|
216 | """ | |
|
217 | max_len = max(len(s) for s in sequences) | |
|
218 | for s in sequences: | |
|
219 | if len(s)!=max_len: | |
|
220 | raise ValueError('all sequences must have equal length') | |
|
221 | task_args = zip(*sequences) | |
|
222 | task_ids = [] | |
|
223 | for ta in task_args: | |
|
224 | task = MapTask(func, ta, clear_before=self.clear_before, | |
|
225 | clear_after=self.clear_after, retries=self.retries, | |
|
226 | recovery_task=self.recovery_task, depend=self.depend) | |
|
227 | task_ids.append(self.task_controller.run(task)) | |
|
228 | if self.block: | |
|
229 | self.task_controller.barrier(task_ids) | |
|
230 | task_results = [self.task_controller.get_task_result(tid) for tid in task_ids] | |
|
231 | return task_results | |
|
232 | else: | |
|
233 | return task_ids No newline at end of file |
@@ -0,0 +1,41 b'' | |||
|
1 | from __future__ import with_statement | |
|
2 | ||
|
3 | #def test_simple(): | |
|
4 | if 0: | |
|
5 | ||
|
6 | # XXX - for now, we need a running cluster to be started separately. The | |
|
7 | # daemon work is almost finished, and will make much of this unnecessary. | |
|
8 | from IPython.kernel import client | |
|
9 | mec = client.MultiEngineClient(('127.0.0.1',10105)) | |
|
10 | ||
|
11 | try: | |
|
12 | mec.get_ids() | |
|
13 | except ConnectionRefusedError: | |
|
14 | import os, time | |
|
15 | os.system('ipcluster -n 2 &') | |
|
16 | time.sleep(2) | |
|
17 | mec = client.MultiEngineClient(('127.0.0.1',10105)) | |
|
18 | ||
|
19 | mec.block = False | |
|
20 | ||
|
21 | import itertools | |
|
22 | c = itertools.count() | |
|
23 | ||
|
24 | parallel = RemoteMultiEngine(mec) | |
|
25 | ||
|
26 | mec.pushAll() | |
|
27 | ||
|
28 | with parallel as pr: | |
|
29 | # A comment | |
|
30 | remote() # this means the code below only runs remotely | |
|
31 | print 'Hello remote world' | |
|
32 | x = range(10) | |
|
33 | # Comments are OK | |
|
34 | # Even misindented. | |
|
35 | y = x+1 | |
|
36 | ||
|
37 | ||
|
38 | with pfor('i',sequence) as pr: | |
|
39 | print x[i] | |
|
40 | ||
|
41 | print pr.x + pr.y |
@@ -0,0 +1,146 b'' | |||
|
1 | ## The basic trick is to generate the source code for the decorated function | |
|
2 | ## with the right signature and to evaluate it. | |
|
3 | ## Uncomment the statement 'print >> sys.stderr, func_src' in _decorate | |
|
4 | ## to understand what is going on. | |
|
5 | ||
|
6 | __all__ = ["decorator", "update_wrapper", "getinfo"] | |
|
7 | ||
|
8 | import inspect, sys | |
|
9 | ||
|
10 | def getinfo(func): | |
|
11 | """ | |
|
12 | Returns an info dictionary containing: | |
|
13 | - name (the name of the function : str) | |
|
14 | - argnames (the names of the arguments : list) | |
|
15 | - defaults (the values of the default arguments : tuple) | |
|
16 | - signature (the signature : str) | |
|
17 | - doc (the docstring : str) | |
|
18 | - module (the module name : str) | |
|
19 | - dict (the function __dict__ : str) | |
|
20 | ||
|
21 | >>> def f(self, x=1, y=2, *args, **kw): pass | |
|
22 | ||
|
23 | >>> info = getinfo(f) | |
|
24 | ||
|
25 | >>> info["name"] | |
|
26 | 'f' | |
|
27 | >>> info["argnames"] | |
|
28 | ['self', 'x', 'y', 'args', 'kw'] | |
|
29 | ||
|
30 | >>> info["defaults"] | |
|
31 | (1, 2) | |
|
32 | ||
|
33 | >>> info["signature"] | |
|
34 | 'self, x, y, *args, **kw' | |
|
35 | """ | |
|
36 | assert inspect.ismethod(func) or inspect.isfunction(func) | |
|
37 | regargs, varargs, varkwargs, defaults = inspect.getargspec(func) | |
|
38 | argnames = list(regargs) | |
|
39 | if varargs: | |
|
40 | argnames.append(varargs) | |
|
41 | if varkwargs: | |
|
42 | argnames.append(varkwargs) | |
|
43 | signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults, | |
|
44 | formatvalue=lambda value: "")[1:-1] | |
|
45 | return dict(name=func.__name__, argnames=argnames, signature=signature, | |
|
46 | defaults = func.func_defaults, doc=func.__doc__, | |
|
47 | module=func.__module__, dict=func.__dict__, | |
|
48 | globals=func.func_globals, closure=func.func_closure) | |
|
49 | ||
|
50 | def update_wrapper(wrapper, wrapped, create=False): | |
|
51 | """ | |
|
52 | An improvement over functools.update_wrapper. By default it works the | |
|
53 | same, but if the 'create' flag is set, generates a copy of the wrapper | |
|
54 | with the right signature and update the copy, not the original. | |
|
55 | Moreovoer, 'wrapped' can be a dictionary with keys 'name', 'doc', 'module', | |
|
56 | 'dict', 'defaults'. | |
|
57 | """ | |
|
58 | if isinstance(wrapped, dict): | |
|
59 | infodict = wrapped | |
|
60 | else: # assume wrapped is a function | |
|
61 | infodict = getinfo(wrapped) | |
|
62 | assert not '_wrapper_' in infodict["argnames"], \ | |
|
63 | '"_wrapper_" is a reserved argument name!' | |
|
64 | if create: # create a brand new wrapper with the right signature | |
|
65 | src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict | |
|
66 | # import sys; print >> sys.stderr, src # for debugging purposes | |
|
67 | wrapper = eval(src, dict(_wrapper_=wrapper)) | |
|
68 | try: | |
|
69 | wrapper.__name__ = infodict['name'] | |
|
70 | except: # Python version < 2.4 | |
|
71 | pass | |
|
72 | wrapper.__doc__ = infodict['doc'] | |
|
73 | wrapper.__module__ = infodict['module'] | |
|
74 | wrapper.__dict__.update(infodict['dict']) | |
|
75 | wrapper.func_defaults = infodict['defaults'] | |
|
76 | return wrapper | |
|
77 | ||
|
78 | # the real meat is here | |
|
79 | def _decorator(caller, func): | |
|
80 | infodict = getinfo(func) | |
|
81 | argnames = infodict['argnames'] | |
|
82 | assert not ('_call_' in argnames or '_func_' in argnames), \ | |
|
83 | 'You cannot use _call_ or _func_ as argument names!' | |
|
84 | src = "lambda %(signature)s: _call_(_func_, %(signature)s)" % infodict | |
|
85 | dec_func = eval(src, dict(_func_=func, _call_=caller)) | |
|
86 | return update_wrapper(dec_func, func) | |
|
87 | ||
|
88 | def decorator(caller, func=None): | |
|
89 | """ | |
|
90 | General purpose decorator factory: takes a caller function as | |
|
91 | input and returns a decorator with the same attributes. | |
|
92 | A caller function is any function like this:: | |
|
93 | ||
|
94 | def caller(func, *args, **kw): | |
|
95 | # do something | |
|
96 | return func(*args, **kw) | |
|
97 | ||
|
98 | Here is an example of usage: | |
|
99 | ||
|
100 | >>> @decorator | |
|
101 | ... def chatty(f, *args, **kw): | |
|
102 | ... print "Calling %r" % f.__name__ | |
|
103 | ... return f(*args, **kw) | |
|
104 | ||
|
105 | >>> chatty.__name__ | |
|
106 | 'chatty' | |
|
107 | ||
|
108 | >>> @chatty | |
|
109 | ... def f(): pass | |
|
110 | ... | |
|
111 | >>> f() | |
|
112 | Calling 'f' | |
|
113 | ||
|
114 | For sake of convenience, the decorator factory can also be called with | |
|
115 | two arguments. In this casem ``decorator(caller, func)`` is just a | |
|
116 | shortcut for ``decorator(caller)(func)``. | |
|
117 | """ | |
|
118 | if func is None: # return a decorator function | |
|
119 | return update_wrapper(lambda f : _decorator(caller, f), caller) | |
|
120 | else: # return a decorated function | |
|
121 | return _decorator(caller, func) | |
|
122 | ||
|
123 | if __name__ == "__main__": | |
|
124 | import doctest; doctest.testmod() | |
|
125 | ||
|
126 | ####################### LEGALESE ################################## | |
|
127 | ||
|
128 | ## Redistributions of source code must retain the above copyright | |
|
129 | ## notice, this list of conditions and the following disclaimer. | |
|
130 | ## Redistributions in bytecode form must reproduce the above copyright | |
|
131 | ## notice, this list of conditions and the following disclaimer in | |
|
132 | ## the documentation and/or other materials provided with the | |
|
133 | ## distribution. | |
|
134 | ||
|
135 | ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
|
136 | ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
|
137 | ## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
|
138 | ## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
|
139 | ## HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
|
140 | ## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
|
141 | ## BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |
|
142 | ## OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
|
143 | ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |
|
144 | ## TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | |
|
145 | ## USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
|
146 | ## DAMAGE. |
@@ -0,0 +1,133 b'' | |||
|
1 | """Decorators for labeling test objects. | |
|
2 | ||
|
3 | Decorators that merely return a modified version of the original | |
|
4 | function object are straightforward. Decorators that return a new | |
|
5 | function object need to use | |
|
6 | nose.tools.make_decorator(original_function)(decorator) in returning | |
|
7 | the decorator, in order to preserve metadata such as function name, | |
|
8 | setup and teardown functions and so on - see nose.tools for more | |
|
9 | information. | |
|
10 | ||
|
11 | NOTE: This file contains IPython-specific decorators and imports the | |
|
12 | numpy.testing.decorators file, which we've copied verbatim. Any of our own | |
|
13 | code will be added at the bottom if we end up extending this. | |
|
14 | """ | |
|
15 | ||
|
16 | # Stdlib imports | |
|
17 | import inspect | |
|
18 | ||
|
19 | # Third-party imports | |
|
20 | ||
|
21 | # This is Michele Simionato's decorator module, also kept verbatim. | |
|
22 | from decorator_msim import decorator, update_wrapper | |
|
23 | ||
|
24 | # Grab the numpy-specific decorators which we keep in a file that we | |
|
25 | # occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy | |
|
26 | # of numpy.testing.decorators. | |
|
27 | from decorators_numpy import * | |
|
28 | ||
|
29 | ############################################################################## | |
|
30 | # Local code begins | |
|
31 | ||
|
32 | # Utility functions | |
|
33 | ||
|
34 | def apply_wrapper(wrapper,func): | |
|
35 | """Apply a wrapper to a function for decoration. | |
|
36 | ||
|
37 | This mixes Michele Simionato's decorator tool with nose's make_decorator, | |
|
38 | to apply a wrapper in a decorator so that all nose attributes, as well as | |
|
39 | function signature and other properties, survive the decoration cleanly. | |
|
40 | This will ensure that wrapped functions can still be well introspected via | |
|
41 | IPython, for example. | |
|
42 | """ | |
|
43 | import nose.tools | |
|
44 | ||
|
45 | return decorator(wrapper,nose.tools.make_decorator(func)(wrapper)) | |
|
46 | ||
|
47 | ||
|
48 | def make_label_dec(label,ds=None): | |
|
49 | """Factory function to create a decorator that applies one or more labels. | |
|
50 | ||
|
51 | :Parameters: | |
|
52 | label : string or sequence | |
|
53 | One or more labels that will be applied by the decorator to the functions | |
|
54 | it decorates. Labels are attributes of the decorated function with their | |
|
55 | value set to True. | |
|
56 | ||
|
57 | :Keywords: | |
|
58 | ds : string | |
|
59 | An optional docstring for the resulting decorator. If not given, a | |
|
60 | default docstring is auto-generated. | |
|
61 | ||
|
62 | :Returns: | |
|
63 | A decorator. | |
|
64 | ||
|
65 | :Examples: | |
|
66 | ||
|
67 | A simple labeling decorator: | |
|
68 | >>> slow = make_label_dec('slow') | |
|
69 | >>> print slow.__doc__ | |
|
70 | Labels a test as 'slow'. | |
|
71 | ||
|
72 | And one that uses multiple labels and a custom docstring: | |
|
73 | >>> rare = make_label_dec(['slow','hard'], | |
|
74 | ... "Mix labels 'slow' and 'hard' for rare tests.") | |
|
75 | >>> print rare.__doc__ | |
|
76 | Mix labels 'slow' and 'hard' for rare tests. | |
|
77 | ||
|
78 | Now, let's test using this one: | |
|
79 | >>> @rare | |
|
80 | ... def f(): pass | |
|
81 | ... | |
|
82 | >>> | |
|
83 | >>> f.slow | |
|
84 | True | |
|
85 | >>> f.hard | |
|
86 | True | |
|
87 | """ | |
|
88 | ||
|
89 | if isinstance(label,basestring): | |
|
90 | labels = [label] | |
|
91 | else: | |
|
92 | labels = label | |
|
93 | ||
|
94 | # Validate that the given label(s) are OK for use in setattr() by doing a | |
|
95 | # dry run on a dummy function. | |
|
96 | tmp = lambda : None | |
|
97 | for label in labels: | |
|
98 | setattr(tmp,label,True) | |
|
99 | ||
|
100 | # This is the actual decorator we'll return | |
|
101 | def decor(f): | |
|
102 | for label in labels: | |
|
103 | setattr(f,label,True) | |
|
104 | return f | |
|
105 | ||
|
106 | # Apply the user's docstring, or autogenerate a basic one | |
|
107 | if ds is None: | |
|
108 | ds = "Labels a test as %r." % label | |
|
109 | decor.__doc__ = ds | |
|
110 | ||
|
111 | return decor | |
|
112 | ||
|
113 | #----------------------------------------------------------------------------- | |
|
114 | # Decorators for public use | |
|
115 | ||
|
116 | skip_doctest = make_label_dec('skip_doctest', | |
|
117 | """Decorator - mark a function or method for skipping its doctest. | |
|
118 | ||
|
119 | This decorator allows you to mark a function whose docstring you wish to | |
|
120 | omit from testing, while preserving the docstring for introspection, help, | |
|
121 | etc.""") | |
|
122 | ||
|
123 | ||
|
124 | def skip(func): | |
|
125 | """Decorator - mark a test function for skipping from test suite.""" | |
|
126 | ||
|
127 | import nose | |
|
128 | ||
|
129 | def wrapper(*a,**k): | |
|
130 | raise nose.SkipTest("Skipping test for function: %s" % | |
|
131 | func.__name__) | |
|
132 | ||
|
133 | return apply_wrapper(wrapper,func) |
@@ -0,0 +1,94 b'' | |||
|
1 | """Decorators for labeling test objects | |
|
2 | ||
|
3 | Decorators that merely return a modified version of the original | |
|
4 | function object are straightforward. Decorators that return a new | |
|
5 | function object need to use | |
|
6 | nose.tools.make_decorator(original_function)(decorator) in returning | |
|
7 | the decorator, in order to preserve metadata such as function name, | |
|
8 | setup and teardown functions and so on - see nose.tools for more | |
|
9 | information. | |
|
10 | ||
|
11 | """ | |
|
12 | ||
|
13 | def slow(t): | |
|
14 | """Labels a test as 'slow'. | |
|
15 | ||
|
16 | The exact definition of a slow test is obviously both subjective and | |
|
17 | hardware-dependent, but in general any individual test that requires more | |
|
18 | than a second or two should be labeled as slow (the whole suite consits of | |
|
19 | thousands of tests, so even a second is significant).""" | |
|
20 | ||
|
21 | t.slow = True | |
|
22 | return t | |
|
23 | ||
|
24 | def setastest(tf=True): | |
|
25 | ''' Signals to nose that this function is or is not a test | |
|
26 | ||
|
27 | Parameters | |
|
28 | ---------- | |
|
29 | tf : bool | |
|
30 | If True specifies this is a test, not a test otherwise | |
|
31 | ||
|
32 | e.g | |
|
33 | >>> from numpy.testing.decorators import setastest | |
|
34 | >>> @setastest(False) | |
|
35 | ... def func_with_test_in_name(arg1, arg2): pass | |
|
36 | ... | |
|
37 | >>> | |
|
38 | ||
|
39 | This decorator cannot use the nose namespace, because it can be | |
|
40 | called from a non-test module. See also istest and nottest in | |
|
41 | nose.tools | |
|
42 | ||
|
43 | ''' | |
|
44 | def set_test(t): | |
|
45 | t.__test__ = tf | |
|
46 | return t | |
|
47 | return set_test | |
|
48 | ||
|
49 | def skipif(skip_condition, msg=None): | |
|
50 | ''' Make function raise SkipTest exception if skip_condition is true | |
|
51 | ||
|
52 | Parameters | |
|
53 | --------- | |
|
54 | skip_condition : bool | |
|
55 | Flag to determine whether to skip test (True) or not (False) | |
|
56 | msg : string | |
|
57 | Message to give on raising a SkipTest exception | |
|
58 | ||
|
59 | Returns | |
|
60 | ------- | |
|
61 | decorator : function | |
|
62 | Decorator, which, when applied to a function, causes SkipTest | |
|
63 | to be raised when the skip_condition was True, and the function | |
|
64 | to be called normally otherwise. | |
|
65 | ||
|
66 | Notes | |
|
67 | ----- | |
|
68 | You will see from the code that we had to further decorate the | |
|
69 | decorator with the nose.tools.make_decorator function in order to | |
|
70 | transmit function name, and various other metadata. | |
|
71 | ''' | |
|
72 | if msg is None: | |
|
73 | msg = 'Test skipped due to test condition' | |
|
74 | def skip_decorator(f): | |
|
75 | # Local import to avoid a hard nose dependency and only incur the | |
|
76 | # import time overhead at actual test-time. | |
|
77 | import nose | |
|
78 | def skipper(*args, **kwargs): | |
|
79 | if skip_condition: | |
|
80 | raise nose.SkipTest, msg | |
|
81 | else: | |
|
82 | return f(*args, **kwargs) | |
|
83 | return nose.tools.make_decorator(f)(skipper) | |
|
84 | return skip_decorator | |
|
85 | ||
|
86 | def skipknownfailure(f): | |
|
87 | ''' Decorator to raise SkipTest for test known to fail | |
|
88 | ''' | |
|
89 | # Local import to avoid a hard nose dependency and only incur the | |
|
90 | # import time overhead at actual test-time. | |
|
91 | import nose | |
|
92 | def skipper(*args, **kwargs): | |
|
93 | raise nose.SkipTest, 'This test is known to fail' | |
|
94 | return nose.tools.make_decorator(f)(skipper) |
@@ -0,0 +1,17 b'' | |||
|
1 | """Simple script to show reference holding behavior. | |
|
2 | ||
|
3 | This is used by a companion test case. | |
|
4 | """ | |
|
5 | ||
|
6 | import gc | |
|
7 | ||
|
8 | class C(object): | |
|
9 | def __del__(self): | |
|
10 | print 'deleting object...' | |
|
11 | ||
|
12 | c = C() | |
|
13 | ||
|
14 | c_refs = gc.get_referrers(c) | |
|
15 | ref_ids = map(id,c_refs) | |
|
16 | ||
|
17 | print 'c referrers:',map(type,c_refs) |
@@ -0,0 +1,180 b'' | |||
|
1 | # Module imports | |
|
2 | # Std lib | |
|
3 | import inspect | |
|
4 | ||
|
5 | # Third party | |
|
6 | ||
|
7 | # Our own | |
|
8 | from IPython.testing import decorators as dec | |
|
9 | ||
|
10 | #----------------------------------------------------------------------------- | |
|
11 | # Utilities | |
|
12 | ||
|
13 | # Note: copied from OInspect, kept here so the testing stuff doesn't create | |
|
14 | # circular dependencies and is easier to reuse. | |
|
15 | def getargspec(obj): | |
|
16 | """Get the names and default values of a function's arguments. | |
|
17 | ||
|
18 | A tuple of four things is returned: (args, varargs, varkw, defaults). | |
|
19 | 'args' is a list of the argument names (it may contain nested lists). | |
|
20 | 'varargs' and 'varkw' are the names of the * and ** arguments or None. | |
|
21 | 'defaults' is an n-tuple of the default values of the last n arguments. | |
|
22 | ||
|
23 | Modified version of inspect.getargspec from the Python Standard | |
|
24 | Library.""" | |
|
25 | ||
|
26 | if inspect.isfunction(obj): | |
|
27 | func_obj = obj | |
|
28 | elif inspect.ismethod(obj): | |
|
29 | func_obj = obj.im_func | |
|
30 | else: | |
|
31 | raise TypeError, 'arg is not a Python function' | |
|
32 | args, varargs, varkw = inspect.getargs(func_obj.func_code) | |
|
33 | return args, varargs, varkw, func_obj.func_defaults | |
|
34 | ||
|
35 | #----------------------------------------------------------------------------- | |
|
36 | # Testing functions | |
|
37 | ||
|
38 | def test_trivial(): | |
|
39 | """A trivial passing test.""" | |
|
40 | pass | |
|
41 | ||
|
42 | ||
|
43 | @dec.skip | |
|
44 | def test_deliberately_broken(): | |
|
45 | """A deliberately broken test - we want to skip this one.""" | |
|
46 | 1/0 | |
|
47 | ||
|
48 | ||
|
49 | # Verify that we can correctly skip the doctest for a function at will, but | |
|
50 | # that the docstring itself is NOT destroyed by the decorator. | |
|
51 | @dec.skip_doctest | |
|
52 | def doctest_bad(x,y=1,**k): | |
|
53 | """A function whose doctest we need to skip. | |
|
54 | ||
|
55 | >>> 1+1 | |
|
56 | 3 | |
|
57 | """ | |
|
58 | print 'x:',x | |
|
59 | print 'y:',y | |
|
60 | print 'k:',k | |
|
61 | ||
|
62 | ||
|
63 | def call_doctest_bad(): | |
|
64 | """Check that we can still call the decorated functions. | |
|
65 | ||
|
66 | >>> doctest_bad(3,y=4) | |
|
67 | x: 3 | |
|
68 | y: 4 | |
|
69 | k: {} | |
|
70 | """ | |
|
71 | pass | |
|
72 | ||
|
73 | ||
|
74 | # Doctest skipping should work for class methods too | |
|
75 | class foo(object): | |
|
76 | """Foo | |
|
77 | ||
|
78 | Example: | |
|
79 | ||
|
80 | >>> 1+1 | |
|
81 | 2 | |
|
82 | """ | |
|
83 | ||
|
84 | @dec.skip_doctest | |
|
85 | def __init__(self,x): | |
|
86 | """Make a foo. | |
|
87 | ||
|
88 | Example: | |
|
89 | ||
|
90 | >>> f = foo(3) | |
|
91 | junk | |
|
92 | """ | |
|
93 | print 'Making a foo.' | |
|
94 | self.x = x | |
|
95 | ||
|
96 | @dec.skip_doctest | |
|
97 | def bar(self,y): | |
|
98 | """Example: | |
|
99 | ||
|
100 | >>> f = foo(3) | |
|
101 | >>> f.bar(0) | |
|
102 | boom! | |
|
103 | >>> 1/0 | |
|
104 | bam! | |
|
105 | """ | |
|
106 | return 1/y | |
|
107 | ||
|
108 | def baz(self,y): | |
|
109 | """Example: | |
|
110 | ||
|
111 | >>> f = foo(3) | |
|
112 | Making a foo. | |
|
113 | >>> f.baz(3) | |
|
114 | True | |
|
115 | """ | |
|
116 | return self.x==y | |
|
117 | ||
|
118 | ||
|
119 | def test_skip_dt_decorator(): | |
|
120 | """Doctest-skipping decorator should preserve the docstring. | |
|
121 | """ | |
|
122 | # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring! | |
|
123 | check = """A function whose doctest we need to skip. | |
|
124 | ||
|
125 | >>> 1+1 | |
|
126 | 3 | |
|
127 | """ | |
|
128 | # Fetch the docstring from doctest_bad after decoration. | |
|
129 | val = doctest_bad.__doc__ | |
|
130 | ||
|
131 | assert check==val,"doctest_bad docstrings don't match" | |
|
132 | ||
|
133 | ||
|
134 | def test_skip_dt_decorator2(): | |
|
135 | """Doctest-skipping decorator should preserve function signature. | |
|
136 | """ | |
|
137 | # Hardcoded correct answer | |
|
138 | dtargs = (['x', 'y'], None, 'k', (1,)) | |
|
139 | # Introspect out the value | |
|
140 | dtargsr = getargspec(doctest_bad) | |
|
141 | assert dtargsr==dtargs, \ | |
|
142 | "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,) | |
|
143 | ||
|
144 | ||
|
145 | def doctest_run(): | |
|
146 | """Test running a trivial script. | |
|
147 | ||
|
148 | In [13]: run simplevars.py | |
|
149 | x is: 1 | |
|
150 | """ | |
|
151 | ||
|
152 | #@dec.skip_doctest | |
|
153 | def doctest_runvars(): | |
|
154 | """Test that variables defined in scripts get loaded correcly via %run. | |
|
155 | ||
|
156 | In [13]: run simplevars.py | |
|
157 | x is: 1 | |
|
158 | ||
|
159 | In [14]: x | |
|
160 | Out[14]: 1 | |
|
161 | """ | |
|
162 | ||
|
163 | def doctest_ivars(): | |
|
164 | """Test that variables defined interactively are picked up. | |
|
165 | In [5]: zz=1 | |
|
166 | ||
|
167 | In [6]: zz | |
|
168 | Out[6]: 1 | |
|
169 | """ | |
|
170 | ||
|
171 | @dec.skip_doctest | |
|
172 | def doctest_refs(): | |
|
173 | """DocTest reference holding issues when running scripts. | |
|
174 | ||
|
175 | In [32]: run show_refs.py | |
|
176 | c referrers: [<type 'dict'>] | |
|
177 | ||
|
178 | In [33]: map(type,gc.get_referrers(c)) | |
|
179 | Out[33]: [<type 'dict'>] | |
|
180 | """ |
|
1 | NO CONTENT: new file 100644 |
@@ -0,0 +1,18 b'' | |||
|
1 | from IPython.kernel import client | |
|
2 | ||
|
3 | mec = client.MultiEngineClient() | |
|
4 | ||
|
5 | result = mec.map(lambda x: 2*x, range(10)) | |
|
6 | print "Simple, default map: ", result | |
|
7 | ||
|
8 | m = mec.mapper(block=False) | |
|
9 | pr = m.map(lambda x: 2*x, range(10)) | |
|
10 | print "Submitted map, got PendingResult: ", pr | |
|
11 | result = pr.r | |
|
12 | print "Using a mapper: ", result | |
|
13 | ||
|
14 | @mec.parallel() | |
|
15 | def f(x): return 2*x | |
|
16 | ||
|
17 | result = f(range(10)) | |
|
18 | print "Using a parallel function: ", result No newline at end of file |
@@ -0,0 +1,19 b'' | |||
|
1 | from IPython.kernel import client | |
|
2 | ||
|
3 | tc = client.TaskClient() | |
|
4 | ||
|
5 | result = tc.map(lambda x: 2*x, range(10)) | |
|
6 | print "Simple, default map: ", result | |
|
7 | ||
|
8 | m = tc.mapper(block=False, clear_after=True, clear_before=True) | |
|
9 | tids = m.map(lambda x: 2*x, range(10)) | |
|
10 | print "Submitted tasks, got ids: ", tids | |
|
11 | tc.barrier(tids) | |
|
12 | result = [tc.get_task_result(tid) for tid in tids] | |
|
13 | print "Using a mapper: ", result | |
|
14 | ||
|
15 | @tc.parallel() | |
|
16 | def f(x): return 2*x | |
|
17 | ||
|
18 | result = f(range(10)) | |
|
19 | print "Using a parallel function: ", result No newline at end of file |
@@ -0,0 +1,47 b'' | |||
|
1 | .. Notification: | |
|
2 | ||
|
3 | ========================================== | |
|
4 | IPython.kernel.core.notification blueprint | |
|
5 | ========================================== | |
|
6 | ||
|
7 | Overview | |
|
8 | ======== | |
|
9 | The :mod:`IPython.kernel.core.notification` module will provide a simple implementation of a notification center and support for the observer pattern within the :mod:`IPython.kernel.core`. The main intended use case is to provide notification of Interpreter events to an observing frontend during the execution of a single block of code. | |
|
10 | ||
|
11 | Functional Requirements | |
|
12 | ======================= | |
|
13 | The notification center must: | |
|
14 | * Provide synchronous notification of events to all registered observers. | |
|
15 | * Provide typed or labeled notification types | |
|
16 | * Allow observers to register callbacks for individual or all notification types | |
|
17 | * Allow observers to register callbacks for events from individual or all notifying objects | |
|
18 | * Notification to the observer consists of the notification type, notifying object and user-supplied extra information [implementation: as keyword parameters to the registered callback] | |
|
19 | * Perform as O(1) in the case of no registered observers. | |
|
20 | * Permit out-of-process or cross-network extension. | |
|
21 | ||
|
22 | What's not included | |
|
23 | ============================================================== | |
|
24 | As written, the :mod:`IPython.kernel.core.notificaiton` module does not: | |
|
25 | * Provide out-of-process or network notifications [these should be handled by a separate, Twisted aware module in :mod:`IPython.kernel`]. | |
|
26 | * Provide zope.interface-style interfaces for the notification system [these should also be provided by the :mod:`IPython.kernel` module] | |
|
27 | ||
|
28 | Use Cases | |
|
29 | ========= | |
|
30 | The following use cases describe the main intended uses of the notificaiton module and illustrate the main success scenario for each use case: | |
|
31 | ||
|
32 | 1. Dwight Schroot is writing a frontend for the IPython project. His frontend is stuck in the stone age and must communicate synchronously with an IPython.kernel.core.Interpreter instance. Because code is executed in blocks by the Interpreter, Dwight's UI freezes every time he executes a long block of code. To keep track of the progress of his long running block, Dwight adds the following code to his frontend's set-up code:: | |
|
33 | from IPython.kernel.core.notification import NotificationCenter | |
|
34 | center = NotificationCenter.sharedNotificationCenter | |
|
35 | center.registerObserver(self, type=IPython.kernel.core.Interpreter.STDOUT_NOTIFICATION_TYPE, notifying_object=self.interpreter, callback=self.stdout_notification) | |
|
36 | ||
|
37 | and elsewhere in his front end:: | |
|
38 | def stdout_notification(self, type, notifying_object, out_string=None): | |
|
39 | self.writeStdOut(out_string) | |
|
40 | ||
|
41 | If everything works, the Interpreter will (according to its published API) fire a notification via the :data:`IPython.kernel.core.notification.sharedCenter` of type :const:`STD_OUT_NOTIFICATION_TYPE` before writing anything to stdout [it's up to the Intereter implementation to figure out when to do this]. The notificaiton center will then call the registered callbacks for that event type (in this case, Dwight's frontend's stdout_notification method). Again, according to its API, the Interpreter provides an additional keyword argument when firing the notificaiton of out_string, a copy of the string it will write to stdout. | |
|
42 | ||
|
43 | Like magic, Dwight's frontend is able to provide output, even during long-running calculations. Now if Jim could just convince Dwight to use Twisted... | |
|
44 | ||
|
45 | 2. Boss Hog is writing a frontend for the IPython project. Because Boss Hog is stuck in the stone age, his frontend will be written in a new Fortran-like dialect of python and will run only from the command line. Because he doesn't need any fancy notification system and is used to worrying about every cycle on his rat-wheel powered mini, Boss Hog is adamant that the new notification system not produce any performance penalty. As they say in Hazard county, there's no such thing as a free lunch. If he wanted zero overhead, he should have kept using IPython 0.8. Instead, those tricky Duke boys slide in a suped-up bridge-out jumpin' awkwardly confederate-lovin' notification module that imparts only a constant (and small) performance penalty when the Interpreter (or any other object) fires an event for which there are no registered observers. Of course, the same notificaiton-enabled Interpreter can then be used in frontends that require notifications, thus saving the IPython project from a nasty civil war. | |
|
46 | ||
|
47 | 3. Barry is wrting a frontend for the IPython project. Because Barry's front end is the *new hotness*, it uses an asynchronous event model to communicate with a Twisted :mod:`~IPython.kernel.engineservice` that communicates with the IPython :class:`~IPython.kernel.core.interpreter.Interpreter`. Using the :mod:`IPython.kernel.notification` module, an asynchronous wrapper on the :mod:`IPython.kernel.core.notification` module, Barry's frontend can register for notifications from the interpreter that are delivered asynchronously. Even if Barry's frontend is running on a separate process or even host from the Interpreter, the notifications are delivered, as if by dark and twisted magic. Just like Dwight's frontend, Barry's frontend can now recieve notifications of e.g. writing to stdout/stderr, opening/closing an external file, an exception in the executing code, etc. No newline at end of file |
@@ -61,9 +61,11 b' class Style(object):' | |||
|
61 | 61 | ``bg`` as the background color and ``attrs`` as the attributes. |
|
62 | 62 | |
|
63 | 63 | Examples: |
|
64 | ||
|
65 | 64 |
|
|
65 | <Style fg=red bg=black attrs=0> | |
|
66 | ||
|
66 | 67 |
|
|
68 | <Style fg=yellow bg=blue attrs=bold|underline> | |
|
67 | 69 | """ |
|
68 | 70 | self.fg = fg |
|
69 | 71 | self.bg = bg |
@@ -83,6 +83,8 b' three extensions points (all of them optional):' | |||
|
83 | 83 | maxunicode |0xffff |
|
84 | 84 | """ |
|
85 | 85 | |
|
86 | skip_doctest = True # ignore top-level docstring as a doctest. | |
|
87 | ||
|
86 | 88 | import sys, os, os.path, stat, glob, new, csv, datetime, types |
|
87 | 89 | import itertools, mimetypes, StringIO |
|
88 | 90 | |
@@ -123,8 +125,7 b' except ImportError:' | |||
|
123 | 125 | grp = None |
|
124 | 126 | |
|
125 | 127 | from IPython.external import simplegeneric |
|
126 | ||
|
127 | import path | |
|
128 | from IPython.external import path | |
|
128 | 129 | |
|
129 | 130 | try: |
|
130 | 131 | from IPython import genutils, generics |
@@ -1210,8 +1211,12 b' class ils(Table):' | |||
|
1210 | 1211 | Examples:: |
|
1211 | 1212 | |
|
1212 | 1213 | >>> ils |
|
1214 | <class 'IPython.Extensions.ipipe.ils'> | |
|
1213 | 1215 | >>> ils("/usr/local/lib/python2.4") |
|
1216 | IPython.Extensions.ipipe.ils('/usr/local/lib/python2.4') | |
|
1214 | 1217 | >>> ils("~") |
|
1218 | IPython.Extensions.ipipe.ils('/home/fperez') | |
|
1219 | # all-random | |
|
1215 | 1220 | """ |
|
1216 | 1221 | def __init__(self, base=os.curdir, dirs=True, files=True): |
|
1217 | 1222 | self.base = os.path.expanduser(base) |
@@ -1248,6 +1253,7 b' class iglob(Table):' | |||
|
1248 | 1253 | Examples:: |
|
1249 | 1254 | |
|
1250 | 1255 | >>> iglob("*.py") |
|
1256 | IPython.Extensions.ipipe.iglob('*.py') | |
|
1251 | 1257 | """ |
|
1252 | 1258 | def __init__(self, glob): |
|
1253 | 1259 | self.glob = glob |
@@ -1273,8 +1279,12 b' class iwalk(Table):' | |||
|
1273 | 1279 | List all files and directories in a directory and it's subdirectory:: |
|
1274 | 1280 | |
|
1275 | 1281 | >>> iwalk |
|
1276 | >>> iwalk("/usr/local/lib/python2.4") | |
|
1282 | <class 'IPython.Extensions.ipipe.iwalk'> | |
|
1283 | >>> iwalk("/usr/lib") | |
|
1284 | IPython.Extensions.ipipe.iwalk('/usr/lib') | |
|
1277 | 1285 | >>> iwalk("~") |
|
1286 | IPython.Extensions.ipipe.iwalk('/home/fperez') # random | |
|
1287 | ||
|
1278 | 1288 | """ |
|
1279 | 1289 | def __init__(self, base=os.curdir, dirs=True, files=True): |
|
1280 | 1290 | self.base = os.path.expanduser(base) |
@@ -1378,6 +1388,8 b' class ipwd(Table):' | |||
|
1378 | 1388 | Example:: |
|
1379 | 1389 | |
|
1380 | 1390 | >>> ipwd | isort("uid") |
|
1391 | <IPython.Extensions.ipipe.isort key='uid' reverse=False at 0x849efec> | |
|
1392 | # random | |
|
1381 | 1393 | """ |
|
1382 | 1394 | def __iter__(self): |
|
1383 | 1395 | for entry in pwd.getpwall(): |
@@ -1562,6 +1574,7 b' class ienv(Table):' | |||
|
1562 | 1574 | Example:: |
|
1563 | 1575 | |
|
1564 | 1576 | >>> ienv |
|
1577 | <class 'IPython.Extensions.ipipe.ienv'> | |
|
1565 | 1578 | """ |
|
1566 | 1579 | |
|
1567 | 1580 | def __iter__(self): |
@@ -1583,7 +1596,9 b' class ihist(Table):' | |||
|
1583 | 1596 | Example:: |
|
1584 | 1597 | |
|
1585 | 1598 | >>> ihist |
|
1586 | >>> ihist(True) (raw mode) | |
|
1599 | <class 'IPython.Extensions.ipipe.ihist'> | |
|
1600 | >>> ihist(True) # raw mode | |
|
1601 | <IPython.Extensions.ipipe.ihist object at 0x849602c> # random | |
|
1587 | 1602 | """ |
|
1588 | 1603 | def __init__(self, raw=True): |
|
1589 | 1604 | self.raw = raw |
@@ -1618,6 +1633,7 b' class ialias(Table):' | |||
|
1618 | 1633 | Example:: |
|
1619 | 1634 | |
|
1620 | 1635 | >>> ialias |
|
1636 | <class 'IPython.Extensions.ipipe.ialias'> | |
|
1621 | 1637 | """ |
|
1622 | 1638 | def __iter__(self): |
|
1623 | 1639 | api = ipapi.get() |
@@ -1680,7 +1696,11 b' class ix(Table):' | |||
|
1680 | 1696 | Examples:: |
|
1681 | 1697 | |
|
1682 | 1698 | >>> ix("ps x") |
|
1699 | IPython.Extensions.ipipe.ix('ps x') | |
|
1700 | ||
|
1683 | 1701 | >>> ix("find .") | ifile |
|
1702 | <IPython.Extensions.ipipe.ieval expr=<class 'IPython.Extensions.ipipe.ifile'> at 0x8509d2c> | |
|
1703 | # random | |
|
1684 | 1704 | """ |
|
1685 | 1705 | def __init__(self, cmd): |
|
1686 | 1706 | self.cmd = cmd |
@@ -1721,6 +1741,7 b' class ifilter(Pipe):' | |||
|
1721 | 1741 | >>> ils | ifilter("_.isfile() and size>1000") |
|
1722 | 1742 | >>> igrp | ifilter("len(mem)") |
|
1723 | 1743 | >>> sys.modules | ifilter(lambda _:_.value is not None) |
|
1744 | # all-random | |
|
1724 | 1745 | """ |
|
1725 | 1746 | |
|
1726 | 1747 | def __init__(self, expr, globals=None, errors="raiseifallfail"): |
@@ -1811,7 +1832,9 b' class ieval(Pipe):' | |||
|
1811 | 1832 | Examples:: |
|
1812 | 1833 | |
|
1813 | 1834 | >>> ils | ieval("_.abspath()") |
|
1835 | # random | |
|
1814 | 1836 | >>> sys.path | ieval(ifile) |
|
1837 | # random | |
|
1815 | 1838 | """ |
|
1816 | 1839 | |
|
1817 | 1840 | def __init__(self, expr, globals=None, errors="raiseifallfail"): |
@@ -1884,6 +1907,8 b' class ienum(Pipe):' | |||
|
1884 | 1907 | |
|
1885 | 1908 | >>> xrange(20) | ieval("_,_*_") | ienum | ifilter("index % 2 == 0") | ieval("object") |
|
1886 | 1909 | """ |
|
1910 | skip_doctest = True | |
|
1911 | ||
|
1887 | 1912 | def __iter__(self): |
|
1888 | 1913 | fields = ("index", "object") |
|
1889 | 1914 | for (index, object) in enumerate(xiter(self.input)): |
@@ -1897,7 +1922,10 b' class isort(Pipe):' | |||
|
1897 | 1922 | Examples:: |
|
1898 | 1923 | |
|
1899 | 1924 | >>> ils | isort("size") |
|
1925 | <IPython.Extensions.ipipe.isort key='size' reverse=False at 0x849ec2c> | |
|
1900 | 1926 | >>> ils | isort("_.isdir(), _.lower()", reverse=True) |
|
1927 | <IPython.Extensions.ipipe.isort key='_.isdir(), _.lower()' reverse=True at 0x849eacc> | |
|
1928 | # all-random | |
|
1901 | 1929 | """ |
|
1902 | 1930 | |
|
1903 | 1931 | def __init__(self, key=None, globals=None, reverse=False): |
@@ -2058,6 +2086,8 b' class icap(Table):' | |||
|
2058 | 2086 | >>> icap("for i in range(10): print i, time.sleep(0.1)") |
|
2059 | 2087 | |
|
2060 | 2088 | """ |
|
2089 | skip_doctest = True | |
|
2090 | ||
|
2061 | 2091 | def __init__(self, expr, globals=None): |
|
2062 | 2092 | self.expr = expr |
|
2063 | 2093 | self.globals = globals |
@@ -174,23 +174,15 b' class LeoNode(object, UserDict.DictMixin):' | |||
|
174 | 174 | |
|
175 | 175 | def __get_h(self): return self.p.headString() |
|
176 | 176 | def __set_h(self,val): |
|
177 | print "set head",val | |
|
178 | c.beginUpdate() | |
|
179 | try: | |
|
180 | 177 |
|
|
181 | finally: | |
|
182 | c.endUpdate() | |
|
178 | c.redraw() | |
|
183 | 179 | |
|
184 | 180 | h = property( __get_h, __set_h, doc = "Node headline string") |
|
185 | 181 | |
|
186 | 182 | def __get_b(self): return self.p.bodyString() |
|
187 | 183 | def __set_b(self,val): |
|
188 | print "set body",val | |
|
189 | c.beginUpdate() | |
|
190 | try: | |
|
191 | 184 |
|
|
192 | finally: | |
|
193 | c.endUpdate() | |
|
185 | c.redraw() | |
|
194 | 186 | |
|
195 | 187 | b = property(__get_b, __set_b, doc = "Nody body string") |
|
196 | 188 | |
@@ -265,11 +257,8 b' class LeoNode(object, UserDict.DictMixin):' | |||
|
265 | 257 | |
|
266 | 258 | def go(self): |
|
267 | 259 | """ Set node as current node (to quickly see it in Outline) """ |
|
268 | c.beginUpdate() | |
|
269 | try: | |
|
270 | 260 |
|
|
271 | finally: | |
|
272 | c.endUpdate() | |
|
261 | c.redraw() | |
|
273 | 262 | |
|
274 | 263 | def script(self): |
|
275 | 264 | """ Method to get the 'tangled' contents of the node |
@@ -337,7 +326,6 b' def workbook_complete(obj, prev):' | |||
|
337 | 326 | |
|
338 | 327 | |
|
339 | 328 | def add_var(varname): |
|
340 | c.beginUpdate() | |
|
341 | 329 | r = rootnode() |
|
342 | 330 | try: |
|
343 | 331 | if r is None: |
@@ -356,7 +344,7 b' def add_var(varname):' | |||
|
356 | 344 | c.setHeadString(p2,varname) |
|
357 | 345 | return LeoNode(p2) |
|
358 | 346 | finally: |
|
359 |
c. |
|
|
347 | c.redraw() | |
|
360 | 348 | |
|
361 | 349 | def add_file(self,fname): |
|
362 | 350 | p2 = c.currentPosition().insertAfter() |
@@ -368,7 +356,6 b' def expose_ileo_push(f, prio = 0):' | |||
|
368 | 356 | |
|
369 | 357 | def push_ipython_script(node): |
|
370 | 358 | """ Execute the node body in IPython, as if it was entered in interactive prompt """ |
|
371 | c.beginUpdate() | |
|
372 | 359 | try: |
|
373 | 360 | ohist = ip.IP.output_hist |
|
374 | 361 | hstart = len(ip.IP.input_hist) |
@@ -393,7 +380,7 b' def push_ipython_script(node):' | |||
|
393 | 380 | if not has_output: |
|
394 | 381 | es('ipy run: %s (%d LL)' %( node.h,len(script))) |
|
395 | 382 | finally: |
|
396 |
c. |
|
|
383 | c.redraw() | |
|
397 | 384 | |
|
398 | 385 | |
|
399 | 386 | def eval_body(body): |
@@ -495,7 +482,6 b' def lee_f(self,s):' | |||
|
495 | 482 | """ |
|
496 | 483 | import os |
|
497 | 484 | |
|
498 | c.beginUpdate() | |
|
499 | 485 | try: |
|
500 | 486 | if s == 'hist': |
|
501 | 487 | wb.ipython_history.b = get_history() |
@@ -533,7 +519,7 b' def lee_f(self,s):' | |||
|
533 | 519 | c.selectPosition(p) |
|
534 | 520 | print "Editing file(s), press ctrl+shift+w in Leo to write @auto nodes" |
|
535 | 521 | finally: |
|
536 |
c. |
|
|
522 | c.redraw() | |
|
537 | 523 | |
|
538 | 524 | |
|
539 | 525 |
@@ -61,6 +61,8 b' from IPython import platutils' | |||
|
61 | 61 | import IPython.generics |
|
62 | 62 | import IPython.ipapi |
|
63 | 63 | from IPython.ipapi import UsageError |
|
64 | from IPython.testing import decorators as testdec | |
|
65 | ||
|
64 | 66 | #*************************************************************************** |
|
65 | 67 | # Utility functions |
|
66 | 68 | def on_off(tag): |
@@ -522,7 +524,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
522 | 524 | rc.automagic = not rc.automagic |
|
523 | 525 | print '\n' + Magic.auto_status[rc.automagic] |
|
524 | 526 | |
|
525 | ||
|
527 | @testdec.skip_doctest | |
|
526 | 528 | def magic_autocall(self, parameter_s = ''): |
|
527 | 529 | """Make functions callable without having to type parentheses. |
|
528 | 530 | |
@@ -551,8 +553,9 b' Currently the magic system has the following functions:\\n"""' | |||
|
551 | 553 | 2 -> Active always. Even if no arguments are present, the callable |
|
552 | 554 | object is called: |
|
553 | 555 | |
|
554 |
In [ |
|
|
555 |
------> |
|
|
556 | In [2]: float | |
|
557 | ------> float() | |
|
558 | Out[2]: 0.0 | |
|
556 | 559 | |
|
557 | 560 | Note that even with autocall off, you can still use '/' at the start of |
|
558 | 561 | a line to treat the first argument on the command line as a function |
@@ -561,6 +564,8 b' Currently the magic system has the following functions:\\n"""' | |||
|
561 | 564 | In [8]: /str 43 |
|
562 | 565 | ------> str(43) |
|
563 | 566 | Out[8]: '43' |
|
567 | ||
|
568 | # all-random (note for auto-testing) | |
|
564 | 569 | """ |
|
565 | 570 | |
|
566 | 571 | rc = self.shell.rc |
@@ -1243,12 +1248,13 b' Currently the magic system has the following functions:\\n"""' | |||
|
1243 | 1248 | |
|
1244 | 1249 | self.shell.debugger(force=True) |
|
1245 | 1250 | |
|
1251 | @testdec.skip_doctest | |
|
1246 | 1252 | def magic_prun(self, parameter_s ='',user_mode=1, |
|
1247 | 1253 | opts=None,arg_lst=None,prog_ns=None): |
|
1248 | 1254 | |
|
1249 | 1255 | """Run a statement through the python code profiler. |
|
1250 | 1256 | |
|
1251 |
Usage: |
|
|
1257 | Usage: | |
|
1252 | 1258 | %prun [options] statement |
|
1253 | 1259 | |
|
1254 | 1260 | The given statement (which doesn't require quote marks) is run via the |
@@ -1293,16 +1299,16 b' Currently the magic system has the following functions:\\n"""' | |||
|
1293 | 1299 | abbreviation is unambiguous. The following are the keys currently |
|
1294 | 1300 | defined: |
|
1295 | 1301 | |
|
1296 |
Valid Arg Meaning |
|
|
1297 |
"calls" call count |
|
|
1298 |
"cumulative" cumulative time |
|
|
1299 |
"file" file name |
|
|
1300 |
"module" file name |
|
|
1301 |
"pcalls" primitive call count |
|
|
1302 |
"line" line number |
|
|
1303 |
"name" function name |
|
|
1304 |
"nfl" name/file/line |
|
|
1305 |
"stdname" standard name |
|
|
1302 | Valid Arg Meaning | |
|
1303 | "calls" call count | |
|
1304 | "cumulative" cumulative time | |
|
1305 | "file" file name | |
|
1306 | "module" file name | |
|
1307 | "pcalls" primitive call count | |
|
1308 | "line" line number | |
|
1309 | "name" function name | |
|
1310 | "nfl" name/file/line | |
|
1311 | "stdname" standard name | |
|
1306 | 1312 | "time" internal time |
|
1307 | 1313 | |
|
1308 | 1314 | Note that all sorts on statistics are in descending order (placing |
@@ -1328,8 +1334,10 b' Currently the magic system has the following functions:\\n"""' | |||
|
1328 | 1334 | '%run -p [prof_opts] filename.py [args to program]' where prof_opts |
|
1329 | 1335 | contains profiler specific options as described here. |
|
1330 | 1336 | |
|
1331 |
You can read the complete documentation for the profile module with: |
|
|
1332 | In [1]: import profile; profile.help() """ | |
|
1337 | You can read the complete documentation for the profile module with:: | |
|
1338 | ||
|
1339 | In [1]: import profile; profile.help() | |
|
1340 | """ | |
|
1333 | 1341 | |
|
1334 | 1342 | opts_def = Struct(D=[''],l=[],s=['time'],T=['']) |
|
1335 | 1343 | # protect user quote marks |
@@ -1413,6 +1421,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
1413 | 1421 | else: |
|
1414 | 1422 | return None |
|
1415 | 1423 | |
|
1424 | @testdec.skip_doctest | |
|
1416 | 1425 | def magic_run(self, parameter_s ='',runner=None): |
|
1417 | 1426 | """Run the named file inside IPython as a program. |
|
1418 | 1427 | |
@@ -1575,12 +1584,16 b' Currently the magic system has the following functions:\\n"""' | |||
|
1575 | 1584 | |
|
1576 | 1585 | # pickle fix. See iplib for an explanation. But we need to make sure |
|
1577 | 1586 | # that, if we overwrite __main__, we replace it at the end |
|
1578 |
|
|
|
1587 | main_mod_name = prog_ns['__name__'] | |
|
1588 | ||
|
1589 | if main_mod_name == '__main__': | |
|
1579 | 1590 | restore_main = sys.modules['__main__'] |
|
1580 | 1591 | else: |
|
1581 | 1592 | restore_main = False |
|
1582 | 1593 | |
|
1583 | sys.modules[prog_ns['__name__']] = main_mod | |
|
1594 | # This needs to be undone at the end to prevent holding references to | |
|
1595 | # every single object ever created. | |
|
1596 | sys.modules[main_mod_name] = main_mod | |
|
1584 | 1597 | |
|
1585 | 1598 | stats = None |
|
1586 | 1599 | try: |
@@ -1673,9 +1686,15 b' Currently the magic system has the following functions:\\n"""' | |||
|
1673 | 1686 | del prog_ns['__name__'] |
|
1674 | 1687 | self.shell.user_ns.update(prog_ns) |
|
1675 | 1688 | finally: |
|
1689 | # Ensure key global structures are restored | |
|
1676 | 1690 | sys.argv = save_argv |
|
1677 | 1691 | if restore_main: |
|
1678 | 1692 | sys.modules['__main__'] = restore_main |
|
1693 | else: | |
|
1694 | # Remove from sys.modules the reference to main_mod we'd | |
|
1695 | # added. Otherwise it will trap references to objects | |
|
1696 | # contained therein. | |
|
1697 | del sys.modules[main_mod_name] | |
|
1679 | 1698 | self.shell.reloadhist() |
|
1680 | 1699 | |
|
1681 | 1700 | return stats |
@@ -1699,6 +1718,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
1699 | 1718 | self.shell.safe_execfile(f,self.shell.user_ns, |
|
1700 | 1719 | self.shell.user_ns,islog=1) |
|
1701 | 1720 | |
|
1721 | @testdec.skip_doctest | |
|
1702 | 1722 | def magic_timeit(self, parameter_s =''): |
|
1703 | 1723 | """Time execution of a Python statement or expression |
|
1704 | 1724 | |
@@ -1726,7 +1746,8 b' Currently the magic system has the following functions:\\n"""' | |||
|
1726 | 1746 | Default: 3 |
|
1727 | 1747 | |
|
1728 | 1748 | |
|
1729 |
Examples: |
|
|
1749 | Examples: | |
|
1750 | ||
|
1730 | 1751 | In [1]: %timeit pass |
|
1731 | 1752 | 10000000 loops, best of 3: 53.3 ns per loop |
|
1732 | 1753 | |
@@ -1755,7 +1776,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
1755 | 1776 | import timeit |
|
1756 | 1777 | import math |
|
1757 | 1778 | |
|
1758 |
units = ["s", "ms", " |
|
|
1779 | units = [u"s", u"ms", u"\xb5s", u"ns"] | |
|
1759 | 1780 | scaling = [1, 1e3, 1e6, 1e9] |
|
1760 | 1781 | |
|
1761 | 1782 | opts, stmt = self.parse_options(parameter_s,'n:r:tcp:', |
@@ -1804,13 +1825,14 b' Currently the magic system has the following functions:\\n"""' | |||
|
1804 | 1825 | order = min(-int(math.floor(math.log10(best)) // 3), 3) |
|
1805 | 1826 | else: |
|
1806 | 1827 | order = 3 |
|
1807 | print "%d loops, best of %d: %.*g %s per loop" % (number, repeat, | |
|
1828 | print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat, | |
|
1808 | 1829 | precision, |
|
1809 | 1830 | best * scaling[order], |
|
1810 | 1831 | units[order]) |
|
1811 | 1832 | if tc > tc_min: |
|
1812 | 1833 | print "Compiler time: %.2f s" % tc |
|
1813 | 1834 | |
|
1835 | @testdec.skip_doctest | |
|
1814 | 1836 | def magic_time(self,parameter_s = ''): |
|
1815 | 1837 | """Time execution of a Python statement or expression. |
|
1816 | 1838 | |
@@ -1902,6 +1924,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
1902 | 1924 | print "Compiler : %.2f s" % tc |
|
1903 | 1925 | return out |
|
1904 | 1926 | |
|
1927 | @testdec.skip_doctest | |
|
1905 | 1928 | def magic_macro(self,parameter_s = ''): |
|
1906 | 1929 | """Define a set of input lines as a macro for future re-execution. |
|
1907 | 1930 | |
@@ -1931,17 +1954,17 b' Currently the magic system has the following functions:\\n"""' | |||
|
1931 | 1954 | |
|
1932 | 1955 | For example, if your history contains (%hist prints it): |
|
1933 | 1956 | |
|
1934 |
44: x=1 |
|
|
1935 |
45: y=3 |
|
|
1936 |
46: z=x+y |
|
|
1937 |
47: print x |
|
|
1938 |
48: a=5 |
|
|
1939 |
49: print 'x',x,'y',y |
|
|
1957 | 44: x=1 | |
|
1958 | 45: y=3 | |
|
1959 | 46: z=x+y | |
|
1960 | 47: print x | |
|
1961 | 48: a=5 | |
|
1962 | 49: print 'x',x,'y',y | |
|
1940 | 1963 | |
|
1941 | 1964 | you can create a macro with lines 44 through 47 (included) and line 49 |
|
1942 | 1965 | called my_macro with: |
|
1943 | 1966 | |
|
1944 |
In [5 |
|
|
1967 | In [55]: %macro my_macro 44-47 49 | |
|
1945 | 1968 | |
|
1946 | 1969 | Now, typing `my_macro` (without quotes) will re-execute all this code |
|
1947 | 1970 | in one pass. |
@@ -2033,6 +2056,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
2033 | 2056 | """Alias to %edit.""" |
|
2034 | 2057 | return self.magic_edit(parameter_s) |
|
2035 | 2058 | |
|
2059 | @testdec.skip_doctest | |
|
2036 | 2060 | def magic_edit(self,parameter_s='',last_call=['','']): |
|
2037 | 2061 | """Bring up an editor and execute the resulting code. |
|
2038 | 2062 | |
@@ -2126,47 +2150,47 b' Currently the magic system has the following functions:\\n"""' | |||
|
2126 | 2150 | This is an example of creating a simple function inside the editor and |
|
2127 | 2151 | then modifying it. First, start up the editor: |
|
2128 | 2152 | |
|
2129 |
In [1]: ed |
|
|
2130 |
Editing... done. Executing edited code... |
|
|
2131 |
Out[1]: 'def foo(): |
|
|
2153 | In [1]: ed | |
|
2154 | Editing... done. Executing edited code... | |
|
2155 | Out[1]: 'def foo():n print "foo() was defined in an editing session"n' | |
|
2132 | 2156 | |
|
2133 | 2157 | We can then call the function foo(): |
|
2134 | 2158 | |
|
2135 |
In [2]: foo() |
|
|
2159 | In [2]: foo() | |
|
2136 | 2160 | foo() was defined in an editing session |
|
2137 | 2161 | |
|
2138 | 2162 | Now we edit foo. IPython automatically loads the editor with the |
|
2139 | 2163 | (temporary) file where foo() was previously defined: |
|
2140 | 2164 | |
|
2141 |
In [3]: ed foo |
|
|
2165 | In [3]: ed foo | |
|
2142 | 2166 | Editing... done. Executing edited code... |
|
2143 | 2167 | |
|
2144 | 2168 | And if we call foo() again we get the modified version: |
|
2145 | 2169 | |
|
2146 |
In [4]: foo() |
|
|
2170 | In [4]: foo() | |
|
2147 | 2171 | foo() has now been changed! |
|
2148 | 2172 | |
|
2149 | 2173 | Here is an example of how to edit a code snippet successive |
|
2150 | 2174 | times. First we call the editor: |
|
2151 | 2175 | |
|
2152 |
In [ |
|
|
2153 |
Editing... done. Executing edited code... |
|
|
2154 |
hello |
|
|
2155 |
Out[ |
|
|
2176 | In [5]: ed | |
|
2177 | Editing... done. Executing edited code... | |
|
2178 | hello | |
|
2179 | Out[5]: "print 'hello'n" | |
|
2156 | 2180 | |
|
2157 | 2181 | Now we call it again with the previous output (stored in _): |
|
2158 | 2182 | |
|
2159 |
In [ |
|
|
2160 |
Editing... done. Executing edited code... |
|
|
2161 |
hello world |
|
|
2162 |
Out[ |
|
|
2183 | In [6]: ed _ | |
|
2184 | Editing... done. Executing edited code... | |
|
2185 | hello world | |
|
2186 | Out[6]: "print 'hello world'n" | |
|
2163 | 2187 | |
|
2164 | 2188 | Now we call it with the output #8 (stored in _8, also as Out[8]): |
|
2165 | 2189 | |
|
2166 |
In [ |
|
|
2167 |
Editing... done. Executing edited code... |
|
|
2168 |
hello again |
|
|
2169 |
Out[ |
|
|
2190 | In [7]: ed _8 | |
|
2191 | Editing... done. Executing edited code... | |
|
2192 | hello again | |
|
2193 | Out[7]: "print 'hello again'n" | |
|
2170 | 2194 | |
|
2171 | 2195 | |
|
2172 | 2196 | Changing the default editor hook: |
@@ -2464,6 +2488,7 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
2464 | 2488 | #...................................................................... |
|
2465 | 2489 | # Functions to implement unix shell-type things |
|
2466 | 2490 | |
|
2491 | @testdec.skip_doctest | |
|
2467 | 2492 | def magic_alias(self, parameter_s = ''): |
|
2468 | 2493 | """Define an alias for a system command. |
|
2469 | 2494 | |
@@ -2479,18 +2504,18 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
2479 | 2504 | You can use the %l specifier in an alias definition to represent the |
|
2480 | 2505 | whole line when the alias is called. For example: |
|
2481 | 2506 | |
|
2482 |
In [2]: alias all echo "Input in brackets: <%l>" |
|
|
2483 |
In [3]: all hello world |
|
|
2507 | In [2]: alias all echo "Input in brackets: <%l>" | |
|
2508 | In [3]: all hello world | |
|
2484 | 2509 | Input in brackets: <hello world> |
|
2485 | 2510 | |
|
2486 | 2511 | You can also define aliases with parameters using %s specifiers (one |
|
2487 | 2512 | per parameter): |
|
2488 | 2513 | |
|
2489 |
In [1]: alias parts echo first %s second %s |
|
|
2490 |
In [2]: %parts A B |
|
|
2491 |
first A second B |
|
|
2492 |
In [3]: %parts A |
|
|
2493 |
Incorrect number of arguments: 2 expected. |
|
|
2514 | In [1]: alias parts echo first %s second %s | |
|
2515 | In [2]: %parts A B | |
|
2516 | first A second B | |
|
2517 | In [3]: %parts A | |
|
2518 | Incorrect number of arguments: 2 expected. | |
|
2494 | 2519 | parts is an alias to: 'echo first %s second %s' |
|
2495 | 2520 | |
|
2496 | 2521 | Note that %l and %s are mutually exclusive. You can only use one or |
@@ -2503,11 +2528,11 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
2503 | 2528 | IPython for variable expansion. If you want to access a true shell |
|
2504 | 2529 | variable, an extra $ is necessary to prevent its expansion by IPython: |
|
2505 | 2530 | |
|
2506 |
In [6]: alias show echo |
|
|
2507 |
In [7]: PATH='A Python string' |
|
|
2508 |
In [8]: show $PATH |
|
|
2509 |
A Python string |
|
|
2510 |
In [9]: show $$PATH |
|
|
2531 | In [6]: alias show echo | |
|
2532 | In [7]: PATH='A Python string' | |
|
2533 | In [8]: show $PATH | |
|
2534 | A Python string | |
|
2535 | In [9]: show $$PATH | |
|
2511 | 2536 | /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... |
|
2512 | 2537 | |
|
2513 | 2538 | You can use the alias facility to acess all of $PATH. See the %rehash |
@@ -2822,7 +2847,7 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
2822 | 2847 | header = 'Directory history (kept in _dh)', |
|
2823 | 2848 | start=ini,stop=fin) |
|
2824 | 2849 | |
|
2825 | ||
|
2850 | @testdec.skip_doctest | |
|
2826 | 2851 | def magic_sc(self, parameter_s=''): |
|
2827 | 2852 | """Shell capture - execute a shell command and capture its output. |
|
2828 | 2853 | |
@@ -2866,31 +2891,33 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
2866 | 2891 | |
|
2867 | 2892 | For example: |
|
2868 | 2893 | |
|
2894 | # all-random | |
|
2895 | ||
|
2869 | 2896 | # Capture into variable a |
|
2870 |
In [ |
|
|
2897 | In [1]: sc a=ls *py | |
|
2871 | 2898 | |
|
2872 | 2899 | # a is a string with embedded newlines |
|
2873 |
In [ |
|
|
2874 |
Out[ |
|
|
2900 | In [2]: a | |
|
2901 | Out[2]: 'setup.py\\nwin32_manual_post_install.py' | |
|
2875 | 2902 | |
|
2876 | 2903 | # which can be seen as a list: |
|
2877 |
In [ |
|
|
2878 |
Out[ |
|
|
2904 | In [3]: a.l | |
|
2905 | Out[3]: ['setup.py', 'win32_manual_post_install.py'] | |
|
2879 | 2906 | |
|
2880 | 2907 | # or as a whitespace-separated string: |
|
2881 |
In [ |
|
|
2882 |
Out[ |
|
|
2908 | In [4]: a.s | |
|
2909 | Out[4]: 'setup.py win32_manual_post_install.py' | |
|
2883 | 2910 | |
|
2884 | 2911 | # a.s is useful to pass as a single command line: |
|
2885 |
In [ |
|
|
2912 | In [5]: !wc -l $a.s | |
|
2886 | 2913 | 146 setup.py |
|
2887 | 2914 | 130 win32_manual_post_install.py |
|
2888 | 2915 | 276 total |
|
2889 | 2916 | |
|
2890 | 2917 | # while the list form is useful to loop over: |
|
2891 |
In [ |
|
|
2892 |
|
|
|
2893 |
|
|
|
2918 | In [6]: for f in a.l: | |
|
2919 | ...: !wc -l $f | |
|
2920 | ...: | |
|
2894 | 2921 | 146 setup.py |
|
2895 | 2922 | 130 win32_manual_post_install.py |
|
2896 | 2923 | |
@@ -2898,13 +2925,13 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
2898 | 2925 | the sense that you can equally invoke the .s attribute on them to |
|
2899 | 2926 | automatically get a whitespace-separated string from their contents: |
|
2900 | 2927 | |
|
2901 |
In [ |
|
|
2928 | In [7]: sc -l b=ls *py | |
|
2902 | 2929 | |
|
2903 |
In [ |
|
|
2904 |
Out[ |
|
|
2930 | In [8]: b | |
|
2931 | Out[8]: ['setup.py', 'win32_manual_post_install.py'] | |
|
2905 | 2932 | |
|
2906 |
In [ |
|
|
2907 |
Out[ |
|
|
2933 | In [9]: b.s | |
|
2934 | Out[9]: 'setup.py win32_manual_post_install.py' | |
|
2908 | 2935 | |
|
2909 | 2936 | In summary, both the lists and strings used for ouptut capture have |
|
2910 | 2937 | the following special attributes: |
@@ -3273,6 +3300,7 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
3273 | 3300 | save_dstore('rc_separate_out',rc.separate_out) |
|
3274 | 3301 | save_dstore('rc_separate_out2',rc.separate_out2) |
|
3275 | 3302 | save_dstore('rc_prompts_pad_left',rc.prompts_pad_left) |
|
3303 | save_dstore('rc_separate_in',rc.separate_in) | |
|
3276 | 3304 | |
|
3277 | 3305 | if mode == False: |
|
3278 | 3306 | # turn on |
@@ -3282,6 +3310,8 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
3282 | 3310 | oc.prompt2.p_template = '... ' |
|
3283 | 3311 | oc.prompt_out.p_template = '' |
|
3284 | 3312 | |
|
3313 | # Prompt separators like plain python | |
|
3314 | oc.input_sep = oc.prompt1.sep = '' | |
|
3285 | 3315 | oc.output_sep = '' |
|
3286 | 3316 | oc.output_sep2 = '' |
|
3287 | 3317 | |
@@ -3300,6 +3330,8 b' Defaulting color scheme to \'NoColor\'"""' | |||
|
3300 | 3330 | oc.prompt2.p_template = rc.prompt_in2 |
|
3301 | 3331 | oc.prompt_out.p_template = rc.prompt_out |
|
3302 | 3332 | |
|
3333 | oc.input_sep = oc.prompt1.sep = dstore.rc_separate_in | |
|
3334 | ||
|
3303 | 3335 | oc.output_sep = dstore.rc_separate_out |
|
3304 | 3336 | oc.output_sep2 = dstore.rc_separate_out2 |
|
3305 | 3337 |
@@ -24,16 +24,17 b" __all__ = ['Inspector','InspectColors']" | |||
|
24 | 24 | |
|
25 | 25 | # stdlib modules |
|
26 | 26 | import __builtin__ |
|
27 | import StringIO | |
|
27 | 28 | import inspect |
|
28 | 29 | import linecache |
|
29 | import string | |
|
30 | import StringIO | |
|
31 | import types | |
|
32 | 30 | import os |
|
31 | import string | |
|
33 | 32 | import sys |
|
33 | import types | |
|
34 | ||
|
34 | 35 | # IPython's own |
|
35 | 36 | from IPython import PyColorize |
|
36 |
from IPython.genutils import page,indent,Term |
|
|
37 | from IPython.genutils import page,indent,Term | |
|
37 | 38 | from IPython.Itpl import itpl |
|
38 | 39 | from IPython.wildcard import list_namespace |
|
39 | 40 | from IPython.ColorANSI import * |
@@ -136,6 +137,7 b' def getdoc(obj):' | |||
|
136 | 137 | ds = '%s\n%s' % (ds,ds2) |
|
137 | 138 | return ds |
|
138 | 139 | |
|
140 | ||
|
139 | 141 | def getsource(obj,is_binary=False): |
|
140 | 142 | """Wrapper around inspect.getsource. |
|
141 | 143 | |
@@ -162,26 +164,7 b' def getsource(obj,is_binary=False):' | |||
|
162 | 164 | src = inspect.getsource(obj.__class__) |
|
163 | 165 | return src |
|
164 | 166 | |
|
165 | #**************************************************************************** | |
|
166 | # Class definitions | |
|
167 | ||
|
168 | class myStringIO(StringIO.StringIO): | |
|
169 | """Adds a writeln method to normal StringIO.""" | |
|
170 | def writeln(self,*arg,**kw): | |
|
171 | """Does a write() and then a write('\n')""" | |
|
172 | self.write(*arg,**kw) | |
|
173 | self.write('\n') | |
|
174 | ||
|
175 | class Inspector: | |
|
176 | def __init__(self,color_table,code_color_table,scheme, | |
|
177 | str_detail_level=0): | |
|
178 | self.color_table = color_table | |
|
179 | self.parser = PyColorize.Parser(code_color_table,out='str') | |
|
180 | self.format = self.parser.format | |
|
181 | self.str_detail_level = str_detail_level | |
|
182 | self.set_active_scheme(scheme) | |
|
183 | ||
|
184 | def __getargspec(self,obj): | |
|
167 | def getargspec(obj): | |
|
185 | 168 |
|
|
186 | 169 | |
|
187 | 170 |
|
@@ -201,6 +184,26 b' class Inspector:' | |||
|
201 | 184 |
|
|
202 | 185 |
|
|
203 | 186 | |
|
187 | #**************************************************************************** | |
|
188 | # Class definitions | |
|
189 | ||
|
190 | class myStringIO(StringIO.StringIO): | |
|
191 | """Adds a writeln method to normal StringIO.""" | |
|
192 | def writeln(self,*arg,**kw): | |
|
193 | """Does a write() and then a write('\n')""" | |
|
194 | self.write(*arg,**kw) | |
|
195 | self.write('\n') | |
|
196 | ||
|
197 | ||
|
198 | class Inspector: | |
|
199 | def __init__(self,color_table,code_color_table,scheme, | |
|
200 | str_detail_level=0): | |
|
201 | self.color_table = color_table | |
|
202 | self.parser = PyColorize.Parser(code_color_table,out='str') | |
|
203 | self.format = self.parser.format | |
|
204 | self.str_detail_level = str_detail_level | |
|
205 | self.set_active_scheme(scheme) | |
|
206 | ||
|
204 | 207 | def __getdef(self,obj,oname=''): |
|
205 | 208 | """Return the definition header for any callable object. |
|
206 | 209 | |
@@ -208,7 +211,7 b' class Inspector:' | |||
|
208 | 211 | exception is suppressed.""" |
|
209 | 212 | |
|
210 | 213 | try: |
|
211 |
return oname + inspect.formatargspec(* |
|
|
214 | return oname + inspect.formatargspec(*getargspec(obj)) | |
|
212 | 215 | except: |
|
213 | 216 | return None |
|
214 | 217 |
@@ -46,13 +46,6 b' from IPython.ipmaker import make_IPython' | |||
|
46 | 46 | from IPython.Magic import Magic |
|
47 | 47 | from IPython.ipstruct import Struct |
|
48 | 48 | |
|
49 | try: # Python 2.3 compatibility | |
|
50 | set | |
|
51 | except NameError: | |
|
52 | import sets | |
|
53 | set = sets.Set | |
|
54 | ||
|
55 | ||
|
56 | 49 | # Globals |
|
57 | 50 | # global flag to pass around information about Ctrl-C without exceptions |
|
58 | 51 | KBINT = False |
@@ -66,6 +59,9 b' MAIN_THREAD_ID = thread.get_ident()' | |||
|
66 | 59 | # Tag when runcode() is active, for exception handling |
|
67 | 60 | CODE_RUN = None |
|
68 | 61 | |
|
62 | # Default timeout for waiting for multithreaded shells (in seconds) | |
|
63 | GUI_TIMEOUT = 10 | |
|
64 | ||
|
69 | 65 | #----------------------------------------------------------------------------- |
|
70 | 66 | # This class is trivial now, but I want to have it in to publish a clean |
|
71 | 67 | # interface. Later when the internals are reorganized, code that uses this |
@@ -359,12 +355,15 b' class MTInteractiveShell(InteractiveShell):' | |||
|
359 | 355 | isthreaded = True |
|
360 | 356 | |
|
361 | 357 | def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), |
|
362 |
user_ns=None,user_global_ns=None,banner2='', |
|
|
358 | user_ns=None,user_global_ns=None,banner2='', | |
|
359 | gui_timeout=GUI_TIMEOUT,**kw): | |
|
363 | 360 | """Similar to the normal InteractiveShell, but with threading control""" |
|
364 | 361 | |
|
365 | 362 | InteractiveShell.__init__(self,name,usage,rc,user_ns, |
|
366 | 363 | user_global_ns,banner2) |
|
367 | 364 | |
|
365 | # Timeout we wait for GUI thread | |
|
366 | self.gui_timeout = gui_timeout | |
|
368 | 367 | |
|
369 | 368 | # A queue to hold the code to be executed. |
|
370 | 369 | self.code_queue = Queue.Queue() |
@@ -408,11 +407,12 b' class MTInteractiveShell(InteractiveShell):' | |||
|
408 | 407 | # Case 2 |
|
409 | 408 | return True |
|
410 | 409 | |
|
411 |
# shortcut - if we are in worker thread, or the worker thread is not |
|
|
412 |
# execute directly (to allow recursion and prevent deadlock if |
|
|
413 | # in IPython construction) | |
|
410 | # shortcut - if we are in worker thread, or the worker thread is not | |
|
411 | # running, execute directly (to allow recursion and prevent deadlock if | |
|
412 | # code is run early in IPython construction) | |
|
414 | 413 | |
|
415 |
if (self.worker_ident is None |
|
|
414 | if (self.worker_ident is None | |
|
415 | or self.worker_ident == thread.get_ident() ): | |
|
416 | 416 | InteractiveShell.runcode(self,code) |
|
417 | 417 | return |
|
418 | 418 | |
@@ -423,7 +423,7 b' class MTInteractiveShell(InteractiveShell):' | |||
|
423 | 423 | |
|
424 | 424 | self.code_queue.put((code,completed_ev, received_ev)) |
|
425 | 425 | # first make sure the message was received, with timeout |
|
426 |
received_ev.wait( |
|
|
426 | received_ev.wait(self.gui_timeout) | |
|
427 | 427 | if not received_ev.isSet(): |
|
428 | 428 | # the mainloop is dead, start executing code directly |
|
429 | 429 | print "Warning: Timeout for mainloop thread exceeded" |
@@ -39,8 +39,8 b' $Id: __init__.py 2399 2007-05-26 10:23:10Z vivainio $"""' | |||
|
39 | 39 | # Enforce proper version requirements |
|
40 | 40 | import sys |
|
41 | 41 | |
|
42 |
if sys.version[0:3] < '2. |
|
|
43 |
raise ImportError('Python Version 2. |
|
|
42 | if sys.version[0:3] < '2.4': | |
|
43 | raise ImportError('Python Version 2.4 or above is required for IPython.') | |
|
44 | 44 | |
|
45 | 45 | # Make it easy to import extensions - they are always directly on pythonpath. |
|
46 | 46 | # Therefore, non-IPython modules can be added to Extensions directory |
@@ -54,6 +54,7 b" __all__ = ['ipapi','generics','ipstruct','Release','Shell']" | |||
|
54 | 54 | # access to them via IPython.<name> |
|
55 | 55 | glob,loc = globals(),locals() |
|
56 | 56 | for name in __all__: |
|
57 | #print 'Importing: ',name # dbg | |
|
57 | 58 | __import__(name,glob,loc,[]) |
|
58 | 59 | |
|
59 | 60 | import Shell |
@@ -108,13 +108,6 b' class Completer:' | |||
|
108 | 108 | readline.set_completer(Completer(my_namespace).complete) |
|
109 | 109 | """ |
|
110 | 110 | |
|
111 | # some minimal strict typechecks. For some core data structures, I | |
|
112 | # want actual basic python types, not just anything that looks like | |
|
113 | # one. This is especially true for namespaces. | |
|
114 | for ns in (namespace,global_namespace): | |
|
115 | if ns is not None and type(ns) != types.DictType: | |
|
116 | raise TypeError,'namespace must be a dictionary' | |
|
117 | ||
|
118 | 111 | # Don't bind to namespace quite yet, but flag whether the user wants a |
|
119 | 112 | # specific namespace or to use __main__.__dict__. This will allow us |
|
120 | 113 | # to bind to __main__.__dict__ at completion time, not now. |
@@ -4,6 +4,7 b' A module to change reload() so that it acts recursively.' | |||
|
4 | 4 | To enable it type: |
|
5 | 5 | >>> import __builtin__, deep_reload |
|
6 | 6 | >>> __builtin__.reload = deep_reload.reload |
|
7 | ||
|
7 | 8 | You can then disable it with: |
|
8 | 9 | >>> __builtin__.reload = deep_reload.original_reload |
|
9 | 10 |
@@ -45,9 +45,9 b' from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase' | |||
|
45 | 45 | from twisted.internet.threads import blockingCallFromThread |
|
46 | 46 | from twisted.python.failure import Failure |
|
47 | 47 | |
|
48 |
#----------------------------------------------------------------------------- |
|
|
48 | #----------------------------------------------------------------------------- | |
|
49 | 49 | # Classes to implement the Cocoa frontend |
|
50 |
#----------------------------------------------------------------------------- |
|
|
50 | #----------------------------------------------------------------------------- | |
|
51 | 51 | |
|
52 | 52 | # TODO: |
|
53 | 53 | # 1. use MultiEngineClient and out-of-process engine rather than |
@@ -61,39 +61,92 b' class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):' | |||
|
61 | 61 | """wrapped_execute""" |
|
62 | 62 | try: |
|
63 | 63 | p = NSAutoreleasePool.alloc().init() |
|
64 | result = self.shell.execute(lines) | |
|
65 | except Exception,e: | |
|
66 | # This gives the following: | |
|
67 | # et=exception class | |
|
68 | # ev=exception class instance | |
|
69 | # tb=traceback object | |
|
70 | et,ev,tb = sys.exc_info() | |
|
71 | # This call adds attributes to the exception value | |
|
72 | et,ev,tb = self.shell.formatTraceback(et,ev,tb,msg) | |
|
73 | # Add another attribute | |
|
74 | ||
|
75 | # Create a new exception with the new attributes | |
|
76 | e = et(ev._ipython_traceback_text) | |
|
77 | e._ipython_engine_info = msg | |
|
78 | ||
|
79 | # Re-raise | |
|
80 | raise e | |
|
64 | result = super(AutoreleasePoolWrappedThreadedEngineService, | |
|
65 | self).wrapped_execute(msg, lines) | |
|
81 | 66 | finally: |
|
82 | 67 | p.drain() |
|
83 | 68 | |
|
84 | 69 | return result |
|
85 | 70 | |
|
86 | def execute(self, lines): | |
|
87 | # Only import this if we are going to use this class | |
|
88 | from twisted.internet import threads | |
|
89 | 71 | |
|
90 | msg = {'engineid':self.id, | |
|
91 | 'method':'execute', | |
|
92 | 'args':[lines]} | |
|
93 | 72 | |
|
94 | d = threads.deferToThread(self.wrapped_execute, msg, lines) | |
|
95 | d.addCallback(self.addIDToResult) | |
|
96 | return d | |
|
73 | class Cell(NSObject): | |
|
74 | """ | |
|
75 | Representation of the prompts, input and output of a cell in the | |
|
76 | frontend | |
|
77 | """ | |
|
78 | ||
|
79 | blockNumber = objc.ivar().unsigned_long() | |
|
80 | blockID = objc.ivar() | |
|
81 | inputBlock = objc.ivar() | |
|
82 | output = objc.ivar() | |
|
83 | ||
|
84 | ||
|
85 | ||
|
86 | class CellBlock(object): | |
|
87 | """ | |
|
88 | Storage for information about text ranges relating to a single cell | |
|
89 | """ | |
|
90 | ||
|
91 | ||
|
92 | def __init__(self, inputPromptRange, inputRange=None, outputPromptRange=None, | |
|
93 | outputRange=None): | |
|
94 | super(CellBlock, self).__init__() | |
|
95 | self.inputPromptRange = inputPromptRange | |
|
96 | self.inputRange = inputRange | |
|
97 | self.outputPromptRange = outputPromptRange | |
|
98 | self.outputRange = outputRange | |
|
99 | ||
|
100 | def update_ranges_for_insertion(self, text, textRange): | |
|
101 | """Update ranges for text insertion at textRange""" | |
|
102 | ||
|
103 | for r in [self.inputPromptRange,self.inputRange, | |
|
104 | self.outputPromptRange, self.outputRange]: | |
|
105 | if(r == None): | |
|
106 | continue | |
|
107 | intersection = NSIntersectionRange(r,textRange) | |
|
108 | if(intersection.length == 0): #ranges don't intersect | |
|
109 | if r.location >= textRange.location: | |
|
110 | r.location += len(text) | |
|
111 | else: #ranges intersect | |
|
112 | if(r.location > textRange.location): | |
|
113 | offset = len(text) - intersection.length | |
|
114 | r.length -= offset | |
|
115 | r.location += offset | |
|
116 | elif(r.location == textRange.location): | |
|
117 | r.length += len(text) - intersection.length | |
|
118 | else: | |
|
119 | r.length -= intersection.length | |
|
120 | ||
|
121 | ||
|
122 | def update_ranges_for_deletion(self, textRange): | |
|
123 | """Update ranges for text deletion at textRange""" | |
|
124 | ||
|
125 | for r in [self.inputPromptRange,self.inputRange, | |
|
126 | self.outputPromptRange, self.outputRange]: | |
|
127 | if(r==None): | |
|
128 | continue | |
|
129 | intersection = NSIntersectionRange(r, textRange) | |
|
130 | if(intersection.length == 0): #ranges don't intersect | |
|
131 | if r.location >= textRange.location: | |
|
132 | r.location -= textRange.length | |
|
133 | else: #ranges intersect | |
|
134 | if(r.location > textRange.location): | |
|
135 | offset = intersection.length | |
|
136 | r.length -= offset | |
|
137 | r.location += offset | |
|
138 | elif(r.location == textRange.location): | |
|
139 | r.length += intersection.length | |
|
140 | else: | |
|
141 | r.length -= intersection.length | |
|
142 | ||
|
143 | def __repr__(self): | |
|
144 | return 'CellBlock('+ str((self.inputPromptRange, | |
|
145 | self.inputRange, | |
|
146 | self.outputPromptRange, | |
|
147 | self.outputRange)) + ')' | |
|
148 | ||
|
149 | ||
|
97 | 150 | |
|
98 | 151 | |
|
99 | 152 | class IPythonCocoaController(NSObject, AsyncFrontEndBase): |
@@ -120,7 +173,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
120 | 173 | self.tabSpaces = 4 |
|
121 | 174 | self.tabUsesSpaces = True |
|
122 | 175 | self.currentBlockID = self.next_block_ID() |
|
123 |
self.blockRanges = {} # blockID=> |
|
|
176 | self.blockRanges = {} # blockID=>CellBlock | |
|
124 | 177 | |
|
125 | 178 | |
|
126 | 179 | def awakeFromNib(self): |
@@ -148,6 +201,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
148 | 201 | self.verticalRulerView = r |
|
149 | 202 | self.verticalRulerView.setClientView_(self.textView) |
|
150 | 203 | self._start_cli_banner() |
|
204 | self.start_new_block() | |
|
151 | 205 | |
|
152 | 206 | |
|
153 | 207 | def appWillTerminate_(self, notification): |
@@ -239,14 +293,16 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
239 | 293 | |
|
240 | 294 | |
|
241 | 295 | def update_cell_prompt(self, result, blockID=None): |
|
296 | print self.blockRanges | |
|
242 | 297 | if(isinstance(result, Failure)): |
|
243 |
|
|
|
244 | textRange=NSMakeRange(self.blockRanges[blockID].location,0), | |
|
245 | scrollToVisible=False | |
|
246 | ) | |
|
298 | prompt = self.input_prompt() | |
|
299 | ||
|
247 | 300 | else: |
|
248 |
|
|
|
249 | textRange=NSMakeRange(self.blockRanges[blockID].location,0), | |
|
301 | prompt = self.input_prompt(number=result['number']) | |
|
302 | ||
|
303 | r = self.blockRanges[blockID].inputPromptRange | |
|
304 | self.insert_text(prompt, | |
|
305 | textRange=r, | |
|
250 | 306 | scrollToVisible=False |
|
251 | 307 | ) |
|
252 | 308 | |
@@ -255,7 +311,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
255 | 311 | |
|
256 | 312 | def render_result(self, result): |
|
257 | 313 | blockID = result['blockID'] |
|
258 | inputRange = self.blockRanges[blockID] | |
|
314 | inputRange = self.blockRanges[blockID].inputRange | |
|
259 | 315 | del self.blockRanges[blockID] |
|
260 | 316 | |
|
261 | 317 | #print inputRange,self.current_block_range() |
@@ -269,11 +325,17 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
269 | 325 | |
|
270 | 326 | |
|
271 | 327 | def render_error(self, failure): |
|
328 | print failure | |
|
329 | blockID = failure.blockID | |
|
330 | inputRange = self.blockRanges[blockID].inputRange | |
|
272 | 331 | self.insert_text('\n' + |
|
273 | 332 | self.output_prompt() + |
|
274 | 333 | '\n' + |
|
275 | 334 | failure.getErrorMessage() + |
|
276 |
'\n\n' |
|
|
335 | '\n\n', | |
|
336 | textRange=NSMakeRange(inputRange.location + | |
|
337 | inputRange.length, | |
|
338 | 0)) | |
|
277 | 339 | self.start_new_block() |
|
278 | 340 | return failure |
|
279 | 341 | |
@@ -291,6 +353,9 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
291 | 353 | """""" |
|
292 | 354 | |
|
293 | 355 | self.currentBlockID = self.next_block_ID() |
|
356 | self.blockRanges[self.currentBlockID] = self.new_cell_block() | |
|
357 | self.insert_text(self.input_prompt(), | |
|
358 | textRange=self.current_block_range().inputPromptRange) | |
|
294 | 359 | |
|
295 | 360 | |
|
296 | 361 | |
@@ -298,15 +363,23 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
298 | 363 | |
|
299 | 364 | return uuid.uuid4() |
|
300 | 365 | |
|
366 | def new_cell_block(self): | |
|
367 | """A new CellBlock at the end of self.textView.textStorage()""" | |
|
368 | ||
|
369 | return CellBlock(NSMakeRange(self.textView.textStorage().length(), | |
|
370 | 0), #len(self.input_prompt())), | |
|
371 | NSMakeRange(self.textView.textStorage().length(),# + len(self.input_prompt()), | |
|
372 | 0)) | |
|
373 | ||
|
374 | ||
|
301 | 375 | def current_block_range(self): |
|
302 | 376 | return self.blockRanges.get(self.currentBlockID, |
|
303 |
|
|
|
304 | 0)) | |
|
377 | self.new_cell_block()) | |
|
305 | 378 | |
|
306 | 379 | def current_block(self): |
|
307 | 380 | """The current block's text""" |
|
308 | 381 | |
|
309 | return self.text_for_range(self.current_block_range()) | |
|
382 | return self.text_for_range(self.current_block_range().inputRange) | |
|
310 | 383 | |
|
311 | 384 | def text_for_range(self, textRange): |
|
312 | 385 | """text_for_range""" |
@@ -315,7 +388,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
315 | 388 | return ts.string().substringWithRange_(textRange) |
|
316 | 389 | |
|
317 | 390 | def current_line(self): |
|
318 | block = self.text_for_range(self.current_block_range()) | |
|
391 | block = self.text_for_range(self.current_block_range().inputRange) | |
|
319 | 392 | block = block.split('\n') |
|
320 | 393 | return block[-1] |
|
321 | 394 | |
@@ -324,38 +397,28 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
324 | 397 | """Insert text into textView at textRange, updating blockRanges |
|
325 | 398 | as necessary |
|
326 | 399 | """ |
|
327 | ||
|
328 | 400 | if(textRange == None): |
|
329 | 401 | #range for end of text |
|
330 | 402 | textRange = NSMakeRange(self.textView.textStorage().length(), 0) |
|
331 | 403 | |
|
332 | for r in self.blockRanges.itervalues(): | |
|
333 | intersection = NSIntersectionRange(r,textRange) | |
|
334 | if(intersection.length == 0): #ranges don't intersect | |
|
335 | if r.location >= textRange.location: | |
|
336 | r.location += len(string) | |
|
337 | else: #ranges intersect | |
|
338 | if(r.location <= textRange.location): | |
|
339 | assert(intersection.length == textRange.length) | |
|
340 | r.length += textRange.length | |
|
341 | else: | |
|
342 | r.location += intersection.length | |
|
343 | 404 | |
|
344 | 405 | self.textView.replaceCharactersInRange_withString_( |
|
345 | 406 | textRange, string) |
|
346 | self.textView.setSelectedRange_( | |
|
347 | NSMakeRange(textRange.location+len(string), 0)) | |
|
407 | ||
|
408 | for r in self.blockRanges.itervalues(): | |
|
409 | r.update_ranges_for_insertion(string, textRange) | |
|
410 | ||
|
411 | self.textView.setSelectedRange_(textRange) | |
|
348 | 412 | if(scrollToVisible): |
|
349 | 413 | self.textView.scrollRangeToVisible_(textRange) |
|
350 | 414 |
|
|
351 | 415 | |
|
352 | 416 | |
|
353 | ||
|
354 | 417 | def replace_current_block_with_string(self, textView, string): |
|
355 | 418 | textView.replaceCharactersInRange_withString_( |
|
356 |
|
|
|
419 | self.current_block_range().inputRange, | |
|
357 | 420 |
|
|
358 | self.current_block_range().length = len(string) | |
|
421 | self.current_block_range().inputRange.length = len(string) | |
|
359 | 422 | r = NSMakeRange(textView.textStorage().length(), 0) |
|
360 | 423 | textView.scrollRangeToVisible_(r) |
|
361 | 424 | textView.setSelectedRange_(r) |
@@ -424,26 +487,18 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
424 | 487 | |
|
425 | 488 | elif(selector == 'moveToBeginningOfParagraph:'): |
|
426 | 489 | textView.setSelectedRange_(NSMakeRange( |
|
427 |
|
|
|
490 | self.current_block_range().inputRange.location, | |
|
428 | 491 |
|
|
429 | 492 | return True |
|
430 | 493 | elif(selector == 'moveToEndOfParagraph:'): |
|
431 | 494 | textView.setSelectedRange_(NSMakeRange( |
|
432 |
|
|
|
433 |
|
|
|
495 | self.current_block_range().inputRange.location + \ | |
|
496 | self.current_block_range().inputRange.length, 0)) | |
|
434 | 497 | return True |
|
435 | 498 | elif(selector == 'deleteToEndOfParagraph:'): |
|
436 | 499 | if(textView.selectedRange().location <= \ |
|
437 | 500 | self.current_block_range().location): |
|
438 | # Intersect the selected range with the current line range | |
|
439 | if(self.current_block_range().length < 0): | |
|
440 | self.blockRanges[self.currentBlockID].length = 0 | |
|
441 | ||
|
442 | r = NSIntersectionRange(textView.rangesForUserTextChange()[0], | |
|
443 | self.current_block_range()) | |
|
444 | ||
|
445 | if(r.length > 0): #no intersection | |
|
446 | textView.setSelectedRange_(r) | |
|
501 | raise NotImplemented() | |
|
447 | 502 | |
|
448 | 503 | return False # don't actually handle the delete |
|
449 | 504 | |
@@ -457,10 +512,15 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
457 | 512 | elif(selector == 'deleteBackward:'): |
|
458 | 513 | #if we're at the beginning of the current block, ignore |
|
459 | 514 | if(textView.selectedRange().location == \ |
|
460 | self.current_block_range().location): | |
|
515 | self.current_block_range().inputRange.location): | |
|
461 | 516 | return True |
|
462 | 517 | else: |
|
463 | self.current_block_range().length-=1 | |
|
518 | for r in self.blockRanges.itervalues(): | |
|
519 | deleteRange = textView.selectedRange | |
|
520 | if(deleteRange.length == 0): | |
|
521 | deleteRange.location -= 1 | |
|
522 | deleteRange.length = 1 | |
|
523 | r.update_ranges_for_deletion(deleteRange) | |
|
464 | 524 | return False |
|
465 | 525 | return False |
|
466 | 526 | |
@@ -479,15 +539,10 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):' | |||
|
479 | 539 | for r,s in zip(ranges, replacementStrings): |
|
480 | 540 | r = r.rangeValue() |
|
481 | 541 | if(textView.textStorage().length() > 0 and |
|
482 |
|
|
|
542 | r.location < self.current_block_range().inputRange.location): | |
|
483 | 543 | self.insert_text(s) |
|
484 | 544 | allow = False |
|
485 | 545 |
|
|
486 | ||
|
487 | self.blockRanges.setdefault(self.currentBlockID, | |
|
488 | self.current_block_range()).length +=\ | |
|
489 | len(s) | |
|
490 | ||
|
491 | 546 | return allow |
|
492 | 547 | |
|
493 | 548 | def textView_completions_forPartialWordRange_indexOfSelectedItem_(self, |
This diff has been collapsed as it changes many lines, (1033 lines changed) Show them Hide them | |||
@@ -37,12 +37,12 b'' | |||
|
37 | 37 | <string key="NSKeyEquiv" id="255189770"/> |
|
38 | 38 | <int key="NSKeyEquivModMask">1048576</int> |
|
39 | 39 | <int key="NSMnemonicLoc">2147483647</int> |
|
40 |
<object class="NSCustomResource" key="NSOnImage" id=" |
|
|
41 |
<string key="NSClassName" id=" |
|
|
40 | <object class="NSCustomResource" key="NSOnImage" id="271266416"> | |
|
41 | <string key="NSClassName" id="375865337">NSImage</string> | |
|
42 | 42 | <string key="NSResourceName">NSMenuCheckmark</string> |
|
43 | 43 | </object> |
|
44 |
<object class="NSCustomResource" key="NSMixedImage" id=" |
|
|
45 |
<reference key="NSClassName" ref=" |
|
|
44 | <object class="NSCustomResource" key="NSMixedImage" id="508123839"> | |
|
45 | <reference key="NSClassName" ref="375865337"/> | |
|
46 | 46 | <string key="NSResourceName">NSMenuMixedState</string> |
|
47 | 47 | </object> |
|
48 | 48 | <string key="NSAction">submenuAction:</string> |
@@ -55,8 +55,8 b'' | |||
|
55 | 55 | <string key="NSTitle">About IPython1Sandbox</string> |
|
56 | 56 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
57 | 57 | <int key="NSMnemonicLoc">2147483647</int> |
|
58 |
<reference key="NSOnImage" ref=" |
|
|
59 |
<reference key="NSMixedImage" ref=" |
|
|
58 | <reference key="NSOnImage" ref="271266416"/> | |
|
59 | <reference key="NSMixedImage" ref="508123839"/> | |
|
60 | 60 | </object> |
|
61 | 61 | <object class="NSMenuItem" id="304266470"> |
|
62 | 62 | <reference key="NSMenu" ref="110575045"/> |
@@ -66,8 +66,8 b'' | |||
|
66 | 66 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
67 | 67 | <int key="NSKeyEquivModMask">1048576</int> |
|
68 | 68 | <int key="NSMnemonicLoc">2147483647</int> |
|
69 |
<reference key="NSOnImage" ref=" |
|
|
70 |
<reference key="NSMixedImage" ref=" |
|
|
69 | <reference key="NSOnImage" ref="271266416"/> | |
|
70 | <reference key="NSMixedImage" ref="508123839"/> | |
|
71 | 71 | </object> |
|
72 | 72 | <object class="NSMenuItem" id="609285721"> |
|
73 | 73 | <reference key="NSMenu" ref="110575045"/> |
@@ -75,8 +75,8 b'' | |||
|
75 | 75 | <string key="NSKeyEquiv">,</string> |
|
76 | 76 | <int key="NSKeyEquivModMask">1048576</int> |
|
77 | 77 | <int key="NSMnemonicLoc">2147483647</int> |
|
78 |
<reference key="NSOnImage" ref=" |
|
|
79 |
<reference key="NSMixedImage" ref=" |
|
|
78 | <reference key="NSOnImage" ref="271266416"/> | |
|
79 | <reference key="NSMixedImage" ref="508123839"/> | |
|
80 | 80 | </object> |
|
81 | 81 | <object class="NSMenuItem" id="481834944"> |
|
82 | 82 | <reference key="NSMenu" ref="110575045"/> |
@@ -86,8 +86,8 b'' | |||
|
86 | 86 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
87 | 87 | <int key="NSKeyEquivModMask">1048576</int> |
|
88 | 88 | <int key="NSMnemonicLoc">2147483647</int> |
|
89 |
<reference key="NSOnImage" ref=" |
|
|
90 |
<reference key="NSMixedImage" ref=" |
|
|
89 | <reference key="NSOnImage" ref="271266416"/> | |
|
90 | <reference key="NSMixedImage" ref="508123839"/> | |
|
91 | 91 | </object> |
|
92 | 92 | <object class="NSMenuItem" id="1046388886"> |
|
93 | 93 | <reference key="NSMenu" ref="110575045"/> |
@@ -95,8 +95,8 b'' | |||
|
95 | 95 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
96 | 96 | <int key="NSKeyEquivModMask">1048576</int> |
|
97 | 97 | <int key="NSMnemonicLoc">2147483647</int> |
|
98 |
<reference key="NSOnImage" ref=" |
|
|
99 |
<reference key="NSMixedImage" ref=" |
|
|
98 | <reference key="NSOnImage" ref="271266416"/> | |
|
99 | <reference key="NSMixedImage" ref="508123839"/> | |
|
100 | 100 | <string key="NSAction">submenuAction:</string> |
|
101 | 101 | <object class="NSMenu" key="NSSubmenu" id="752062318"> |
|
102 | 102 | <reference key="NSTitle" ref="642338826"/> |
@@ -114,8 +114,8 b'' | |||
|
114 | 114 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
115 | 115 | <int key="NSKeyEquivModMask">1048576</int> |
|
116 | 116 | <int key="NSMnemonicLoc">2147483647</int> |
|
117 |
<reference key="NSOnImage" ref=" |
|
|
118 |
<reference key="NSMixedImage" ref=" |
|
|
117 | <reference key="NSOnImage" ref="271266416"/> | |
|
118 | <reference key="NSMixedImage" ref="508123839"/> | |
|
119 | 119 | </object> |
|
120 | 120 | <object class="NSMenuItem" id="755159360"> |
|
121 | 121 | <reference key="NSMenu" ref="110575045"/> |
@@ -123,8 +123,8 b'' | |||
|
123 | 123 | <string key="NSKeyEquiv" id="940330891">h</string> |
|
124 | 124 | <int key="NSKeyEquivModMask">1048576</int> |
|
125 | 125 | <int key="NSMnemonicLoc">2147483647</int> |
|
126 |
<reference key="NSOnImage" ref=" |
|
|
127 |
<reference key="NSMixedImage" ref=" |
|
|
126 | <reference key="NSOnImage" ref="271266416"/> | |
|
127 | <reference key="NSMixedImage" ref="508123839"/> | |
|
128 | 128 | </object> |
|
129 | 129 | <object class="NSMenuItem" id="342932134"> |
|
130 | 130 | <reference key="NSMenu" ref="110575045"/> |
@@ -132,8 +132,8 b'' | |||
|
132 | 132 | <reference key="NSKeyEquiv" ref="940330891"/> |
|
133 | 133 | <int key="NSKeyEquivModMask">1572864</int> |
|
134 | 134 | <int key="NSMnemonicLoc">2147483647</int> |
|
135 |
<reference key="NSOnImage" ref=" |
|
|
136 |
<reference key="NSMixedImage" ref=" |
|
|
135 | <reference key="NSOnImage" ref="271266416"/> | |
|
136 | <reference key="NSMixedImage" ref="508123839"/> | |
|
137 | 137 | </object> |
|
138 | 138 | <object class="NSMenuItem" id="908899353"> |
|
139 | 139 | <reference key="NSMenu" ref="110575045"/> |
@@ -141,8 +141,8 b'' | |||
|
141 | 141 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
142 | 142 | <int key="NSKeyEquivModMask">1048576</int> |
|
143 | 143 | <int key="NSMnemonicLoc">2147483647</int> |
|
144 |
<reference key="NSOnImage" ref=" |
|
|
145 |
<reference key="NSMixedImage" ref=" |
|
|
144 | <reference key="NSOnImage" ref="271266416"/> | |
|
145 | <reference key="NSMixedImage" ref="508123839"/> | |
|
146 | 146 | </object> |
|
147 | 147 | <object class="NSMenuItem" id="1056857174"> |
|
148 | 148 | <reference key="NSMenu" ref="110575045"/> |
@@ -152,8 +152,8 b'' | |||
|
152 | 152 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
153 | 153 | <int key="NSKeyEquivModMask">1048576</int> |
|
154 | 154 | <int key="NSMnemonicLoc">2147483647</int> |
|
155 |
<reference key="NSOnImage" ref=" |
|
|
156 |
<reference key="NSMixedImage" ref=" |
|
|
155 | <reference key="NSOnImage" ref="271266416"/> | |
|
156 | <reference key="NSMixedImage" ref="508123839"/> | |
|
157 | 157 | </object> |
|
158 | 158 | <object class="NSMenuItem" id="632727374"> |
|
159 | 159 | <reference key="NSMenu" ref="110575045"/> |
@@ -161,8 +161,8 b'' | |||
|
161 | 161 | <string key="NSKeyEquiv">q</string> |
|
162 | 162 | <int key="NSKeyEquivModMask">1048576</int> |
|
163 | 163 | <int key="NSMnemonicLoc">2147483647</int> |
|
164 |
<reference key="NSOnImage" ref=" |
|
|
165 |
<reference key="NSMixedImage" ref=" |
|
|
164 | <reference key="NSOnImage" ref="271266416"/> | |
|
165 | <reference key="NSMixedImage" ref="508123839"/> | |
|
166 | 166 | </object> |
|
167 | 167 | </object> |
|
168 | 168 | <string key="NSName">_NSAppleMenu</string> |
@@ -174,8 +174,8 b'' | |||
|
174 | 174 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
175 | 175 | <int key="NSKeyEquivModMask">1048576</int> |
|
176 | 176 | <int key="NSMnemonicLoc">2147483647</int> |
|
177 |
<reference key="NSOnImage" ref=" |
|
|
178 |
<reference key="NSMixedImage" ref=" |
|
|
177 | <reference key="NSOnImage" ref="271266416"/> | |
|
178 | <reference key="NSMixedImage" ref="508123839"/> | |
|
179 | 179 | <string key="NSAction">submenuAction:</string> |
|
180 | 180 | <object class="NSMenu" key="NSSubmenu" id="720053764"> |
|
181 | 181 | <reference key="NSTitle" ref="881404960"/> |
@@ -187,8 +187,8 b'' | |||
|
187 | 187 | <string key="NSKeyEquiv">n</string> |
|
188 | 188 | <int key="NSKeyEquivModMask">1048576</int> |
|
189 | 189 | <int key="NSMnemonicLoc">2147483647</int> |
|
190 |
<reference key="NSOnImage" ref=" |
|
|
191 |
<reference key="NSMixedImage" ref=" |
|
|
190 | <reference key="NSOnImage" ref="271266416"/> | |
|
191 | <reference key="NSMixedImage" ref="508123839"/> | |
|
192 | 192 | </object> |
|
193 | 193 | <object class="NSMenuItem" id="722745758"> |
|
194 | 194 | <reference key="NSMenu" ref="720053764"/> |
@@ -196,8 +196,8 b'' | |||
|
196 | 196 | <string key="NSKeyEquiv">o</string> |
|
197 | 197 | <int key="NSKeyEquivModMask">1048576</int> |
|
198 | 198 | <int key="NSMnemonicLoc">2147483647</int> |
|
199 |
<reference key="NSOnImage" ref=" |
|
|
200 |
<reference key="NSMixedImage" ref=" |
|
|
199 | <reference key="NSOnImage" ref="271266416"/> | |
|
200 | <reference key="NSMixedImage" ref="508123839"/> | |
|
201 | 201 | </object> |
|
202 | 202 | <object class="NSMenuItem" id="1025936716"> |
|
203 | 203 | <reference key="NSMenu" ref="720053764"/> |
@@ -205,8 +205,8 b'' | |||
|
205 | 205 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
206 | 206 | <int key="NSKeyEquivModMask">1048576</int> |
|
207 | 207 | <int key="NSMnemonicLoc">2147483647</int> |
|
208 |
<reference key="NSOnImage" ref=" |
|
|
209 |
<reference key="NSMixedImage" ref=" |
|
|
208 | <reference key="NSOnImage" ref="271266416"/> | |
|
209 | <reference key="NSMixedImage" ref="508123839"/> | |
|
210 | 210 | <string key="NSAction">submenuAction:</string> |
|
211 | 211 | <object class="NSMenu" key="NSSubmenu" id="1065607017"> |
|
212 | 212 | <reference key="NSTitle" ref="975517829"/> |
@@ -218,8 +218,8 b'' | |||
|
218 | 218 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
219 | 219 | <int key="NSKeyEquivModMask">1048576</int> |
|
220 | 220 | <int key="NSMnemonicLoc">2147483647</int> |
|
221 |
<reference key="NSOnImage" ref=" |
|
|
222 |
<reference key="NSMixedImage" ref=" |
|
|
221 | <reference key="NSOnImage" ref="271266416"/> | |
|
222 | <reference key="NSMixedImage" ref="508123839"/> | |
|
223 | 223 | </object> |
|
224 | 224 | </object> |
|
225 | 225 | <string key="NSName">_NSRecentDocumentsMenu</string> |
@@ -233,8 +233,8 b'' | |||
|
233 | 233 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
234 | 234 | <int key="NSKeyEquivModMask">1048576</int> |
|
235 | 235 | <int key="NSMnemonicLoc">2147483647</int> |
|
236 |
<reference key="NSOnImage" ref=" |
|
|
237 |
<reference key="NSMixedImage" ref=" |
|
|
236 | <reference key="NSOnImage" ref="271266416"/> | |
|
237 | <reference key="NSMixedImage" ref="508123839"/> | |
|
238 | 238 | </object> |
|
239 | 239 | <object class="NSMenuItem" id="776162233"> |
|
240 | 240 | <reference key="NSMenu" ref="720053764"/> |
@@ -242,8 +242,8 b'' | |||
|
242 | 242 | <string key="NSKeyEquiv">w</string> |
|
243 | 243 | <int key="NSKeyEquivModMask">1048576</int> |
|
244 | 244 | <int key="NSMnemonicLoc">2147483647</int> |
|
245 |
<reference key="NSOnImage" ref=" |
|
|
246 |
<reference key="NSMixedImage" ref=" |
|
|
245 | <reference key="NSOnImage" ref="271266416"/> | |
|
246 | <reference key="NSMixedImage" ref="508123839"/> | |
|
247 | 247 | </object> |
|
248 | 248 | <object class="NSMenuItem" id="1023925487"> |
|
249 | 249 | <reference key="NSMenu" ref="720053764"/> |
@@ -251,8 +251,8 b'' | |||
|
251 | 251 | <string key="NSKeyEquiv">s</string> |
|
252 | 252 | <int key="NSKeyEquivModMask">1048576</int> |
|
253 | 253 | <int key="NSMnemonicLoc">2147483647</int> |
|
254 |
<reference key="NSOnImage" ref=" |
|
|
255 |
<reference key="NSMixedImage" ref=" |
|
|
254 | <reference key="NSOnImage" ref="271266416"/> | |
|
255 | <reference key="NSMixedImage" ref="508123839"/> | |
|
256 | 256 | </object> |
|
257 | 257 | <object class="NSMenuItem" id="117038363"> |
|
258 | 258 | <reference key="NSMenu" ref="720053764"/> |
@@ -260,16 +260,16 b'' | |||
|
260 | 260 | <string key="NSKeyEquiv">S</string> |
|
261 | 261 | <int key="NSKeyEquivModMask">1179648</int> |
|
262 | 262 | <int key="NSMnemonicLoc">2147483647</int> |
|
263 |
<reference key="NSOnImage" ref=" |
|
|
264 |
<reference key="NSMixedImage" ref=" |
|
|
263 | <reference key="NSOnImage" ref="271266416"/> | |
|
264 | <reference key="NSMixedImage" ref="508123839"/> | |
|
265 | 265 | </object> |
|
266 | 266 | <object class="NSMenuItem" id="579971712"> |
|
267 | 267 | <reference key="NSMenu" ref="720053764"/> |
|
268 | 268 | <string key="NSTitle">Revert to Saved</string> |
|
269 | 269 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
270 | 270 | <int key="NSMnemonicLoc">2147483647</int> |
|
271 |
<reference key="NSOnImage" ref=" |
|
|
272 |
<reference key="NSMixedImage" ref=" |
|
|
271 | <reference key="NSOnImage" ref="271266416"/> | |
|
272 | <reference key="NSMixedImage" ref="508123839"/> | |
|
273 | 273 | </object> |
|
274 | 274 | <object class="NSMenuItem" id="1010469920"> |
|
275 | 275 | <reference key="NSMenu" ref="720053764"/> |
@@ -279,8 +279,8 b'' | |||
|
279 | 279 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
280 | 280 | <int key="NSKeyEquivModMask">1048576</int> |
|
281 | 281 | <int key="NSMnemonicLoc">2147483647</int> |
|
282 |
<reference key="NSOnImage" ref=" |
|
|
283 |
<reference key="NSMixedImage" ref=" |
|
|
282 | <reference key="NSOnImage" ref="271266416"/> | |
|
283 | <reference key="NSMixedImage" ref="508123839"/> | |
|
284 | 284 | </object> |
|
285 | 285 | <object class="NSMenuItem" id="294629803"> |
|
286 | 286 | <reference key="NSMenu" ref="720053764"/> |
@@ -288,8 +288,8 b'' | |||
|
288 | 288 | <string key="NSKeyEquiv">P</string> |
|
289 | 289 | <int key="NSKeyEquivModMask">1179648</int> |
|
290 | 290 | <int key="NSMnemonicLoc">2147483647</int> |
|
291 |
<reference key="NSOnImage" ref=" |
|
|
292 |
<reference key="NSMixedImage" ref=" |
|
|
291 | <reference key="NSOnImage" ref="271266416"/> | |
|
292 | <reference key="NSMixedImage" ref="508123839"/> | |
|
293 | 293 | <reference key="NSToolTip" ref="255189770"/> |
|
294 | 294 | </object> |
|
295 | 295 | <object class="NSMenuItem" id="49223823"> |
@@ -298,8 +298,8 b'' | |||
|
298 | 298 | <string key="NSKeyEquiv">p</string> |
|
299 | 299 | <int key="NSKeyEquivModMask">1048576</int> |
|
300 | 300 | <int key="NSMnemonicLoc">2147483647</int> |
|
301 |
<reference key="NSOnImage" ref=" |
|
|
302 |
<reference key="NSMixedImage" ref=" |
|
|
301 | <reference key="NSOnImage" ref="271266416"/> | |
|
302 | <reference key="NSMixedImage" ref="508123839"/> | |
|
303 | 303 | </object> |
|
304 | 304 | </object> |
|
305 | 305 | </object> |
@@ -310,8 +310,8 b'' | |||
|
310 | 310 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
311 | 311 | <int key="NSKeyEquivModMask">1048576</int> |
|
312 | 312 | <int key="NSMnemonicLoc">2147483647</int> |
|
313 |
<reference key="NSOnImage" ref=" |
|
|
314 |
<reference key="NSMixedImage" ref=" |
|
|
313 | <reference key="NSOnImage" ref="271266416"/> | |
|
314 | <reference key="NSMixedImage" ref="508123839"/> | |
|
315 | 315 | <string key="NSAction">submenuAction:</string> |
|
316 | 316 | <object class="NSMenu" key="NSSubmenu" id="789758025"> |
|
317 | 317 | <reference key="NSTitle" ref="1037326483"/> |
@@ -323,8 +323,8 b'' | |||
|
323 | 323 | <string key="NSKeyEquiv">z</string> |
|
324 | 324 | <int key="NSKeyEquivModMask">1048576</int> |
|
325 | 325 | <int key="NSMnemonicLoc">2147483647</int> |
|
326 |
<reference key="NSOnImage" ref=" |
|
|
327 |
<reference key="NSMixedImage" ref=" |
|
|
326 | <reference key="NSOnImage" ref="271266416"/> | |
|
327 | <reference key="NSMixedImage" ref="508123839"/> | |
|
328 | 328 | </object> |
|
329 | 329 | <object class="NSMenuItem" id="790794224"> |
|
330 | 330 | <reference key="NSMenu" ref="789758025"/> |
@@ -332,8 +332,8 b'' | |||
|
332 | 332 | <string key="NSKeyEquiv">Z</string> |
|
333 | 333 | <int key="NSKeyEquivModMask">1179648</int> |
|
334 | 334 | <int key="NSMnemonicLoc">2147483647</int> |
|
335 |
<reference key="NSOnImage" ref=" |
|
|
336 |
<reference key="NSMixedImage" ref=" |
|
|
335 | <reference key="NSOnImage" ref="271266416"/> | |
|
336 | <reference key="NSMixedImage" ref="508123839"/> | |
|
337 | 337 | </object> |
|
338 | 338 | <object class="NSMenuItem" id="1040322652"> |
|
339 | 339 | <reference key="NSMenu" ref="789758025"/> |
@@ -343,8 +343,8 b'' | |||
|
343 | 343 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
344 | 344 | <int key="NSKeyEquivModMask">1048576</int> |
|
345 | 345 | <int key="NSMnemonicLoc">2147483647</int> |
|
346 |
<reference key="NSOnImage" ref=" |
|
|
347 |
<reference key="NSMixedImage" ref=" |
|
|
346 | <reference key="NSOnImage" ref="271266416"/> | |
|
347 | <reference key="NSMixedImage" ref="508123839"/> | |
|
348 | 348 | </object> |
|
349 | 349 | <object class="NSMenuItem" id="296257095"> |
|
350 | 350 | <reference key="NSMenu" ref="789758025"/> |
@@ -352,8 +352,8 b'' | |||
|
352 | 352 | <string key="NSKeyEquiv">x</string> |
|
353 | 353 | <int key="NSKeyEquivModMask">1048576</int> |
|
354 | 354 | <int key="NSMnemonicLoc">2147483647</int> |
|
355 |
<reference key="NSOnImage" ref=" |
|
|
356 |
<reference key="NSMixedImage" ref=" |
|
|
355 | <reference key="NSOnImage" ref="271266416"/> | |
|
356 | <reference key="NSMixedImage" ref="508123839"/> | |
|
357 | 357 | </object> |
|
358 | 358 | <object class="NSMenuItem" id="860595796"> |
|
359 | 359 | <reference key="NSMenu" ref="789758025"/> |
@@ -361,8 +361,8 b'' | |||
|
361 | 361 | <string key="NSKeyEquiv">c</string> |
|
362 | 362 | <int key="NSKeyEquivModMask">1048576</int> |
|
363 | 363 | <int key="NSMnemonicLoc">2147483647</int> |
|
364 |
<reference key="NSOnImage" ref=" |
|
|
365 |
<reference key="NSMixedImage" ref=" |
|
|
364 | <reference key="NSOnImage" ref="271266416"/> | |
|
365 | <reference key="NSMixedImage" ref="508123839"/> | |
|
366 | 366 | </object> |
|
367 | 367 | <object class="NSMenuItem" id="29853731"> |
|
368 | 368 | <reference key="NSMenu" ref="789758025"/> |
@@ -370,8 +370,8 b'' | |||
|
370 | 370 | <string key="NSKeyEquiv">v</string> |
|
371 | 371 | <int key="NSKeyEquivModMask">1048576</int> |
|
372 | 372 | <int key="NSMnemonicLoc">2147483647</int> |
|
373 |
<reference key="NSOnImage" ref=" |
|
|
374 |
<reference key="NSMixedImage" ref=" |
|
|
373 | <reference key="NSOnImage" ref="271266416"/> | |
|
374 | <reference key="NSMixedImage" ref="508123839"/> | |
|
375 | 375 | </object> |
|
376 | 376 | <object class="NSMenuItem" id="437104165"> |
|
377 | 377 | <reference key="NSMenu" ref="789758025"/> |
@@ -379,8 +379,8 b'' | |||
|
379 | 379 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
380 | 380 | <int key="NSKeyEquivModMask">1048576</int> |
|
381 | 381 | <int key="NSMnemonicLoc">2147483647</int> |
|
382 |
<reference key="NSOnImage" ref=" |
|
|
383 |
<reference key="NSMixedImage" ref=" |
|
|
382 | <reference key="NSOnImage" ref="271266416"/> | |
|
383 | <reference key="NSMixedImage" ref="508123839"/> | |
|
384 | 384 | </object> |
|
385 | 385 | <object class="NSMenuItem" id="583158037"> |
|
386 | 386 | <reference key="NSMenu" ref="789758025"/> |
@@ -388,8 +388,8 b'' | |||
|
388 | 388 | <string key="NSKeyEquiv">a</string> |
|
389 | 389 | <int key="NSKeyEquivModMask">1048576</int> |
|
390 | 390 | <int key="NSMnemonicLoc">2147483647</int> |
|
391 |
<reference key="NSOnImage" ref=" |
|
|
392 |
<reference key="NSMixedImage" ref=" |
|
|
391 | <reference key="NSOnImage" ref="271266416"/> | |
|
392 | <reference key="NSMixedImage" ref="508123839"/> | |
|
393 | 393 | </object> |
|
394 | 394 | <object class="NSMenuItem" id="212016141"> |
|
395 | 395 | <reference key="NSMenu" ref="789758025"/> |
@@ -399,8 +399,8 b'' | |||
|
399 | 399 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
400 | 400 | <int key="NSKeyEquivModMask">1048576</int> |
|
401 | 401 | <int key="NSMnemonicLoc">2147483647</int> |
|
402 |
<reference key="NSOnImage" ref=" |
|
|
403 |
<reference key="NSMixedImage" ref=" |
|
|
402 | <reference key="NSOnImage" ref="271266416"/> | |
|
403 | <reference key="NSMixedImage" ref="508123839"/> | |
|
404 | 404 | </object> |
|
405 | 405 | <object class="NSMenuItem" id="892235320"> |
|
406 | 406 | <reference key="NSMenu" ref="789758025"/> |
@@ -408,8 +408,8 b'' | |||
|
408 | 408 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
409 | 409 | <int key="NSKeyEquivModMask">1048576</int> |
|
410 | 410 | <int key="NSMnemonicLoc">2147483647</int> |
|
411 |
<reference key="NSOnImage" ref=" |
|
|
412 |
<reference key="NSMixedImage" ref=" |
|
|
411 | <reference key="NSOnImage" ref="271266416"/> | |
|
412 | <reference key="NSMixedImage" ref="508123839"/> | |
|
413 | 413 | <string key="NSAction">submenuAction:</string> |
|
414 | 414 | <object class="NSMenu" key="NSSubmenu" id="963351320"> |
|
415 | 415 | <reference key="NSTitle" ref="688083180"/> |
@@ -421,8 +421,8 b'' | |||
|
421 | 421 | <string key="NSKeyEquiv" id="469505129">f</string> |
|
422 | 422 | <int key="NSKeyEquivModMask">1048576</int> |
|
423 | 423 | <int key="NSMnemonicLoc">2147483647</int> |
|
424 |
<reference key="NSOnImage" ref=" |
|
|
425 |
<reference key="NSMixedImage" ref=" |
|
|
424 | <reference key="NSOnImage" ref="271266416"/> | |
|
425 | <reference key="NSMixedImage" ref="508123839"/> | |
|
426 | 426 | <int key="NSTag">1</int> |
|
427 | 427 | </object> |
|
428 | 428 | <object class="NSMenuItem" id="326711663"> |
@@ -431,8 +431,8 b'' | |||
|
431 | 431 | <string key="NSKeyEquiv" id="762398675">g</string> |
|
432 | 432 | <int key="NSKeyEquivModMask">1048576</int> |
|
433 | 433 | <int key="NSMnemonicLoc">2147483647</int> |
|
434 |
<reference key="NSOnImage" ref=" |
|
|
435 |
<reference key="NSMixedImage" ref=" |
|
|
434 | <reference key="NSOnImage" ref="271266416"/> | |
|
435 | <reference key="NSMixedImage" ref="508123839"/> | |
|
436 | 436 | <int key="NSTag">2</int> |
|
437 | 437 | </object> |
|
438 | 438 | <object class="NSMenuItem" id="270902937"> |
@@ -441,8 +441,8 b'' | |||
|
441 | 441 | <string key="NSKeyEquiv" id="819654342">G</string> |
|
442 | 442 | <int key="NSKeyEquivModMask">1179648</int> |
|
443 | 443 | <int key="NSMnemonicLoc">2147483647</int> |
|
444 |
<reference key="NSOnImage" ref=" |
|
|
445 |
<reference key="NSMixedImage" ref=" |
|
|
444 | <reference key="NSOnImage" ref="271266416"/> | |
|
445 | <reference key="NSMixedImage" ref="508123839"/> | |
|
446 | 446 | <int key="NSTag">3</int> |
|
447 | 447 | </object> |
|
448 | 448 | <object class="NSMenuItem" id="159080638"> |
@@ -451,8 +451,8 b'' | |||
|
451 | 451 | <string key="NSKeyEquiv">e</string> |
|
452 | 452 | <int key="NSKeyEquivModMask">1048576</int> |
|
453 | 453 | <int key="NSMnemonicLoc">2147483647</int> |
|
454 |
<reference key="NSOnImage" ref=" |
|
|
455 |
<reference key="NSMixedImage" ref=" |
|
|
454 | <reference key="NSOnImage" ref="271266416"/> | |
|
455 | <reference key="NSMixedImage" ref="508123839"/> | |
|
456 | 456 | <int key="NSTag">7</int> |
|
457 | 457 | </object> |
|
458 | 458 | <object class="NSMenuItem" id="88285865"> |
@@ -461,8 +461,8 b'' | |||
|
461 | 461 | <string key="NSKeyEquiv">j</string> |
|
462 | 462 | <int key="NSKeyEquivModMask">1048576</int> |
|
463 | 463 | <int key="NSMnemonicLoc">2147483647</int> |
|
464 |
<reference key="NSOnImage" ref=" |
|
|
465 |
<reference key="NSMixedImage" ref=" |
|
|
464 | <reference key="NSOnImage" ref="271266416"/> | |
|
465 | <reference key="NSMixedImage" ref="508123839"/> | |
|
466 | 466 | </object> |
|
467 | 467 | </object> |
|
468 | 468 | </object> |
@@ -473,8 +473,8 b'' | |||
|
473 | 473 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
474 | 474 | <int key="NSKeyEquivModMask">1048576</int> |
|
475 | 475 | <int key="NSMnemonicLoc">2147483647</int> |
|
476 |
<reference key="NSOnImage" ref=" |
|
|
477 |
<reference key="NSMixedImage" ref=" |
|
|
476 | <reference key="NSOnImage" ref="271266416"/> | |
|
477 | <reference key="NSMixedImage" ref="508123839"/> | |
|
478 | 478 | <string key="NSAction">submenuAction:</string> |
|
479 | 479 | <object class="NSMenu" key="NSSubmenu" id="769623530"> |
|
480 | 480 | <reference key="NSTitle" ref="739167250"/> |
@@ -486,8 +486,8 b'' | |||
|
486 | 486 | <string key="NSKeyEquiv">:</string> |
|
487 | 487 | <int key="NSKeyEquivModMask">1048576</int> |
|
488 | 488 | <int key="NSMnemonicLoc">2147483647</int> |
|
489 |
<reference key="NSOnImage" ref=" |
|
|
490 |
<reference key="NSMixedImage" ref=" |
|
|
489 | <reference key="NSOnImage" ref="271266416"/> | |
|
490 | <reference key="NSMixedImage" ref="508123839"/> | |
|
491 | 491 | </object> |
|
492 | 492 | <object class="NSMenuItem" id="96193923"> |
|
493 | 493 | <reference key="NSMenu" ref="769623530"/> |
@@ -495,8 +495,8 b'' | |||
|
495 | 495 | <string key="NSKeyEquiv">;</string> |
|
496 | 496 | <int key="NSKeyEquivModMask">1048576</int> |
|
497 | 497 | <int key="NSMnemonicLoc">2147483647</int> |
|
498 |
<reference key="NSOnImage" ref=" |
|
|
499 |
<reference key="NSMixedImage" ref=" |
|
|
498 | <reference key="NSOnImage" ref="271266416"/> | |
|
499 | <reference key="NSMixedImage" ref="508123839"/> | |
|
500 | 500 | </object> |
|
501 | 501 | <object class="NSMenuItem" id="948374510"> |
|
502 | 502 | <reference key="NSMenu" ref="769623530"/> |
@@ -504,8 +504,8 b'' | |||
|
504 | 504 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
505 | 505 | <int key="NSKeyEquivModMask">1048576</int> |
|
506 | 506 | <int key="NSMnemonicLoc">2147483647</int> |
|
507 |
<reference key="NSOnImage" ref=" |
|
|
508 |
<reference key="NSMixedImage" ref=" |
|
|
507 | <reference key="NSOnImage" ref="271266416"/> | |
|
508 | <reference key="NSMixedImage" ref="508123839"/> | |
|
509 | 509 | </object> |
|
510 | 510 | <object class="NSMenuItem" id="967646866"> |
|
511 | 511 | <reference key="NSMenu" ref="769623530"/> |
@@ -513,8 +513,8 b'' | |||
|
513 | 513 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
514 | 514 | <int key="NSKeyEquivModMask">1048576</int> |
|
515 | 515 | <int key="NSMnemonicLoc">2147483647</int> |
|
516 |
<reference key="NSOnImage" ref=" |
|
|
517 |
<reference key="NSMixedImage" ref=" |
|
|
516 | <reference key="NSOnImage" ref="271266416"/> | |
|
517 | <reference key="NSMixedImage" ref="508123839"/> | |
|
518 | 518 | </object> |
|
519 | 519 | </object> |
|
520 | 520 | </object> |
@@ -525,8 +525,8 b'' | |||
|
525 | 525 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
526 | 526 | <int key="NSKeyEquivModMask">1048576</int> |
|
527 | 527 | <int key="NSMnemonicLoc">2147483647</int> |
|
528 |
<reference key="NSOnImage" ref=" |
|
|
529 |
<reference key="NSMixedImage" ref=" |
|
|
528 | <reference key="NSOnImage" ref="271266416"/> | |
|
529 | <reference key="NSMixedImage" ref="508123839"/> | |
|
530 | 530 | <string key="NSAction">submenuAction:</string> |
|
531 | 531 | <object class="NSMenu" key="NSSubmenu" id="698887838"> |
|
532 | 532 | <reference key="NSTitle" ref="904739598"/> |
@@ -538,8 +538,8 b'' | |||
|
538 | 538 | <reference key="NSKeyEquiv" ref="469505129"/> |
|
539 | 539 | <int key="NSKeyEquivModMask">1048576</int> |
|
540 | 540 | <int key="NSMnemonicLoc">2147483647</int> |
|
541 |
<reference key="NSOnImage" ref=" |
|
|
542 |
<reference key="NSMixedImage" ref=" |
|
|
541 | <reference key="NSOnImage" ref="271266416"/> | |
|
542 | <reference key="NSMixedImage" ref="508123839"/> | |
|
543 | 543 | <int key="NSTag">1</int> |
|
544 | 544 | </object> |
|
545 | 545 | <object class="NSMenuItem" id="197661976"> |
@@ -548,8 +548,8 b'' | |||
|
548 | 548 | <reference key="NSKeyEquiv" ref="762398675"/> |
|
549 | 549 | <int key="NSKeyEquivModMask">1048576</int> |
|
550 | 550 | <int key="NSMnemonicLoc">2147483647</int> |
|
551 |
<reference key="NSOnImage" ref=" |
|
|
552 |
<reference key="NSMixedImage" ref=" |
|
|
551 | <reference key="NSOnImage" ref="271266416"/> | |
|
552 | <reference key="NSMixedImage" ref="508123839"/> | |
|
553 | 553 | <int key="NSTag">2</int> |
|
554 | 554 | </object> |
|
555 | 555 | <object class="NSMenuItem" id="708854459"> |
@@ -558,8 +558,8 b'' | |||
|
558 | 558 | <reference key="NSKeyEquiv" ref="819654342"/> |
|
559 | 559 | <int key="NSKeyEquivModMask">1179648</int> |
|
560 | 560 | <int key="NSMnemonicLoc">2147483647</int> |
|
561 |
<reference key="NSOnImage" ref=" |
|
|
562 |
<reference key="NSMixedImage" ref=" |
|
|
561 | <reference key="NSOnImage" ref="271266416"/> | |
|
562 | <reference key="NSMixedImage" ref="508123839"/> | |
|
563 | 563 | <int key="NSTag">3</int> |
|
564 | 564 | </object> |
|
565 | 565 | </object> |
@@ -571,8 +571,8 b'' | |||
|
571 | 571 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
572 | 572 | <int key="NSKeyEquivModMask">1048576</int> |
|
573 | 573 | <int key="NSMnemonicLoc">2147483647</int> |
|
574 |
<reference key="NSOnImage" ref=" |
|
|
575 |
<reference key="NSMixedImage" ref=" |
|
|
574 | <reference key="NSOnImage" ref="271266416"/> | |
|
575 | <reference key="NSMixedImage" ref="508123839"/> | |
|
576 | 576 | <string key="NSAction">submenuAction:</string> |
|
577 | 577 | <object class="NSMenu" key="NSSubmenu" id="785027613"> |
|
578 | 578 | <reference key="NSTitle" ref="812002426"/> |
@@ -584,8 +584,8 b'' | |||
|
584 | 584 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
585 | 585 | <int key="NSKeyEquivModMask">1048576</int> |
|
586 | 586 | <int key="NSMnemonicLoc">2147483647</int> |
|
587 |
<reference key="NSOnImage" ref=" |
|
|
588 |
<reference key="NSMixedImage" ref=" |
|
|
587 | <reference key="NSOnImage" ref="271266416"/> | |
|
588 | <reference key="NSMixedImage" ref="508123839"/> | |
|
589 | 589 | </object> |
|
590 | 590 | <object class="NSMenuItem" id="680220178"> |
|
591 | 591 | <reference key="NSMenu" ref="785027613"/> |
@@ -593,8 +593,8 b'' | |||
|
593 | 593 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
594 | 594 | <int key="NSKeyEquivModMask">1048576</int> |
|
595 | 595 | <int key="NSMnemonicLoc">2147483647</int> |
|
596 |
<reference key="NSOnImage" ref=" |
|
|
597 |
<reference key="NSMixedImage" ref=" |
|
|
596 | <reference key="NSOnImage" ref="271266416"/> | |
|
597 | <reference key="NSMixedImage" ref="508123839"/> | |
|
598 | 598 | </object> |
|
599 | 599 | </object> |
|
600 | 600 | </object> |
@@ -608,8 +608,8 b'' | |||
|
608 | 608 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
609 | 609 | <int key="NSKeyEquivModMask">1048576</int> |
|
610 | 610 | <int key="NSMnemonicLoc">2147483647</int> |
|
611 |
<reference key="NSOnImage" ref=" |
|
|
612 |
<reference key="NSMixedImage" ref=" |
|
|
611 | <reference key="NSOnImage" ref="271266416"/> | |
|
612 | <reference key="NSMixedImage" ref="508123839"/> | |
|
613 | 613 | <string key="NSAction">submenuAction:</string> |
|
614 | 614 | <object class="NSMenu" key="NSSubmenu" id="502084290"> |
|
615 | 615 | <reference key="NSTitle" ref="241242548"/> |
@@ -621,8 +621,8 b'' | |||
|
621 | 621 | <string key="NSKeyEquiv" id="806579634">t</string> |
|
622 | 622 | <int key="NSKeyEquivModMask">1048576</int> |
|
623 | 623 | <int key="NSMnemonicLoc">2147483647</int> |
|
624 |
<reference key="NSOnImage" ref=" |
|
|
625 |
<reference key="NSMixedImage" ref=" |
|
|
624 | <reference key="NSOnImage" ref="271266416"/> | |
|
625 | <reference key="NSMixedImage" ref="508123839"/> | |
|
626 | 626 | </object> |
|
627 | 627 | <object class="NSMenuItem" id="1028416764"> |
|
628 | 628 | <reference key="NSMenu" ref="502084290"/> |
@@ -630,8 +630,8 b'' | |||
|
630 | 630 | <string key="NSKeyEquiv">C</string> |
|
631 | 631 | <int key="NSKeyEquivModMask">1179648</int> |
|
632 | 632 | <int key="NSMnemonicLoc">2147483647</int> |
|
633 |
<reference key="NSOnImage" ref=" |
|
|
634 |
<reference key="NSMixedImage" ref=" |
|
|
633 | <reference key="NSOnImage" ref="271266416"/> | |
|
634 | <reference key="NSMixedImage" ref="508123839"/> | |
|
635 | 635 | </object> |
|
636 | 636 | </object> |
|
637 | 637 | </object> |
@@ -642,8 +642,8 b'' | |||
|
642 | 642 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
643 | 643 | <int key="NSKeyEquivModMask">1048576</int> |
|
644 | 644 | <int key="NSMnemonicLoc">2147483647</int> |
|
645 |
<reference key="NSOnImage" ref=" |
|
|
646 |
<reference key="NSMixedImage" ref=" |
|
|
645 | <reference key="NSOnImage" ref="271266416"/> | |
|
646 | <reference key="NSMixedImage" ref="508123839"/> | |
|
647 | 647 | <string key="NSAction">submenuAction:</string> |
|
648 | 648 | <object class="NSMenu" key="NSSubmenu" id="466310130"> |
|
649 | 649 | <reference key="NSTitle" ref="809723865"/> |
@@ -655,8 +655,8 b'' | |||
|
655 | 655 | <reference key="NSKeyEquiv" ref="806579634"/> |
|
656 | 656 | <int key="NSKeyEquivModMask">1572864</int> |
|
657 | 657 | <int key="NSMnemonicLoc">2147483647</int> |
|
658 |
<reference key="NSOnImage" ref=" |
|
|
659 |
<reference key="NSMixedImage" ref=" |
|
|
658 | <reference key="NSOnImage" ref="271266416"/> | |
|
659 | <reference key="NSMixedImage" ref="508123839"/> | |
|
660 | 660 | </object> |
|
661 | 661 | <object class="NSMenuItem" id="237841660"> |
|
662 | 662 | <reference key="NSMenu" ref="466310130"/> |
@@ -664,8 +664,8 b'' | |||
|
664 | 664 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
665 | 665 | <int key="NSKeyEquivModMask">1048576</int> |
|
666 | 666 | <int key="NSMnemonicLoc">2147483647</int> |
|
667 |
<reference key="NSOnImage" ref=" |
|
|
668 |
<reference key="NSMixedImage" ref=" |
|
|
667 | <reference key="NSOnImage" ref="271266416"/> | |
|
668 | <reference key="NSMixedImage" ref="508123839"/> | |
|
669 | 669 | </object> |
|
670 | 670 | </object> |
|
671 | 671 | </object> |
@@ -676,8 +676,8 b'' | |||
|
676 | 676 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
677 | 677 | <int key="NSKeyEquivModMask">1048576</int> |
|
678 | 678 | <int key="NSMnemonicLoc">2147483647</int> |
|
679 |
<reference key="NSOnImage" ref=" |
|
|
680 |
<reference key="NSMixedImage" ref=" |
|
|
679 | <reference key="NSOnImage" ref="271266416"/> | |
|
680 | <reference key="NSMixedImage" ref="508123839"/> | |
|
681 | 681 | <string key="NSAction">submenuAction:</string> |
|
682 | 682 | <object class="NSMenu" key="NSSubmenu" id="835318025"> |
|
683 | 683 | <reference key="NSTitle" ref="64165424"/> |
@@ -689,8 +689,8 b'' | |||
|
689 | 689 | <string key="NSKeyEquiv">m</string> |
|
690 | 690 | <int key="NSKeyEquivModMask">1048576</int> |
|
691 | 691 | <int key="NSMnemonicLoc">2147483647</int> |
|
692 |
<reference key="NSOnImage" ref=" |
|
|
693 |
<reference key="NSMixedImage" ref=" |
|
|
692 | <reference key="NSOnImage" ref="271266416"/> | |
|
693 | <reference key="NSMixedImage" ref="508123839"/> | |
|
694 | 694 | </object> |
|
695 | 695 | <object class="NSMenuItem" id="575023229"> |
|
696 | 696 | <reference key="NSMenu" ref="835318025"/> |
@@ -698,8 +698,8 b'' | |||
|
698 | 698 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
699 | 699 | <int key="NSKeyEquivModMask">1048576</int> |
|
700 | 700 | <int key="NSMnemonicLoc">2147483647</int> |
|
701 |
<reference key="NSOnImage" ref=" |
|
|
702 |
<reference key="NSMixedImage" ref=" |
|
|
701 | <reference key="NSOnImage" ref="271266416"/> | |
|
702 | <reference key="NSMixedImage" ref="508123839"/> | |
|
703 | 703 | </object> |
|
704 | 704 | <object class="NSMenuItem" id="299356726"> |
|
705 | 705 | <reference key="NSMenu" ref="835318025"/> |
@@ -709,8 +709,8 b'' | |||
|
709 | 709 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
710 | 710 | <int key="NSKeyEquivModMask">1048576</int> |
|
711 | 711 | <int key="NSMnemonicLoc">2147483647</int> |
|
712 |
<reference key="NSOnImage" ref=" |
|
|
713 |
<reference key="NSMixedImage" ref=" |
|
|
712 | <reference key="NSOnImage" ref="271266416"/> | |
|
713 | <reference key="NSMixedImage" ref="508123839"/> | |
|
714 | 714 | </object> |
|
715 | 715 | <object class="NSMenuItem" id="625202149"> |
|
716 | 716 | <reference key="NSMenu" ref="835318025"/> |
@@ -718,8 +718,8 b'' | |||
|
718 | 718 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
719 | 719 | <int key="NSKeyEquivModMask">1048576</int> |
|
720 | 720 | <int key="NSMnemonicLoc">2147483647</int> |
|
721 |
<reference key="NSOnImage" ref=" |
|
|
722 |
<reference key="NSMixedImage" ref=" |
|
|
721 | <reference key="NSOnImage" ref="271266416"/> | |
|
722 | <reference key="NSMixedImage" ref="508123839"/> | |
|
723 | 723 | </object> |
|
724 | 724 | </object> |
|
725 | 725 | <string key="NSName">_NSWindowsMenu</string> |
@@ -731,8 +731,8 b'' | |||
|
731 | 731 | <reference key="NSKeyEquiv" ref="255189770"/> |
|
732 | 732 | <int key="NSKeyEquivModMask">1048576</int> |
|
733 | 733 | <int key="NSMnemonicLoc">2147483647</int> |
|
734 |
<reference key="NSOnImage" ref=" |
|
|
735 |
<reference key="NSMixedImage" ref=" |
|
|
734 | <reference key="NSOnImage" ref="271266416"/> | |
|
735 | <reference key="NSMixedImage" ref="508123839"/> | |
|
736 | 736 | <string key="NSAction">submenuAction:</string> |
|
737 | 737 | <object class="NSMenu" key="NSSubmenu" id="374024848"> |
|
738 | 738 | <reference key="NSTitle" ref="461919786"/> |
@@ -744,8 +744,8 b'' | |||
|
744 | 744 | <string key="NSKeyEquiv">?</string> |
|
745 | 745 | <int key="NSKeyEquivModMask">1048576</int> |
|
746 | 746 | <int key="NSMnemonicLoc">2147483647</int> |
|
747 |
<reference key="NSOnImage" ref=" |
|
|
748 |
<reference key="NSMixedImage" ref=" |
|
|
747 | <reference key="NSOnImage" ref="271266416"/> | |
|
748 | <reference key="NSMixedImage" ref="508123839"/> | |
|
749 | 749 | </object> |
|
750 | 750 | </object> |
|
751 | 751 | </object> |
@@ -860,7 +860,7 b'' | |||
|
860 | 860 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
861 | 861 | <object class="NSColor"> |
|
862 | 862 | <int key="NSColorSpace">6</int> |
|
863 |
<string key="NSCatalogName" id=" |
|
|
863 | <string key="NSCatalogName" id="484387293">System</string> | |
|
864 | 864 | <string key="NSColorName">selectedTextBackgroundColor</string> |
|
865 | 865 | <object class="NSColor" key="NSColor" id="377165725"> |
|
866 | 866 | <int key="NSColorSpace">3</int> |
@@ -869,7 +869,7 b'' | |||
|
869 | 869 | </object> |
|
870 | 870 | <object class="NSColor"> |
|
871 | 871 | <int key="NSColorSpace">6</int> |
|
872 |
<reference key="NSCatalogName" ref=" |
|
|
872 | <reference key="NSCatalogName" ref="484387293"/> | |
|
873 | 873 | <string key="NSColorName">selectedTextColor</string> |
|
874 | 874 | <reference key="NSColor" ref="555789289"/> |
|
875 | 875 | </object> |
@@ -963,13 +963,13 b'' | |||
|
963 | 963 | <int key="NSCellFlags2">0</int> |
|
964 | 964 | <string key="NSContents">Console</string> |
|
965 | 965 | <object class="NSFont" key="NSSupport" id="26"> |
|
966 |
<string key="NSName" id=" |
|
|
966 | <string key="NSName" id="378950370">LucidaGrande</string> | |
|
967 | 967 | <double key="NSSize">1.100000e+01</double> |
|
968 | 968 | <int key="NSfFlags">3100</int> |
|
969 | 969 | </object> |
|
970 | 970 | <object class="NSColor" key="NSBackgroundColor" id="131515055"> |
|
971 | 971 | <int key="NSColorSpace">6</int> |
|
972 |
<reference key="NSCatalogName" ref=" |
|
|
972 | <reference key="NSCatalogName" ref="484387293"/> | |
|
973 | 973 | <string key="NSColorName">textBackgroundColor</string> |
|
974 | 974 | <reference key="NSColor" ref="521347521"/> |
|
975 | 975 | </object> |
@@ -1043,7 +1043,7 b'' | |||
|
1043 | 1043 | </object> |
|
1044 | 1044 | <object class="NSColor" key="NSTextColor" id="866628999"> |
|
1045 | 1045 | <int key="NSColorSpace">6</int> |
|
1046 |
<reference key="NSCatalogName" ref=" |
|
|
1046 | <reference key="NSCatalogName" ref="484387293"/> | |
|
1047 | 1047 | <string key="NSColorName">headerTextColor</string> |
|
1048 | 1048 | <reference key="NSColor" ref="555789289"/> |
|
1049 | 1049 | </object> |
@@ -1051,22 +1051,22 b'' | |||
|
1051 | 1051 | <object class="NSTextFieldCell" key="NSDataCell" id="525071236"> |
|
1052 | 1052 | <int key="NSCellFlags">337772096</int> |
|
1053 | 1053 | <int key="NSCellFlags2">2048</int> |
|
1054 |
<string key="NSContents" id=" |
|
|
1054 | <string key="NSContents" id="456204663">Text Cell</string> | |
|
1055 | 1055 | <object class="NSFont" key="NSSupport" id="8196371"> |
|
1056 |
<reference key="NSName" ref=" |
|
|
1056 | <reference key="NSName" ref="378950370"/> | |
|
1057 | 1057 | <double key="NSSize">1.300000e+01</double> |
|
1058 | 1058 | <int key="NSfFlags">1044</int> |
|
1059 | 1059 | </object> |
|
1060 | 1060 | <reference key="NSControlView" ref="23853726"/> |
|
1061 | 1061 | <object class="NSColor" key="NSBackgroundColor" id="224028609"> |
|
1062 | 1062 | <int key="NSColorSpace">6</int> |
|
1063 |
<reference key="NSCatalogName" ref=" |
|
|
1063 | <reference key="NSCatalogName" ref="484387293"/> | |
|
1064 | 1064 | <string key="NSColorName">controlBackgroundColor</string> |
|
1065 | 1065 | <reference key="NSColor" ref="377165725"/> |
|
1066 | 1066 | </object> |
|
1067 | 1067 | <object class="NSColor" key="NSTextColor" id="205104690"> |
|
1068 | 1068 | <int key="NSColorSpace">6</int> |
|
1069 |
<reference key="NSCatalogName" ref=" |
|
|
1069 | <reference key="NSCatalogName" ref="484387293"/> | |
|
1070 | 1070 | <string key="NSColorName">controlTextColor</string> |
|
1071 | 1071 | <reference key="NSColor" ref="555789289"/> |
|
1072 | 1072 | </object> |
@@ -1091,7 +1091,7 b'' | |||
|
1091 | 1091 | <object class="NSTextFieldCell" key="NSDataCell" id="377147224"> |
|
1092 | 1092 | <int key="NSCellFlags">337772096</int> |
|
1093 | 1093 | <int key="NSCellFlags2">2048</int> |
|
1094 |
<reference key="NSContents" ref=" |
|
|
1094 | <reference key="NSContents" ref="456204663"/> | |
|
1095 | 1095 | <reference key="NSSupport" ref="8196371"/> |
|
1096 | 1096 | <reference key="NSControlView" ref="23853726"/> |
|
1097 | 1097 | <reference key="NSBackgroundColor" ref="224028609"/> |
@@ -1108,7 +1108,7 b'' | |||
|
1108 | 1108 | <reference key="NSBackgroundColor" ref="521347521"/> |
|
1109 | 1109 | <object class="NSColor" key="NSGridColor"> |
|
1110 | 1110 | <int key="NSColorSpace">6</int> |
|
1111 |
<reference key="NSCatalogName" ref=" |
|
|
1111 | <reference key="NSCatalogName" ref="484387293"/> | |
|
1112 | 1112 | <string key="NSColorName">gridColor</string> |
|
1113 | 1113 | <object class="NSColor" key="NSColor"> |
|
1114 | 1114 | <int key="NSColorSpace">3</int> |
@@ -2787,9 +2787,9 b'' | |||
|
2787 | 2787 | <reference ref="9"/> |
|
2788 | 2788 | <reference ref="113577022"/> |
|
2789 | 2789 | <integer value="0"/> |
|
2790 |
<string>{{ |
|
|
2790 | <string>{{27, 368}, {725, 337}}</string> | |
|
2791 | 2791 | <reference ref="9"/> |
|
2792 |
<string>{{ |
|
|
2792 | <string>{{27, 368}, {725, 337}}</string> | |
|
2793 | 2793 | <reference ref="113577022"/> |
|
2794 | 2794 | <reference ref="113577022"/> |
|
2795 | 2795 | <reference ref="113577022"/> |
@@ -2878,8 +2878,8 b'' | |||
|
2878 | 2878 | <object class="NSMutableArray" key="referencedPartialClassDescriptions"> |
|
2879 | 2879 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
2880 | 2880 | <object class="IBPartialClassDescription"> |
|
2881 | <string key="className">IPython1SandboxAppDelegate</string> | |
|
2882 |
< |
|
|
2881 | <reference key="className" ref="695797635"/> | |
|
2882 | <nil key="superclassName"/> | |
|
2883 | 2883 | <object class="NSMutableDictionary" key="actions"> |
|
2884 | 2884 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
2885 | 2885 | <object class="NSArray" key="dict.sortedKeys"> |
@@ -2890,17 +2890,17 b'' | |||
|
2890 | 2890 | </object> |
|
2891 | 2891 | </object> |
|
2892 | 2892 | <object class="NSMutableDictionary" key="outlets"> |
|
2893 | <string key="NS.key.0">ipythonController</string> | |
|
2894 |
<string key="NS.object.0"> |
|
|
2893 | <reference key="NS.key.0" ref="684042788"/> | |
|
2894 | <string key="NS.object.0">NSTextView</string> | |
|
2895 | 2895 | </object> |
|
2896 | 2896 | <object class="IBClassDescriptionSource" key="sourceIdentifier"> |
|
2897 |
<string key="majorKey">IB |
|
|
2898 | <string key="minorKey">IPython1SandboxAppDelegate.py</string> | |
|
2897 | <string key="majorKey">IBUserSource</string> | |
|
2898 | <reference key="minorKey" ref="255189770"/> | |
|
2899 | 2899 | </object> |
|
2900 | 2900 | </object> |
|
2901 | 2901 | <object class="IBPartialClassDescription"> |
|
2902 | <reference key="className" ref="695797635"/> | |
|
2903 |
< |
|
|
2902 | <string key="className">IPython1SandboxAppDelegate</string> | |
|
2903 | <string key="superclassName">NSObject</string> | |
|
2904 | 2904 | <object class="NSMutableDictionary" key="actions"> |
|
2905 | 2905 | <bool key="EncodedWithXMLCoder">YES</bool> |
|
2906 | 2906 | <object class="NSArray" key="dict.sortedKeys"> |
@@ -2911,12 +2911,12 b'' | |||
|
2911 | 2911 | </object> |
|
2912 | 2912 | </object> |
|
2913 | 2913 | <object class="NSMutableDictionary" key="outlets"> |
|
2914 | <reference key="NS.key.0" ref="684042788"/> | |
|
2915 |
<string key="NS.object.0"> |
|
|
2914 | <string key="NS.key.0">ipythonController</string> | |
|
2915 | <string key="NS.object.0">id</string> | |
|
2916 | 2916 | </object> |
|
2917 | 2917 | <object class="IBClassDescriptionSource" key="sourceIdentifier"> |
|
2918 |
<string key="majorKey">IB |
|
|
2919 | <reference key="minorKey" ref="255189770"/> | |
|
2918 | <string key="majorKey">IBProjectSource</string> | |
|
2919 | <string key="minorKey">IPython1SandboxAppDelegate.py</string> | |
|
2920 | 2920 | </object> |
|
2921 | 2921 | </object> |
|
2922 | 2922 | </object> |
@@ -2932,18 +2932,18 b' AQUBBgEHAQgBCQEKAQsBDwEQARkBIQEmASoBLQExATUBOQE7AT0BTQFSAVUBWgFBAVQBYwFqAWsBbAFv' | |||
|
2932 | 2932 | AXQBdQF4AYAAkAGBAYQBhwGIAYkBjgGPAZABkwGYAZkBmwGeAasBrAGtAbEBvAG9Ab4BwQHCAcQBxQHG |
|
2933 | 2933 | AdIB0wHbAdwB3wHkAeUB6AHtAfAB/AIAAgcCCwIdAiUCLwIzAlECUgJaAmQCZQJoAm4CbwJyAncCiAKP |
|
2934 | 2934 | ApACkwKYApkCnAKmAqcCrAKxArICtwK4ArsCwwLJAsoC0QLWAtcC2gLcAt0C5gLnAvAC8QL1AvYC9wL4 |
|
2935 |
AvkC/wMAAwIDAwMEAwcDFgMYAxsDHAMfAAsDIAMhAyIDJQNXA10Db |
|
|
2936 | A4gDjAOQA5cDmwOcA50DngOiA6kDqgOrA6wDsAO3A7sDvAO9A74DwgPJA80DzgPPA9AD1APcA90D3gPf | |
|
2937 | A+MD6wPwA/ED8gPzA/cD/gQCBAMEBAQFBAkEEAQRBBIEEwQXBB4EHwQgBCQEKwQvASkEMAQxBDcEOgQ7 | |
|
2938 | BDwEPwRDBEoESwRMBFAEVwRcBF0EXgRfBGMEagRrBGwEcAR3BHgEeQR9BIQEhQSGBIcEjASTBJQElQSZ | |
|
2939 | BKAEpASlBKYEpwSrBLIEswS0BLUEuQTABMEEwgTGBM0EzgTPBNME2gTbBNwE3QThBOgE6QTqBOsE7wT2 | |
|
2940 | BPcE+AT5BP0FBAUFBQYFBwUMBQ8FEAURBRUFHAUdBR4FIgUpBSoFKwUsBTAFNwU7BTwFPQU+BUMFRgVK | |
|
2941 | BVEFUgVTBVcFXgViBWMFZAVlBWkFcAV1BXYFdwV7BYIFgwWEBYgFjwWQBZEFkgWXBZgFnQWeBaIFqwWs | |
|
2942 |
B |
|
|
2943 |
B |
|
|
2944 | BuQG5QbvBvgGuAb5BwcHEgcZBxoHGwckBy0GuAcuBzMHNgc3B0AHSQdKB1MGuAdUB2IHaQdqB2sHcgdz | |
|
2945 | B3QHfQeGB48GuAeQB6AHqQeyB7sGuAe8B8QHywfMB9MH1AfcB90H3gfnBrgH6AfvB/gGuAf5B/4IBQgG | |
|
2946 |
CA8G |
|
|
2935 | AvkC/wMAAwIDAwMEAwcDFgMYAxsDHAMfAAsDIAMhAyIDJQNXA10DbQNzASkDdAN5A3oDewN+A4IDgwOG | |
|
2936 | A4cDiwOPA5YDmgObA5wDnQOhA6gDrAOtA64DrwOzA7wDwAPBA8IDwwPHA84D0gPTA9QD1QPZA+AD5APl | |
|
2937 | A+YD6gPxA/UD9gP3A/gD/AQDBAQEBQQJBBAEEQQSBBMEFwQeBB8EIAQkBCsELwQwBDEENQQ9BD4EPwRA | |
|
2938 | BEQESwRMBE0ETgRUBFcEWgRbBFwEXwRjBGoEawRsBG0EcgR1BHYEdwR7BIIEgwSEBIUEiQSQBJUElgSX | |
|
2939 | BJgEnASjBKQEpQSmBKoEsQSyBLMEtAS4BL8EwwTEBMUExgTKBNEE0gTTBNQE2ATfBOAE4QTiBOYE7QTx | |
|
2940 | BPIE8wT0BPgE/wUABQEFBgUNBQ4FDwUTBRwFHQUeBR8FJAUoBS8FMAUxBTIFNwU4BTwFQwVEBUUFRgVK | |
|
2941 | BVEFVgVXBVgFXAVjBWQFZQVpBXAFcQVyBXcFeAV8BYMFhAWFBYkFkAWRBZIFlgWdBZ4FnwWjBaoFqwWs | |
|
2942 | BbAFtwW4BbkFugW+BcUFxgXHBcgFzAXTBdQF1QXWBeAF9gX8Bf0F/gX/BgMGCwYMBg8GEQYXBhgGGQYa | |
|
2943 | Bh0GJAYlBiYGJwYuBi8GMAY3BjgGOQZABkEGQgZDBq0GuAbCBscGyAbJBs4G1QbWBtgG2QbdBt4GyAbn | |
|
2944 | BvAGyAbxBvgHAQbIBwIHEgcbByQHLQbIBy4HNgc9Bz4HRQdGB04HTwdQB1kGyAdaB2AHaQbIB2oHbwdw | |
|
2945 | B3oHgwbIB4QHkgebB6IHowekB60HtgbIB7cHvAe/B8AHyQfKB9MGyAfUB+IH6QfqB+sH8gfzB/QH/QgG | |
|
2946 | CA8GyAgQCBUIHgbICB8IJggvCDAIOQbICDoIPgg/CKkJFAl/CYAJgQmCCYMJhAmFCYYJhwmICYkJigmL | |
|
2947 | 2947 | CYwJjQmOCY8JkAmRCZIJkwmUCZUJlgmXCZgJmQmaCZsJnAmdCZ4JnwmgCaEJogmjCaQJpQmmCacJqAmp |
|
2948 | 2948 | CaoJqwmsCa0JrgmvCbAJsQmyCbMJtAm1CbYJtwm4CbkJugm7CbwJvQm+Cb8JwAnBCcIJwwnECcUJxgnH |
|
2949 | 2949 | CcgJyQnKCcsJzAnNCc4JzwnQCdEJ0gnTCdQJ1QnWCdcJ2AnZCdoJ2wncCd0J3gnfCeAJ4QniCeMJ5Anl |
@@ -3073,351 +3073,352 b' ezE2LCAxNn190gA3ADgDHQMepAMeAYwBjQA7XxATTlNQcm9ncmVzc0luZGljYXRvclp7NzI1LCAzMzd9' | |||
|
3073 | 3073 | XxAVe3swLCAwfSwgezEyODAsIDc3OH19XxAQaXB5dGhvbjFfc2FuZGJveNIANwA4AyMDJKIDJAA7XxAQ |
|
3074 | 3074 | TlNXaW5kb3dUZW1wbGF0ZdIADgA+AGkDJ4A0rxAvAygDKQMqAysDLAMtAy4DLwMwAzEDMgMzAzQDNQM2 |
|
3075 | 3075 | AzcDOAM5AzoDOwM8Az0DPgM/A0ADQQNCA0MDRANFA0YDRwNIA0kDSgNLA0wDTQNOA08DUANRA1IDUwNU |
|
3076 |
A1UDVoCugLyAwoD |
|
|
3077 |
AS |
|
|
3078 |
AY |
|
|
3079 | A2MDZANlA2YDZwNoA2kDagNrA2wDbQBVV05TVGl0bGVfEBFOU0tleUVxdWl2TW9kTWFza1pOU0tleUVx | |
|
3080 | dWl2XU5TTW5lbW9uaWNMb2NZTlNPbkltYWdlXE5TTWl4ZWRJbWFnZVZOU01lbnVVTlNUYWeAuYCxEgAQ | |
|
3081 | AACAshJ/////gLOAt4Cw0wAOA14DbwNwA3EDcltOU01lbnVJdGVtc4EBoIEBp4EBqVxTbWFydCBRdW90 | |
|
3082 |
|
|
|
3083 |
|
|
|
3084 |
|
|
|
3085 | b3RlU3Vic3RpdHV0aW9uOtIANwA4A4kDiqMDigOLADtfEBVOU05pYkNvbnRyb2xDb25uZWN0b3JeTlNO | |
|
3086 | aWJDb25uZWN0b3LTAA4DWANZA1oDjgOPgLuAvYDB2AAOA14DXwNgA2EDYgNjA2QDZgOSA2gDkwNqA2sD | |
|
3087 | bAOWgLmAv4DAgLOAt4C+0wAOA14DbwNwA5kDmoEBoIEB0oEB1F8QEUp1bXAgdG8gU2VsZWN0aW9uUWpf | |
|
3088 | EB1jZW50ZXJTZWxlY3Rpb25JblZpc2libGVBcmVhOtMADgNYA1kDWgOgA6GAu4DDgMbZAA4DXgNfA2AD | |
|
3089 | YQNiA2MDZANlA2YDpANoA6UDagNrA2wDbQCQgLmAxIDFgLOAt4CwXxAQU21hcnQgQ29weS9QYXN0ZVFm | |
|
3090 | XxAYdG9nZ2xlU21hcnRJbnNlcnREZWxldGU60wAOA1gDWQNaA64Dr4C7gMiAzNgADgNeA18DYANhA2ID | |
|
3091 | YwNkA2YDsgNoA7MDagNrA2wDtoC5gMqAy4CzgLeAydMADgNeA28DcAO5A7qBAaCBAcCBAcJUU2F2ZVFz | |
|
3092 | XXNhdmVEb2N1bWVudDrTAA4DWANZA1oDwAPBgLuAzoDS2AAOA14DXwNgA2EDYgNjA2QDZgPEA2gDxQNq | |
|
3093 | A2sDbAPIgLmA0IDRgLOAt4DP0wAOA14DbwNwA8sDzIEBoIEBzIEBzlRVbmRvUXpVdW5kbzrTAA4DWANZ | |
|
3094 | A1oD0gPTgLuA1IDX2AAOA14DXwNgA2EDYgNjA2QDZgPWA9cD2ANqA2sDbAPIgLmA1RIAEgAAgNaAs4C3 | |
|
3095 | gM9UUmVkb1FaVXJlZG860wAOA1gDWQNaA+ED4oC7gNmA3dgADgNeA18DYANhA2IDYwNkA2YD5QPmA+cD | |
|
3096 | agNrA2wD6oC5gNsSABgAAIDcgLOAt4Da1AAOA14B1QNvA3AD7QPuA++BAaCBAa6BAb6BAbBbSGlkZSBP | |
|
3097 | dGhlcnNRaF8QFmhpZGVPdGhlckFwcGxpY2F0aW9uczrTAA4DWANZA1oD9QP2gLuA34Dj2AAOA14DXwNg | |
|
3098 | A2EDYgNjA2QDZgP5A9cD+gNqA2sDbAP9gLmA4YDigLOAt4Dg0wAOA14DbwNwBAAEAYEBoIEB4YEB41tT | |
|
3099 | aG93IENvbG9yc1FDXxAVb3JkZXJGcm9udENvbG9yUGFuZWw60wAOA1gDWQNaBAcECIC7gOWA6NgADgNe | |
|
3100 | A18DYANhA2IDYwNkA2YECwNoBAwDagNrA2wDyIC5gOaA54CzgLeAz1VQYXN0ZVF2VnBhc3RlOtMADgNY | |
|
3101 | A1kDWgQVBBaAu4DqgOzZAA4DXgNfA2ADYQNiA2MDZANlA2YEGQNoA6UDagNrA2wDlgCQgLmA64DFgLOA | |
|
3102 | t4C+ZQBGAGkAbgBkICZfEBdwZXJmb3JtRmluZFBhbmVsQWN0aW9uOtMADgNYA1kDWgQiBCOAu4DugPLY | |
|
3103 | AA4DXgNfA2ADYQNiA2MDZANmBCYDaAQnA2oDawNsBCqAuYDwgPGAs4C3gO/TAA4DXgNvA3AELQQugQGg | |
|
3104 | gQGdgQGfXVN0b3AgU3BlYWtpbmddc3RvcFNwZWFraW5nOtQADgQyA1gDWQQzBDQAQQQ2XU5TRGVzdGlu | |
|
3105 | YXRpb26A94D0gAeA9tIADgAyADMEOYAEgPVfEBZJUHl0aG9uQ29jb2FDb250cm9sbGVyWGRlbGVnYXRl | |
|
3106 | 0gA3ADgEPQQ+owQ+A4sAO18QFE5TTmliT3V0bGV0Q29ubmVjdG9y0wAOA1gDWQNaBEEEQoC7gPmA+9gA | |
|
3107 | DgNeA18DYANhA2IDYwNkA2YERQNoBCcDagNrA2wDyIC5gPqA8YCzgLeAz1ZEZWxldGVXZGVsZXRlOtMA | |
|
3108 | DgNYA1kDWgROBE+Au4D9gQEB2AAOA14DXwNgA2EDYgNjA2QDZgRSA2gEUwNqA2sDbARWgLmA/4EBAICz | |
|
3109 | gLeA/tQADgNeAdUDbwNwBFkEWgRbgQGggQHrgQHvgQHtWE1pbmltaXplUW1fEBNwZXJmb3JtTWluaWF0 | |
|
3110 | dXJpemU60wAOA1gDWQNaBGEEYoC7gQEDgQEF2AAOA14DXwNgA2EDYgNjA2QDZgRlA2gEJwNqA2sDbARW | |
|
3111 | gLmBAQSA8YCzgLeA/l8QEkJyaW5nIEFsbCB0byBGcm9udF8QD2FycmFuZ2VJbkZyb250OtMADgNYA1kD | |
|
3112 | WgRuBG+Au4EBB4EBCdgADgNeA18DYANhA2IDYwNkA2YEcgNoBCcDagNrA2wD6oC5gQEIgPGAs4C3gNpY | |
|
3113 | U2hvdyBBbGxfEBZ1bmhpZGVBbGxBcHBsaWNhdGlvbnM60wAOA1gDWQNaBHsEfIC7gQELgQEO2AAOA14D | |
|
3114 | XwNgA2EDYgNjA2QDZgR/A2gEgANqA2sDbAO2gLmBAQyBAQ2As4C3gMlVQ2xvc2VRd11wZXJmb3JtQ2xv | |
|
3115 | c2U61AAOBDIDWANZA1oAHwSKBIuAu4ACgQEQgQES1wAOA14DYANhA2IDYwNkA2YEjgQnA2oDawNsA+qA | |
|
3116 | uYEBEYDxgLOAt4DaXxAVQWJvdXQgSVB5dGhvbjFTYW5kYm94XxAdb3JkZXJGcm9udFN0YW5kYXJkQWJv | |
|
3117 | dXRQYW5lbDrTAA4DWANZA1oElwSYgLuBARSBARjYAA4DXgNfA2ADYQNiA2MDZANmBJsDaAScA2oDawNs | |
|
3118 | BJ+AuYEBFoEBF4CzgLeBARXTAA4DXgNvA3AEogSjgQGggQHdgQHfXkNoZWNrIFNwZWxsaW5nUTteY2hl | |
|
3119 | Y2tTcGVsbGluZzrTAA4DWANZA1oEqQSqgLuBARqBAR3YAA4DXgNfA2ADYQNiA2MDZANmBK0DaASuA2oD | |
|
3120 | awNsA8iAuYEBG4EBHICzgLeAz1pTZWxlY3QgQWxsUWFac2VsZWN0QWxsOtMADgNYA1kDWgS3BLiAu4EB | |
|
3121 | H4EBIdgADgNeA18DYANhA2IDYwNkA2YEuwNoA+cDagNrA2wD6oC5gQEggNyAs4C3gNpfEBRIaWRlIElQ | |
|
3122 |
|
|
|
3123 | yANoBCcDagNrA2wEn4C5gQEkgPGAs4C3gQEVXxAbQ2hlY2sgU3BlbGxpbmcgV2hpbGUgVHlwaW5nXxAe | |
|
3124 | dG9nZ2xlQ29udGludW91c1NwZWxsQ2hlY2tpbmc60wAOA1gDWQNaBNEE0oC7gQEngQEq2AAOA14DXwNg | |
|
3125 | A2EDYgNjA2QDZgTVA2gE1gNqA2sDbAO2gLmBASiBASmAs4C3gMlmAFAAcgBpAG4AdCAmUXBWcHJpbnQ6 | |
|
3126 |
0wAOA1gDWQNaBN |
|
|
3127 | AS6As4C3gMloAFMAYQB2AGUAIABBAHMgJlFTXxAPc2F2ZURvY3VtZW50QXM60wAOA1gDWQNaBO0E7oC7 | |
|
3128 | gQExgQE02AAOA14DXwNgA2EDYgNjA2QDZgTxA2gE8gNqA2sDbAPqgLmBATKBATOAs4C3gNpfEBRRdWl0 | |
|
3129 | IElQeXRob24xU2FuZGJveFFxWnRlcm1pbmF0ZTrTAA4DWANZA1oE+wT8gLuBATaBATnZAA4DXgNfA2AD | |
|
3130 | YQNiA2MDZANlA2YE/wPXBQADagNrA2wDbQFYgLmBATeBATiAs4C3gLBbU21hcnQgTGlua3NRR18QHXRv | |
|
3131 | Z2dsZUF1dG9tYXRpY0xpbmtEZXRlY3Rpb2461AAOBDIDWANZBDMENAUKBQuA94D0gQE7gQE90gAOADIA | |
|
3132 | MwUOgASBATxfEBpJUHl0aG9uMVNhbmRib3hBcHBEZWxlZ2F0ZV8QEWlweXRob25Db250cm9sbGVy0wAO | |
|
3133 | A1gDWQNaBRMFFIC7gQE/gQFB2AAOA14DXwNgA2EDYgNjA2QDZgUXA2gEJwNqA2sDbARWgLmBAUCA8YCz | |
|
3134 | gLeA/lRab29tXHBlcmZvcm1ab29tOtMADgNYA1kDWgUgBSGAu4EBQ4EBRtgADgNeA18DYANhA2IDYwNk | |
|
3135 | A2YFJANoBSUDagNrA2wDyIC5gQFEgQFFgLOAt4DPVENvcHlRY1Vjb3B5OtMADgNYA1kDWgUuBS+Au4EB | |
|
3136 |
|
|
|
3137 | cAU5BTqBAaCBAeeBAelcU2hvdyBUb29sYmFyUXRfEBN0b2dnbGVUb29sYmFyU2hvd2461AAOBDIDWANZ | |
|
3138 | BDMFCgVBBDaA94EBO4EBToD20gAOADIAMwA0gASAA9MADgNYA1kDWgVIBUmAu4EBUIEBUtgADgNeA18D | |
|
3139 | YANhA2IDYwNkA2YFTANoBCcDagNrA2wEKoC5gQFRgPGAs4C3gO9eU3RhcnQgU3BlYWtpbmdec3RhcnRT | |
|
3140 | cGVha2luZzrTAA4DWANZA1oFVQVWgLuBAVSBAVjYAA4DXgNfA2ADYQNiA2MDZANmBVkDaAVaA2oDawNs | |
|
3141 | BV2AuYEBVoEBV4CzgLeBAVXTAA4DXgNvA3AFYAVhgQGggQHxgQHzXxAUSVB5dGhvbjFTYW5kYm94IEhl | |
|
3142 | bHBRP1lzaG93SGVscDrTAA4DWANZA1oFZwVogLuBAVqBAV3YAA4DXgNfA2ADYQNiA2MDZANmBWsDaAQn | |
|
3143 | A2oDawNsBW+AuYEBXIDxgLOAt4EBW9QADgNeAdUDbwNwBXIFcwV0gQGggQGigQGlgQGkWkNsZWFyIE1l | |
|
3144 | bnVfEBVjbGVhclJlY2VudERvY3VtZW50czrTAA4DWANZA1oFeQV6gLuBAV+BAWHYAA4DXgNfA2ADYQNi | |
|
3145 | A2MDZANmBX0DaAQnA2oDawNsBTaAuYEBYIDxgLOAt4EBSW8QEgBDAHUAcwB0AG8AbQBpAHoAZQAgAFQA | |
|
3146 | bwBvAGwAYgBhAHIgJl8QH3J1blRvb2xiYXJDdXN0b21pemF0aW9uUGFsZXR0ZTrTAA4DWANZA1oFhgWH | |
|
3147 | gLuBAWOBAWbYAA4DXgNfA2ADYQNiA2MDZANmBYoDaAWLA2oDawNsA8iAuYEBZIEBZYCzgLeAz1NDdXRR | |
|
3148 | eFRjdXQ61AAOBDIDWANZBDMAyAQ0BZaA94AYgPSBAWhYdGV4dFZpZXfUAA4EMgNYA1kEMwDIAEEFnID3 | |
|
3149 | gBiAB4EBal8QFWluaXRpYWxGaXJzdFJlc3BvbmRlctMADgNYA1kDWgWgBaGAu4EBbIEBb9kADgWjA14D | |
|
3150 | XwNgA2EDYgNjA2QDZgQnBaYD1wWnA2oDawNsA7ZZTlNUb29sVGlwgLmA8YEBbYEBboCzgLeAyV1QYWdl | |
|
3151 | IFNldHVwLi4uUVBecnVuUGFnZUxheW91dDrTAA4DWANZA1oFsAWxgLuBAXGBAXTYAA4DXgNfA2ADYQNi | |
|
3152 | A2MDZANmBbQDaAW1A2oDawNsBJ+AuYEBcoEBc4CzgLeBARVuAFMAaABvAHcAIABTAHAAZQBsAGwAaQBu | |
|
3153 | AGcgJlE6XxAPc2hvd0d1ZXNzUGFuZWw60wAOA1gDWQNaBb4Fv4C7gQF2gQF41wAOA14DYANhA2IDYwNk | |
|
3154 | A2YFwgQnA2oDawNsA7aAuYEBd4DxgLOAt4DJXxAPUmV2ZXJ0IHRvIFNhdmVkXxAWcmV2ZXJ0RG9jdW1l | |
|
3155 | bnRUb1NhdmVkOtMADgNYA1kDWgXLBcyAu4EBeoEBfNgADgNeA18DYANhA2IDYwNkA2YFzwNoBCcDagNr | |
|
3156 | A2wEn4C5gQF7gPGAs4C3gQEVXxAbQ2hlY2sgR3JhbW1hciBXaXRoIFNwZWxsaW5nXxAWdG9nZ2xlR3Jh | |
|
3157 |
b |
|
|
3158 |
bmdfEBxOU05pYkJpbmRpbmdDb25uZWN0b3JWZXJzaW9ugQG |
|
|
3159 |
5AXlBeYF5wXoBekF6gB6BewAegXuAHoF8AX |
|
|
3160 |
dGlvbl8QFE5TUHJlc2VydmVzU2VsZWN0aW9uXE5TSW5pdGlhbEtleVpOU0VkaXRhYmxlXk5T |
|
|
3161 |
ZWRLZXlzXk5TSW5pdGlhbFZhbHVlXxAiTlNDbGVhcnNGaWx0ZXJQcmVkaWNhdGVPbkluc2Vy |
|
|
3162 |
GE5TU2VsZWN0c0luc2VydGVkT2JqZWN0c18QFk5TQXZvaWRzRW1wdHlTZWxlY3Rpb25fEBFO |
|
|
3163 |
ZXNjcmlwdG9ycwmBAYgJgQGBCYEBf4EBggkJCYEBg9IADgA+AGkF+IA0owX5Be4F |
|
|
3164 |
ZXlzU2tleVV2YWx1ZdIADgA+BgAGAYEBh6EGAoEBhNQADgYEBgUGBgYHBe4GCQB6VU5TS2V5 |
|
|
3165 |
ZWN0b3JbTlNBc2NlbmRpbmeBAYaBAYGBAYUJWGNvbXBhcmU60gA3ADgGDQYOogYOADtfEBBO |
|
|
3166 |
ZXNjcmlwdG9y0gA3ADgGEAE4ogE4ADvSADcAOAYSBhOlBhMGFAYVBhYAO18QFk5TRGljdGl |
|
|
3167 |
bnRyb2xsZXJfEBFOU0FycmF5Q29udHJvbGxlcl8QEk5TT2JqZWN0Q29udHJvbGxlclxOU0Nv |
|
|
3168 | ZXJfEBp2YWx1ZTogYXJyYW5nZWRPYmplY3RzLmtleV8QE2FycmFuZ2VkT2JqZWN0cy5rZXnSADcAOAYa | |
|
3169 | BhujBhsDiwA7XxAVTlNOaWJCaW5kaW5nQ29ubmVjdG9y1wAOBDIF1wXYA1gDWQXZBdoENAYfBiAF2wYi | |
|
3170 | AFWBAYuA9IEBj4EBjoEBfoEBjV8QGWNvbnRlbnREaWN0aW9uYXJ5OiB1c2VyTlNfEBFjb250ZW50RGlj | |
|
3171 | dGlvbmFyeVZ1c2VyTlPXAA4EMgXXBdgDWANZBdkF2gXbBikF3QJ2BiwAVYEBi4EBfoEBkoEBgoCLgQGR | |
|
3172 | XxAcdmFsdWU6IGFycmFuZ2VkT2JqZWN0cy52YWx1ZV8QFWFycmFuZ2VkT2JqZWN0cy52YWx1ZdcADgQy | |
|
3173 | BdcF2ANYA1kF2QXaBQoGMgYzBdsGNQBVgQGLgQE7gQGWgQGVgQF+gQGUXxApZmlsdGVyUHJlZGljYXRl | |
|
3174 | OiB3b3Jrc3BhY2VGaWx0ZXJQcmVkaWNhdGVfEA9maWx0ZXJQcmVkaWNhdGVfEBh3b3Jrc3BhY2VGaWx0 | |
|
3175 | ZXJQcmVkaWNhdGXXAA4EMgXXBdgDWANZBdkF2gQ0BjwGPQBsBj8AVYEBi4D0gQGagQGZgKOBAZhfEBlh | |
|
3176 | bmltYXRlOiB3YWl0aW5nRm9yRW5naW5lV2FuaW1hdGVfEBB3YWl0aW5nRm9yRW5naW5l0gAOAD4GAAZF | |
|
3177 | gQGHrxBnA1sGRwTfAkQCdQZLBIoEQQUgBW8GUATRBbAFywZUBFYFLgZXBYYGWQIKA20GXATtBl4GXwS3 | |
|
3178 | BmEGYgBNBdsAawVVBHsFoAZpBmoAyAUKBGEGbgSpBnAAbAZyBBUD9QIaA8gAfwPqAnYEIgZ7BJcGfQOO | |
|
3179 | Bn8GgAV5AioGgwSfAhAETgPSBogEBwCqBb4D4QaNBo4D/QLAA64AfgaTBG4FEwTEAKMFXQT7BpoGmwOg | |
|
3180 | BTYDlgafBWcEKgPABDQFQQKDAEEAsQaoBqkFSAO2BqyAr4EBnIEBLIB0gHyBAaGBARCA+YEBQ4EBW4EB | |
|
3181 | poEBJ4EBcYEBeoEBqoD+gQFIgQHDgQFjgQHwgG6AsIEB2YEBMYEBv4EBz4EBH4EB5oEB5IALgQF+gA6B | |
|
3182 | AVSBAQuBAWyBAbaBAbWAGIEBO4EBA4EB6oEBGoEBxoCjgQG9gOqA34CUgM+AaoDagIuA7oEBrYEBFIEB | |
|
3183 | y4C9gQHQgQHugQFfgHKBAbGBARWAloD9gNSBAdGA5YBYgQF2gNmBAdeBAbyA4ICOgMiAEIEB1YEBB4EB | |
|
3184 | P4EBI4AUgQFVgQE2gQHcgQGygMOBAUmAvoEB4IEBWoDvgM6A9IEBToCDgAeAVIEBuYEByoEBUIDJgQHJ | |
|
3185 | 2gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YEKgQtA2gEJwNqA2sDbAPIBrZZTlNTdWJtZW51gLmA74EBnYDx | |
|
3186 | gLOAt4DPgQGeVlNwZWVjaF5zdWJtZW51QWN0aW9uOtIADgA+AGkGu4A0ogVIBCKBAVCA7tIANwA4Br8D | |
|
3187 | ZKIDZAA72gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YFbwVyA2gEJwNqA2sDbAO2BsiAuYEBW4EBooDxgLOA | |
|
3188 | t4DJgQGjW09wZW4gUmVjZW500gAOAD4AaQbMgDShBWeBAVpfEBZfTlNSZWNlbnREb2N1bWVudHNNZW51 | |
|
3189 | 2gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YDbQNxA2gEJwNqA2sDbAPIBteAuYCwgQGngPGAs4C3gM+BAahd | |
|
3190 | U3Vic3RpdHV0aW9uc9IADgA+AGkG24A0owOgA1sE+4DDgK+BATbUAA4DXgHVA28DcAbhBuIG44EBoIEB | |
|
3191 | q4EB9IEBrFlBTWFpbk1lbnXSAA4APgBpBueANKcGewZeBn0GnwZhBm4GWYEBrYEBv4EBy4EB4IEB5oEB | |
|
3192 | 6oEB8NoADgauA14DXwNgA2EDYgNjA2QBoANmA+oD7QNoBCcDagNrA2wGVAb3gLmA2oEBroDxgLOAt4EB | |
|
3193 | qoEBr18QD0lQeXRob24xU2FuZGJveNIADgA+AGkG+4A0qwSKBoMGmwZqBmkGjgS3A+EEbgZyBO2BARCB | |
|
3194 | AbGBAbKBAbWBAbaBAbyBAR+A2YEBB4EBvYEBMdoADgNeA18HCANgBwkDYQNiA2MDZANmBCcDaAB6BCcA | |
|
3195 | egNqA2sDbAPqXU5TSXNTZXBhcmF0b3JcTlNJc0Rpc2FibGVkgLmA8QmA8QmAs4C3gNrYAA4DXgNfA2AD | |
|
3196 | YQNiA2MDZANmBxQDaAcVA2oDawNsA+qAuYEBs4EBtICzgLeA2mwAUAByAGUAZgBlAHIAZQBuAGMAZQBz | |
|
3197 |
|
|
|
3198 |
AA4G |
|
|
3199 | U2VydmljZXPUAA4DXgHVA28DcAcnBzEHMoEBoIEBt4EBu4EButIADgA+AGkHNYA0oF8QD19OU1NlcnZp | |
|
3200 | Y2VzTWVuddoADgNeA18HCANgBwkDYQNiA2MDZANmBCcDaAB6BCcAegNqA2sDbAPqgLmA8QmA8QmAs4C3 | |
|
3201 | gNraAA4DXgNfBwgDYAcJA2EDYgNjA2QDZgQnA2gAegQnAHoDagNrA2wD6oC5gPEJgPEJgLOAt4DaXF9O | |
|
3202 | U0FwcGxlTWVuddoADgauA14DXwNgA2EDYgNjA2QBoANmA7YDuQNoBCcDagNrA2wGVAdSgLmAyYEBwIDx | |
|
3203 | gLOAt4EBqoEBwVRGaWxl0gAOAD4AaQdWgDSrBlcGcAZLBqwEewOuBN8FvgapBaAE0YEBw4EBxoEBoYEB | |
|
3204 | yYEBC4DIgQEsgQF2gQHKgQFsgQEn2AAOA14DXwNgA2EDYgNjA2QDZgdkA2gHZQNqA2sDbAO2gLmBAcSB | |
|
3205 | AcWAs4C3gMlTTmV3UW7YAA4DXgNfA2ADYQNiA2MDZANmB20DaAduA2oDawNsA7aAuYEBx4EByICzgLeA | |
|
3206 | yWUATwBwAGUAbiAmUW/aAA4DXgNfBwgDYAcJA2EDYgNjA2QDZgQnA2gAegQnAHoDagNrA2wDtoC5gPEJ | |
|
3207 | gPEJgLOAt4DJ2gAOA14DXwcIA2AHCQNhA2IDYwNkA2YEJwNoAHoEJwB6A2oDawNsA7aAuYDxCYDxCYCz | |
|
3208 | gLeAydoADgauA14DXwNgA2EDYgNjA2QBoANmA8gDywNoBCcDagNrA2wGVAeOgLmAz4EBzIDxgLOAt4EB | |
|
3209 | qoEBzVRFZGl00gAOAD4AaQeSgDStA8AD0gZfBYYFIAQHBEEEqQZ/BogGmgZQBkeAzoDUgQHPgQFjgQFD | |
|
3210 | gOWA+YEBGoEB0IEB0YEB3IEBpoEBnNoADgNeA18HCANgBwkDYQNiA2MDZANmBCcDaAB6BCcAegNqA2sD | |
|
3211 | bAPIgLmA8QmA8QmAs4C3gM/aAA4DXgNfBwgDYAcJA2EDYgNjA2QDZgQnA2gAegQnAHoDagNrA2wDyIC5 | |
|
3212 | gPEJgPEJgLOAt4DP2gAOBq4DXgNfA2ADYQNiA2MDZAGgA2YDlgOZA2gEJwNqA2sDbAPIB7qAuYC+gQHS | |
|
3213 | gPGAs4C3gM+BAdNURmluZNIADgA+AGkHvoA0pQQVBpMGjQZcA46A6oEB1YEB14EB2YC92QAOA14DXwNg | |
|
3214 | A2EDYgNjA2QDZQNmB8YDaANpA2oDawNsA5YAVYC5gQHWgLKAs4C3gL5ZRmluZCBOZXh02QAOA14DXwNg | |
|
3215 | A2EDYgNjA2QDZQNmB84D1wUAA2oDawNsA5YBWIC5gQHYgQE4gLOAt4C+XUZpbmQgUHJldmlvdXPZAA4D | |
|
3216 | XgNfA2ADYQNiA2MDZANlA2YH1gNoB9cDagNrA2wDlgfbgLmBAdqBAduAs4C3gL4QB18QFlVzZSBTZWxl | |
|
3217 | Y3Rpb24gZm9yIEZpbmRRZdoADgauA14DXwNgA2EDYgNjA2QBoANmBJ8EogNoBCcDagNrA2wDyAfmgLmB | |
|
3218 | ARWBAd2A8YCzgLeAz4EB3l8QFFNwZWxsaW5nIGFuZCBHcmFtbWFy0gAOAD4AaQfqgDSkBbAElwTEBcuB | |
|
3219 | AXGBARSBASOBAXraAA4GrgNeA18DYANhA2IDYwNkAaADZgP9BAADaAQnA2oDawNsBlQH94C5gOCBAeGA | |
|
3220 | 8YCzgLeBAaqBAeJWRm9ybWF00gAOAD4AaQf7gDSiBmID9YEB5IDf2AAOA14DXwNgA2EDYgNjA2QDZggA | |
|
3221 | A2gFMwNqA2sDbAP9gLmBAeWBAUuAs4C3gOBaU2hvdyBGb250c9oADgauA14DXwNgA2EDYgNjA2QBoANm | |
|
3222 | BTYFOQNoBCcDagNrA2wGVAgOgLmBAUmBAeeA8YCzgLeBAaqBAehUVmlld9IADgA+AGkIEoA0ogUuBXmB | |
|
3223 | AUiBAV/aAA4GrgNeA18DYANhA2IDYwNkAaADZgRWBFkDaAQnA2oDawNsBlQIHYC5gP6BAeuA8YCzgLeB | |
|
3224 | AaqBAexWV2luZG930gAOAD4AaQghgDSkBE4FEwaABGGA/YEBP4EB7oEBA9oADgNeA18HCANgBwkDYQNi | |
|
3225 | A2MDZANmBCcDaAB6BCcAegNqA2sDbARWgLmA8QmA8QmAs4C3gP5eX05TV2luZG93c01lbnXaAA4GrgNe | |
|
3226 | A18DYANhA2IDYwNkAaADZgVdBWADaAQnA2oDawNsBlQIOIC5gQFVgQHxgPGAs4C3gQGqgQHyVEhlbHDS | |
|
3227 | AA4APgBpCDyANKEFVYEBVFtfTlNNYWluTWVuddIADgA+BgAIQYEBh68QZwNtA8gDtgIKAioDtgPqA8gD | |
|
3228 | yAZLA8gDtgSfBJ8AHwZuBTYDtgPIBlQAfwZQA5YD6gZUA8gD6gZUA/0AQQAfAE0FXQO2A7YD6gPqAKMA | |
|
3229 | HwRWBlQDyAO2AE0D6gOWA/0CCgZ9AGsGewIqBCoGVASfBlQDlgPIBFYFNgIKA+oGmgIKBFYDyAPIA8gA | |
|
3230 | owO2A+oDlgPqBp8CdgO2AGsDlgPqBFYEnwB+BlkDbQPIA+oDbQZhBogGVAVvBkcDyAAfAB8CdQAfAKMG | |
|
3231 | aQO2BCoGXgO2gLCAz4DJgG6AcoDJgNqAz4DPgQGhgM+AyYEBFYEBFYACgQHqgQFJgMmAz4EBqoBqgQGm | |
|
3232 | gL6A2oEBqoDPgNqBAaqA4IAHgAKAC4EBVYDJgMmA2oDagBSAAoD+gQGqgM+AyYALgNqAvoDggG6BAcuA | |
|
3233 | DoEBrYBygO+BAaqBARWBAaqAvoDPgP6BAUmAboDagQHcgG6A/oDPgM+Az4AUgMmA2oC+gNqBAeCAi4DJ | |
|
3234 | gA6AvoDagP6BARWAEIEB8ICwgM+A2oCwgQHmgQHRgQGqgQFbgQGcgM+AAoACgHyAAoAUgQG2gMmA74EB | |
|
3235 | v4DJ0gAOAD4GAAirgQGHrxBoA1sGRwTfAkQCdQZLBIoEQQUgBW8E0QZQBbAFywUuBlQEVgZXBYYGWQIK | |
|
3236 | A20GXATtBl4GXwS3BmEGYgBNBdsAawVVBHsFoAZpBmoAyAUKBGEGbgZwBKkAbAZyBBUD9QIaA8gD6gB/ | |
|
3237 | BCICdgZ7BJcGfQOOBn8GgAV5AioGgwSfAhAETgPSBogEBwCqBb4D4QaNBo4D/QLAA64AfgaTBG4FEwTE | |
|
3238 | AKMFXQT7AB8GmgabBTYDoAafA5YFZwQqBDQDwAVBAoMAQQCxBqkGqAVIA7YGrICvgQGcgQEsgHSAfIEB | |
|
3239 | oYEBEID5gQFDgQFbgQEngQGmgQFxgQF6gQFIgQGqgP6BAcOBAWOBAfCAboCwgQHZgQExgQG/gQHPgQEf | |
|
3240 | gQHmgQHkgAuBAX6ADoEBVIEBC4EBbIEBtoEBtYAYgQE7gQEDgQHqgQHGgQEagKOBAb2A6oDfgJSAz4Da | |
|
3241 | gGqA7oCLgQGtgQEUgQHLgL2BAdCBAe6BAV+AcoEBsYEBFYCWgP2A1IEB0YDlgFiBAXaA2YEB14EBvIDg | |
|
3242 | gI6AyIAQgQHVgQEHgQE/gQEjgBSBAVWBATaAAoEB3IEBsoEBSYDDgQHggL6BAVqA74D0gM6BAU6Ag4AH | |
|
3243 | gFSBAcqBAbmBAVCAyYEBydIADgA+BgAJFoEBh68QaAkXCRgJGQkaCRsJHAkdCR4JHwkgCSEJIgkjCSQJ | |
|
3244 | JQkmCScJKAkpCSoJKwksCS0JLgkvCTAJMQkyCTMJNAk1CTYJNwk4CTkJOgk7CTwFDgk+CT8JQAlBCUIJ | |
|
3245 | QwlECUUJRglHCUgJSQlKCUsJTAlNCU4JTwlQCVEJUglTCVQJVQlWCVcJWAlZCVoJWwlcCV0JXglfCWAJ | |
|
3246 | YQliCWMJZAllCWYJZwloCWkJaglrCWwJbQluCW8JcAlxCXIJcwl0CXUJdgl3CXgJeQl6CXsJfAl9CX6B | |
|
3247 | AfiBAfmBAfqBAfuBAfyBAf2BAf6BAf+BAgCBAgGBAgKBAgOBAgSBAgWBAgaBAgeBAgiBAgmBAgqBAguB | |
|
3248 | AgyBAg2BAg6BAg+BAhCBAhGBAhKBAhOBAhSBAhWBAhaBAheBAhiBAhmBAhqBAhuBAhyBAh2BATyBAh6B | |
|
3249 | Ah+BAiCBAiGBAiKBAiOBAiSBAiWBAiaBAieBAiiBAimBAiqBAiuBAiyBAi2BAi6BAi+BAjCBAjGBAjKB | |
|
3250 |
|
|
|
3251 |
AkeBAkiBAkmBAkqBAkuBAkyBAk2BAk6BAk+BAlCBAlGBAlKBAlOBAlSBAlWBAla |
|
|
3252 | AluBAlyBAl2BAl5fEBhNZW51IEl0ZW0gKFNtYXJ0IFF1b3RlcylfEBJNZW51IEl0ZW0gKFNwZWVjaClR | |
|
3253 | OF8QEVRhYmxlIEhlYWRlciBWaWV3XxAXVGFibGUgQ29sdW1uIChWYXJpYWJsZSlfEBdNZW51IEl0ZW0g | |
|
3254 | KE9wZW4gUmVjZW50KV8QIU1lbnUgSXRlbSAoQWJvdXQgSVB5dGhvbjFTYW5kYm94KV8QEk1lbnUgSXRl | |
|
3255 | bSAoRGVsZXRlKV8QEE1lbnUgSXRlbSAoQ29weSlfEBJNZW51IChPcGVuIFJlY2VudClRNl8QGU1lbnUg | |
|
3256 | SXRlbSAoU3Vic3RpdHV0aW9ucylvEBoATQBlAG4AdQAgAEkAdABlAG0AIAAoAFMAaABvAHcAIABTAHAA | |
|
3257 | ZQBsAGwAaQBuAGcgJgApXxAnTWVudSBJdGVtIChDaGVjayBHcmFtbWFyIFdpdGggU3BlbGxpbmcpXxAY | |
|
3258 | TWVudSBJdGVtIChTaG93IFRvb2xiYXIpWE1haW5NZW51XU1lbnUgKFdpbmRvdylROV8QD01lbnUgSXRl | |
|
3259 | bSAoQ3V0KVExW1Njcm9sbCBWaWV3XxAUTWVudSAoU3Vic3RpdHV0aW9ucylfECJNZW51IEl0ZW0gKFVz | |
|
3260 | ZSBTZWxlY3Rpb24gZm9yIEZpbmQpVDExMTFfEBBNZW51IEl0ZW0gKEZpbGUpW1NlcGFyYXRvci01XxAg | |
|
3261 | TWVudSBJdGVtIChIaWRlIElQeXRob24xU2FuZGJveClfEBBNZW51IEl0ZW0gKFZpZXcpXxAWTWVudSBJ | |
|
3262 | dGVtIChTaG93IEZvbnRzKVxDb250ZW50IFZpZXdfEBlVc2VyIE5hbWVzcGFjZSBDb250cm9sbGVyWlNw | |
|
3263 | bGl0IFZpZXdfECBNZW51IEl0ZW0gKElQeXRob24xU2FuZGJveCBIZWxwKVMxLTFRNV8QFE1lbnUgSXRl | |
|
3264 | bSAoU2VydmljZXMpW1NlcGFyYXRvci0xWVRleHQgVmlld18QHk1lbnUgSXRlbSAoQnJpbmcgQWxsIHRv | |
|
3265 | IEZyb250KV8QEk1lbnUgSXRlbSAoV2luZG93KW8QEQBNAGUAbgB1ACAASQB0AGUAbQAgACgATwBwAGUA | |
|
3266 | biAmAClfEBZNZW51IEl0ZW0gKFNlbGVjdCBBbGwpXEFzeW5jIEFycm93c1tTZXBhcmF0b3ItMm8QEQBN | |
|
3267 | AGUAbgB1ACAASQB0AGUAbQAgACgARgBpAG4AZCAmAClfEBdNZW51IEl0ZW0gKFNob3cgQ29sb3JzKV8Q | |
|
3268 | EVZlcnRpY2FsIFNjcm9sbGVyW01lbnUgKEVkaXQpXxAWTWVudSAoSVB5dGhvbjFTYW5kYm94KV8QD0Jv | |
|
3269 | eCAoV29ya3NwYWNlKV8QGU1lbnUgSXRlbSAoU3RvcCBTcGVha2luZylfEBRUYWJsZSBDb2x1bW4gKFZh | |
|
3270 | bHVlKV8QG01lbnUgSXRlbSAoSVB5dGhvbjFTYW5kYm94KV8QGk1lbnUgSXRlbSAoQ2hlY2sgU3BlbGxp | |
|
3271 | bmcpXxAQTWVudSBJdGVtIChFZGl0KV8QHU1lbnUgSXRlbSAoSnVtcCB0byBTZWxlY3Rpb24pW1NlcGFy | |
|
3272 | YXRvci02WVNlcGFyYXRvcm8QHgBNAGUAbgB1ACAASQB0AGUAbQAgACgAQwB1AHMAdABvAG0AaQB6AGUA | |
|
3273 | IABUAG8AbwBsAGIAYQByICYAKV8QHFRhYmxlIFZpZXcgKFZhcmlhYmxlLCBWYWx1ZSlbU2VwYXJhdG9y | |
|
3274 | LTNfEBtNZW51IChTcGVsbGluZyBhbmQgR3JhbW1hcilfEBNIb3Jpem9udGFsIFNjcm9sbGVyXxAUTWVu | |
|
3275 | dSBJdGVtIChNaW5pbWl6ZSlfEBBNZW51IEl0ZW0gKFJlZG8pXxAQTWVudSBJdGVtIChGaW5kKV8QEU1l | |
|
3276 | bnUgSXRlbSAoUGFzdGUpXxAVSG9yaXpvbnRhbCBTY3JvbGxlci0xUjEwXxAXTWVudSBJdGVtIChIaWRl | |
|
3277 | IE90aGVycylfEBlNZW51IEl0ZW0gKEZpbmQgUHJldmlvdXMpW1NlcGFyYXRvci00XU1lbnUgKEZvcm1h | |
|
3278 | dClfEB1UZXh0IEZpZWxkIENlbGwgKFRleHQgQ2VsbCktMVEzXUJveCAoQ29uc29sZSlfEBVNZW51IEl0 | |
|
3279 | ZW0gKEZpbmQgTmV4dClfEBRNZW51IEl0ZW0gKFNob3cgQWxsKV8QEE1lbnUgSXRlbSAoWm9vbSlfECdN | |
|
3280 | ZW51IEl0ZW0gKENoZWNrIFNwZWxsaW5nIFdoaWxlIFR5cGluZyldU2Nyb2xsIFZpZXctMVEyXxAXTWVu | |
|
3281 | dSBJdGVtIChTbWFydCBMaW5rcylcRmlsZSdzIE93bmVyXxAgTWVudSBJdGVtIChTcGVsbGluZyBhbmQg | |
|
3282 | R3JhbW1hcilTMTIxW01lbnUgKFZpZXcpXxAcTWVudSBJdGVtIChTbWFydCBDb3B5L1Bhc3RlKV8QEk1l | |
|
3283 | bnUgSXRlbSAoRm9ybWF0KVtNZW51IChGaW5kKV8QFk1lbnUgSXRlbSAoQ2xlYXIgTWVudSldTWVudSAo | |
|
3284 | U3BlZWNoKV8QF1B5dGhvbiBDb2NvYSBDb250cm9sbGVyXxAQTWVudSBJdGVtIChVbmRvKVtBcHBsaWNh | |
|
3285 | dGlvbl8QG1RleHQgRmllbGQgQ2VsbCAoVGV4dCBDZWxsKV8QGVdpbmRvdyAoSVB5dGhvbjEgKENvY29h | |
|
3286 | KSlfEBNWZXJ0aWNhbCBTY3JvbGxlci0xUzItMV8QD01lbnUgKFNlcnZpY2VzKV8QGk1lbnUgSXRlbSAo | |
|
3287 | U3RhcnQgU3BlYWtpbmcpW01lbnUgKEZpbGUpUTfSAA4APgYACeiBAYeg0gAOAD4GAAnrgQGHoNIADgA+ | |
|
3288 | BgAJ7oEBh68QlwNUA1sGRwNBA0kE3wJEAnUGSwSKBEEFIAVvA0IGUATRA0QDMgNOBbADMQNRA0sFywM+ | |
|
3289 | AzoGVARWBS4GVwNNBYYGWQMwAgoDbQZcBO0GXgZfAzkDOAS3AywDTAZhBmIDLwBNBdsDQAM0AGsFVQR7 | |
|
3290 | BaAGaQZqAMgDKwUKBGEGbgSpBnAAbANHBnIEFQP1AhoDyAB/A+oCdgQiAz8GewSXBn0DjgZ/A0oDVgaA | |
|
3291 | A1UFeQIqA0MGgwSfAhADKgROA9IGiAQHAKoDOwNIBb4D4QaNAzYDPAaOA0UD/QMoAsADrgMzAH4GkwRu | |
|
3292 | BRMExACjA1IDKQVdBPsAHwaaBpsDoAU2A5YGnwMuBWcDUAQqA8AENANGBUEDNQKDA08AQQCxBqgGqQM3 | |
|
3293 | Az0DUwMtBUgDtgasgQGQgK+BAZyBATWBAVmBASyAdIB8gQGhgQEQgPmBAUOBAVuBATqBAaaBASeBAUKA | |
|
3294 | 7YEBa4EBcYDpgQF5gQFigQF6gQEmgQETgQGqgP6BAUiBAcOBAWmBAWOBAfCA5IBugLCBAdmBATGBAb+B | |
|
3295 | Ac+BAQ+BAQqBAR+AzYEBZ4EB5oEB5IDegAuBAX6BATCA+IAOgQFUgQELgQFsgQG2gQG1gBiAx4EBO4EB | |
|
3296 | A4EB6oEBGoEBxoCjgQFPgQG9gOqA34CUgM+AaoDagIuA7oEBK4EBrYEBFIEBy4C9gQHQgQFegQGXgQHu | |
|
3297 | gQGTgQFfgHKBAT6BAbGBARWAloDCgP2A1IEB0YDlgFiBARmBAVOBAXaA2YEB14EBAoEBHoEBvIEBR4Dg | |
|
3298 | gK6AjoDIgPOAEIEB1YEBB4EBP4EBI4AUgQF9gLyBAVWBATaAAoEB3IEBsoDDgQFJgL6BAeCA2IEBWoEB | |
|
3299 | dYDvgM6A9IEBTYEBToD8gIOBAXCAB4BUgQG5gQHKgQEGgQEigQGMgNOBAVCAyYEBydIADgA+BgAKiIEB | |
|
3300 | h68QlwqJCooKiwqMCo0KjgqPCpAKkQqSCpMKlAqVCpYKlwqYCpkKmgqbCpwKnQqeCp8KoAqhCqIKowqk | |
|
3301 | CqUKpgqnCqgKqQqqCqsKrAqtCq4KrwqwCrEKsgqzCrQKtQq2CrcKuAq5CroKuwq8Cr0Kvgq/CsAKwQrC | |
|
3302 | CsMKxArFCsYKxwrICskKygrLCswKzQrOCs8K0ArRCtIK0wrUCtUK1grXCtgK2QraCtsK3ArdCt4K3wrg | |
|
3303 | CuEK4grjCuQK5QrmCucK6ArpCuoK6wrsCu0K7grvCvAK8QryCvMK9Ar1CvYK9wr4CvkK+gr7CvwK/Qr+ | |
|
3304 | Cv8LAAsBCwILAwsECwULBgsHCwgLCQsKCwsLDAsNCw4LDwsQCxELEgsTCxQLFQsWCxcLGAsZCxoLGwsc | |
|
3305 | Cx0LHgsfgQJjgQJkgQJlgQJmgQJngQJogQJpgQJqgQJrgQJsgQJtgQJugQJvgQJwgQJxgQJygQJzgQJ0 | |
|
3306 | gQJ1gQJ2gQJ3gQJ4gQJ5gQJ6gQJ7gQJ8gQJ9gQJ+gQJ/gQKAgQKBgQKCgQKDgQKEgQKFgQKGgQKHgQKI | |
|
3307 | gQKJgQKKgQKLgQKMgQKNgQKOgQKPgQKQgQKRgQKSgQKTgQKUgQKVgQKWgQKXgQKYgQKZgQKagQKbgQKc | |
|
3308 | gQKdgQKegQKfgQKggQKhgQKigQKjgQKkgQKlgQKmgQKngQKogQKpgQKqgQKrgQKsgQKtgQKugQKvgQKw | |
|
3309 | gQKxgQKygQKzgQK0gQK1gQK2gQK3gQK4gQK5gQK6gQK7gQK8gQK9gQK+gQK/gQLAgQLBgQLCgQLDgQLE | |
|
3310 | gQLFgQLGgQLHgQLIgQLJgQLKgQLLgQLMgQLNgQLOgQLPgQLQgQLRgQLSgQLTgQLUgQLVgQLWgQLXgQLY | |
|
3311 | gQLZgQLagQLbgQLcgQLdgQLegQLfgQLggQLhgQLigQLjgQLkgQLlgQLmgQLngQLogQLpgQLqgQLrgQLs | |
|
3312 | gQLtgQLugQLvgQLwgQLxgQLygQLzgQL0gQL1gQL2gQL3gQL4gQL5EQGrEQFfENMRAWUQfxBQEQGYEQGc | |
|
3313 | EHwQOhDKEMUQfREBuREBXBBOEOAQ4xBXEMwQ8REBWxDkEQFaEFYQ4RAdEBgRASkQUhEBvRDHEGcQ4hEB | |
|
3314 | lxEBXRDdEIgQUxDOEI4QwRCGEN8RAbwRAScRAVgRAWkRAXQRAYERAXEQ6xEBpRBvEEkQTRCDEI8RAaMR | |
|
3315 | AWoRAXUQBRATEMYQSBEBtBDpEJUQ0REBWREBmRDNEQGWEDkRAZ0QwxEBaxA4EMkQ2RDSENYRAW0RAbUQ | |
|
3316 | XBEBuBEBKhEBmxDwEOwQyBEBmhEBYxAXENcQ2hDLEQGiEOgRAWgQcBCRENUQJxEBbxCQEQFuEQEsEQFk | |
|
3317 | EQGeEEsRAa0RAaQQ0BCWEO8Q2xEBoBEBrBD1EGoRAWIRAb4Q2BCBEQFeEQEoENwRASsRAXAQfhEBbBDU | |
|
3318 | EM8RAaYRAXYT//////////0QJREBnxDmEQFzEQGhEIIQShEBchDeEQGoEOcQxBBREE/SAA4APgBpC7mA | |
|
3319 | NKDSAA4APgYAC7yBAYeg0gAOAD4GAAu/gQGHoNIANwA4C8ELwqILwgA7Xk5TSUJPYmplY3REYXRhAAgA | |
|
3320 | GQAiACcAMQA6AD8ARABSAFQAZgZmBmwGtwa+BsUG0wblBwEHDwcbBycHNQdAB04Hagd4B4sHnQe3B8EH | |
|
3321 | zgfQB9MH1gfZB9wH3gfhB+MH5gfpB+wH7wfxB/MH9gf5B/wH/wgICBQIFggYCCYILwg4CEMISAhXCGAI | |
|
3322 | cwh8CIcIiQiMCI4IuwjICNUI6wj5CQMJEQkeCTAJRAlQCVIJVAlWCVgJWglfCWEJYwllCWcJaQmECZcJ | |
|
3323 | oAm9Cc8J2gnjCe8J+wn9Cf8KAQoECgYKCAoKChMKFQoaChwKHgpHCk8KXgptCnoKfAp+CoAKggqFCocK | |
|
3324 | iQqLCowKlQqXCpwKngqgCtkK4wrvCv0LCgsUCyYLNAs2CzgLOgs8Cz0LPwtBC0MLRQtHC0kLSwtNC1YL | |
|
3325 | WAtbC10Legt8C34LgAuCC4QLhguPC5ELlAuWC8cL0wvcC+gL9gv4C/oL/Av+DAEMAwwFDAcMCQwLDA0M | |
|
3326 | FgwYDB8MIQwjDCUMWgxjDGwMdgyADIoMjAyODJAMkgyUDJYMmAybDJ0MnwyhDKMMpQyuDLAMswy1DOoM | |
|
3327 | /A0GDRMNHw0pDTINPQ0/DUENQw1FDUcNSQ1LDU4NUA1SDVQNVg1YDWENYw2IDYoNjA2ODZANkg2UDZYN | |
|
3328 | mA2aDZwNng2gDaINpA2mDagNqg3GDdsN+A4ZDjUOWw6BDp8Ouw7XDvQPDA8mD1oPdw+TD8APyQ/QD90P | |
|
3329 | 4w/6EA8QGRAkECwQPhBAEEIQSxBNEGIQdRCDEI0QjxCREJMQlRCiEKsQrRCvELEQuhDEEMYQxxDQENcQ | |
|
3330 | 6RDyEPsRFxEsETURNxE6ETwRRRFMEVsRYxFsEXERehF/EaARqBHCEdUR6RIAEhUSKBIqEi8SMRIzEjUS | |
|
3331 | NxI5EjsSSBJVElsSXRJ4EoEShhKOEpsSoxKlEqcSqhK3Er8SwRLGEsgSyhLPEtES0xLoEvQTAhMEEwYT | |
|
3332 | CBMKExETLxM8Ez4TShNfE2ETYxNlE2cTexOEE4kTlhOjE6UTqhOsE64TsxO1E7cTwxPQE9IT2RPiE+cT | |
|
3333 | /hQLFBMUHBQnFC4UNRRBFFgUcBR9FH8UghSPFJkUphSoFKoUshS7FMAUyRTSFN0VAhULFRQVHhUgFSIV | |
|
3334 | JBUmFS8VMRUzFTUVPhVWFWMVbBV3FYIVjBW5FcQVxhXIFcoVzBXOFdAV0hXbFeQV/xYYFiEWKhY3Fk4W | |
|
3335 | VxZeFmkWcBaNFpkWpBauFrsWxxbMFs4W0BbSFtQW1hbeFu8W9hb9FwYXCBcRFxMXFhcjFywXMRc4F00X | |
|
3336 | TxdRF1MXVRdrF3gXeheIF5EXmhesF7kXwBfJF9IX2BgRGBMYFRgXGBkYGhgcGB4YIBgiGCQYJhgvGDEY | |
|
3337 | NBg2GFMYVRhXGFkYWxhdGF8YaBhqGG0YbxiuGLsYzhjbGN0Y3xjhGOMY5RjnGOkY6xj+GQAZAhkEGQYZ | |
|
3338 | CBkRGRMZHhkgGSIZJBkmGSgZVRlXGVkZWxldGV8ZYRljGWUZZxlwGXIZdRl3Gc4Z8Bn6GgcaHBo2GlIa | |
|
3339 | bRp3GoMalRqkGsMazxrRGtMa3BreGuAa4RrjGuwa9Rr3Gvga+hr8Gv4bABsJGxQbMRs9Gz8bQRtDG0Ub | |
|
3340 | RxtJG3YbeBt6G3wbfhuAG4IbhBuGG4gbkhubG6QbuBvRG9Mb1RvXG9kb2xvyG/scBBwSHBscHRwiHCQc | |
|
3341 | JhxPHF4caxx2HIUckBybHKgcqRyrHK0cthy4HMEcyhzLHM0c6hzvHPEc8xz1HPcc+R0CHQ8dER0dHTId | |
|
3342 | NB02HTgdOh1MHVUdYB10HZUdox2oHaodrB2uHbAdsh21HbcdwR3SHdQd3R3fHeId9x35Hfsd/R3/Hhge | |
|
3343 | LR4vHjEeMx41HkgeUR5WHmQejR6OHpAekh6bHp0enh6gHr0evx7BHsMexR7HHs0e7h7wHvIe9B72Hvge | |
|
3344 | +h8PHxEfEx8VHxcfIR8uHzAfNR8+H0kfYR+GH4gfih+MH44fkB+SH5QfnR+2H98f4R/jH+Uf5x/pH+sf | |
|
3345 | 7R/2IA4gFyAZIBwgHiA0IE0gZCB9IJognCCeIKAgoiCkIK4guyC9INYg+SECIQshFyFAIUshViFgIW0h | |
|
3346 | byFxIXMhfCGFIYghiiGNIY8hkSGWIZghoSGmIbEhySHSIdsh8SH8IhQiJyIwIjUiSCJRIlMitCK2Irgi | |
|
3347 | uiK8Ir4iwCLCIsQixiLIIsoizCLOItAi0yLWItki3CLfIuIi5SLoIusi7iLxIvQi9yL6Iv0jACMDIwYj | |
|
3348 | CSMMIw8jEiMVIxgjGyMeIyEjJCMnIyojLSMwIzMjQCNJI1EjUyNVI1cjfCOEI5gjoyOxI7sjyCPPI9Uj | |
|
3349 | 1yPZI94j4CPlI+cj6SPrI/gkBCQHJAokDSQaJBwkKSQ4JDokPCQ+JEYkWCRhJGYkeSSGJIgkiiSMJJ8k | |
|
3350 | qCStJLgk3CTlJOwlBCUTJSAlIiUkJSYlRyVJJUslTSVPJVElUyVgJWMlZiVpJX0lfyWfJawlriWwJbIl | |
|
3351 | 1yXZJdsl3SXfJeEl4yX2JfgmEyYgJiImJCYmJkcmSSZLJk0mTyZRJlMmYCZjJmYmaSZuJnAmfiaLJo0m | |
|
3352 | jyaRJrImtCa2Jrgmuia8Jr4myybOJtEm1CbZJtsm4SbuJvAm8ib0JxUnFycZJx4nICciJyQnJicrJy0n | |
|
3353 | MydAJ0InRCdGJ2cnaSdrJ3Ancid0J3YneCeJJ4wnjyeSJ5UnoSejJ7wnySfLJ80nzyfwJ/In9Cf2J/gn | |
|
3354 | +if8KAkoDCgPKBIoHiggKDgoRShHKEkoSyhsKG4ocChyKHQodih4KH4ogCiHKJQoliiYKJoovyjBKMMo | |
|
3355 | xSjHKMkoyyjWKPAo/Sj/KQEpAykkKSYpKCkqKSwpLikwKT0pQClDKUYpVCliKXMpgSmDKYUphymJKZIp | |
|
3356 | lCmWKa8puCnBKcgp3ynsKe4p8CnyKhMqFSoXKhkqGyodKh8qJiouKjsqPSo/KkIqYyplKmcqaipsKm4q | |
|
3357 | cCqBKoQqhyqKKo0qliqYKq4quyq9KsAqwyrkKuYq6SrrKu0q7yrxKwYrGCslKycrKistK04rUCtTK1Ur | |
|
3358 | VytZK1srZCt9K4orjCuPK5Irsyu1K7gruyu9K78rwSvHK8kr1yvoK+or7CvvK/IsDywRLBQsFiwYLBos | |
|
3359 | HCw0LFQsYSxjLGYsaSyKLIwsjyySLJQsliyZLKYsqSysLK8svizALM8s3CzeLOEs5C0FLQctCi0NLQ8t | |
|
3360 | ES0TLR4tIC0rLTgtOi09LUAtYS1jLWYtaC1qLWwtbi2FLYstmC2aLZ0toC3BLcMtxi3ILcotzC3PLe0u | |
|
3361 | Di4bLh0uIC4jLkQuRi5JLkwuTi5QLlIuXy5hLmgudS53LnoufS6eLqAuoy6mLqguqi6sLr0uvy7RLt4u | |
|
3362 | 4C7jLuYvBy8JLwwvDy8RLxMvFS8sLy4vOS9GL0gvSy9OL3MvdS94L3svfS9/L4EvjS+PL68vwC/CL8Qv | |
|
3363 | xy/KL9Mv1S/YL/UwCTAWMBgwGzAeMD8wQTBEMEYwSDBKMEwwUTBeMGswbTBwMHMwlDCWMJkwnDCeMKAw | |
|
3364 | ojCnMKkwrzC8ML4wwTDEMOUw5zDqMO0w7zDxMPQxATEEMQcxCjEXMRkxLzFAMUIxRTFIMUoxUzFVMVcx | |
|
3365 | ZDFmMWkxbDGNMY8xkjGUMZYxmDGaMakxuDHFMccxyjHNMe4x8DHzMfYx+DH6Mf0yCjINMhAyEzIqMiwy | |
|
3366 | NjJDMkUySDJLMmwybjJxMnMydTJ3MnoyizKOMpEylDKXMqIyujLHMskyzDLPMvAy8jL1Mvcy+TL7Mv4z | |
|
3367 | JTNHM1QzVjNZM1wzfTN/M4IzhTOHM4kzizOPM5EzljOnM6kzqzOtM7AzuTPKM8wzzjPQM9Mz6zP4M/oz | |
|
3368 | /TQANCU0LzQxNDM0NjQ5NDs0PTQ/NE00TzReNGs0bTRwNHM0lDSWNJk0nDSeNKA0ozTANMI01DThNOM0 | |
|
3369 | 5jTpNQY1CDULNQ01DzURNRM1JTU+NUs1TTVQNVM1dDV2NXk1ezV9NX81gjWgNbk11jXgNeo2CTYMNg82 | |
|
3370 | EjYVNhc2GjZHNmQ2ezaINpM2ojaxNtY28TcKNx43HzciNyM3JjcnNyo3LTcuNy83MDczNzw3PjdFN0g3 | |
|
3371 | SzdON1M3VzddN2Y3aTdsN283gDeGN5E3nTegN6M3pjenN7A3uTe+N9E32jffN+g38zgMOCA4NThCOF84 | |
|
3372 | dTh+OIU4nTi6OL04vzjCOMU4yDjLOOc4+zkCOR85IjklOSg5KzktOTA5TzlnOYQ5hzmKOY05kDmTOZY5 | |
|
3373 | wjnUOe86DDoPOhE6FDoXOhk6HDo4OkA6UzpcOl87MDsyOzU7ODs6Ozw7PztCO0Q7RztKO007UDtTO1Y7 | |
|
3374 | WTtbO147YTtkO2c7aTtrO247cTt0O3c7ejt9O4A7gjuFO4c7ijuNO5A7kzuWO5g7mzueO6E7pDunO6k7 | |
|
3375 | rDuuO7A7sju0O7Y7uDu6O7w7vzvCO8U7xzvKO8070DvSO9U72DvaO9w73jvhO+M75TvoO+o77TvwO/I7 | |
|
3376 | 9Dv2O/g7+zv+PAE8BDwGPAk8DDwPPBI8FDwXPBk8HDwfPCE8IzwlPCg8KjwsPC48MTw0PDc8OTw8PGU8 | |
|
3377 | bzxxPHM8djx4PHo8fDx+PIE8iDyXPKA8ojynPKo8rDy1PLo84zzlPOg86zztPO888TzzPPY9Aj0LPQ09 | |
|
3378 | ED0TPSw9VT1XPVk9XD1ePWA9Yj1kPWc9dT1+PYA9hz2JPYs9jj2fPaI9pT2oPas9tT2+PcA9zz3SPdU9 | |
|
3379 | 2D3bPd494T3kPg0+Dz4RPhQ+Fj4YPho+HT4gPjI+Oz49PlQ+Vz5aPl0+YD5jPmY+aT5rPm4+cT50Pp0+ | |
|
3380 | qz64Pro+vD69Pr8+wD7CPsQ+xj7nPuk+7D7vPvE+8z71Pw4/ED85Pzs/PT8+P0A/QT9DP0U/Rz9wP3I/ | |
|
3381 | dT94P3o/fD9+P4A/gz+MP50/oD+jP6Y/qT+yP7Q/tT/HP/A/8j/0P/U/9z/4P/o//D/+QCdAKUArQCxA | |
|
3382 | LkAvQDFAM0A1QEJAa0BtQG9AckB0QHZAeEB7QH5Ag0CMQI5ApUCoQKtArkCxQLRAtkC5QLxAv0DCQMVA | |
|
3383 | 5kDoQOtA7kDwQPJA9ED4QPpBG0EdQSBBI0ElQSdBKUE0QTZBX0FhQWNBZEFmQWdBaUFrQW1BlkGYQZpB | |
|
3384 | m0GdQZ5BoEGiQaRBzUHPQdFB1EHWQdhB2kHdQeBB5UHuQfBCC0INQg9CEkIVQhhCGkIcQh9CIkIlQihC | |
|
3385 | K0IuQldCWUJbQlxCXkJfQmFCY0JlQo5CkEKSQpNClUKWQphCmkKcQsVCx0LJQsxCzkLQQtJC1ELXQtxC | |
|
3386 | 5ULnQvJC9EL3QvpC/UL/QyRDJkMpQytDLUMvQzFDO0NgQ2JDZUNoQ2pDbENuQ3xDoUOjQ6ZDqUOrQ61D | |
|
3387 | r0OxQ8pDzEP1Q/dD+kP9Q/9EAUQDRAVECEQfRChEKkQzRDZEOUQ8RD9EaERqRGxEb0RxRHNEdUR4RHtE | |
|
3388 | gkSLRI1EkkSVRJdEuES6RL1EwETCRMRExkTRRPpE/ET/RQJFBEUGRQhFC0UORRNFHEUeRSNFJkUpRVJF | |
|
3389 | VEVWRVlFW0VdRV9FYkVlRWxFdUV3RYBFgkWFRYhFi0W0RbZFuEW5RbtFvEW+RcBFwkXRRfpF/EX/RgJG | |
|
3390 | BEYGRghGC0YORhNGHEYeRiFGJEYwRjlGPEcNRw9HEUcTRxVHF0cZRxtHHUcfRyJHJEcmRylHLEcuRzFH | |
|
3391 |
|
|
|
3392 | dkd4R3tHfUeAR4JHhEeHR4pHjUePR5FHk0eWR5hHmkedR59HoUejR6VHp0epR6tHrUevR7FHtEe2R7hH | |
|
3393 | uke8R75HwEfDR8VHyEfKR8xHzkfQR9NH1kfZR9xH30fhR+NH5UfnR+lH60fuR/BH8kf1R/dIAEgDSNZI | |
|
3394 | 2EjbSN5I4EjiSOVI6EjqSO1I8EjzSPZI+Uj8SP9JAkkESQdJCkkNSQ9JEUkUSRdJGkkdSSBJI0kmSShJ | |
|
3395 | K0ktSTBJM0k2STlJPEk+SUFJRElHSUpJTUlPSVJJVElWSVhJWklcSV5JYEliSWVJaElrSW1JcElzSXZJ | |
|
3396 | eEl7SX5JgEmCSYRJh0mJSYtJjkmQSZNJlkmYSZpJnEmeSaFJpEmnSapJrEmvSbJJtEm3SbpJvUm/ScJJ | |
|
3397 | xEnHSclJy0nNSdBJ0knUSdZJ2UncSd9J4UnkSe1J8ErDSsZKyUrMSs9K0krVSthK20reSuFK5ErnSupK | |
|
3398 | 7UrwSvNK9kr5SvxK/0sCSwVLCEsLSw5LEUsUSxdLGksdSyBLI0smSylLLEsvSzJLNUs4SztLPktBS0RL | |
|
3399 | R0tKS01LUEtTS1ZLWUtcS19LYktlS2hLa0tuS3FLdEt3S3pLfUuAS4NLhkuJS4xLj0uSS5VLmEubS55L | |
|
3400 |
oUukS6dLqkutS7BLs0u2S7lLvEu/S8JLxUvIS8tLzkvRS9RL10vaS91L4EvjS+ZL6UvsS+9L8kv1 |
|
|
3401 | +0wWTCtMLUxBTFtMdUyZTK5MwUzWTNhM9E0rTVVNcE15TYdNiU2bTZ1NqU3ATeVN6k39TglOLE4/TlhO | |
|
3402 | ZU6BToxOr06zTrVOzE7YTuJPA08YTz1PVk9jT29PlE+uT8JPzk/nT/lQFVAsUEpQZ1B6UJpQplCwUO9R | |
|
3403 | DlEaUThRTlFlUXhRi1GfUbdRulHUUfBR/FIKUipSLFI6UlJSaVJ8UqZStFK2UtBS3VMAUwRTEFMvU0RT | |
|
3404 | UFNpU3dTkVOkU7BTzlPqVABUBFQWVDNUP1RBVEpUTVROVFdUWlRbVGRUZ1WYVZtVnVWgVaNVplWpVatV | |
|
3405 | rVWwVbNVtVW4VbtVvlXBVcRVx1XJVcxVz1XRVdRV11XaVd1V4FXjVeVV6FXrVe5V8VX0VfZV+FX6Vf1W | |
|
3406 |
|
|
|
3407 | UlZUVlZWWFZaVlxWXlZgVmJWZVZoVmtWblZwVnNWdlZ5VnxWf1aCVoRWh1aKVo1Wj1aRVpNWlVaYVppW | |
|
3408 | nFafVqJWpVanVqpWrVawVrNWtla4VrpWvFa+VsBWwlbFVshWy1bOVtBW01bVVthW21bdVuBW41blVuhW | |
|
3409 | 6lbtVu9W8lb1VvdW+Vb7Vv5XAVcDVwVXCFcKVwxXD1cSVxVXGFcbVx1XIFciVyVXLlcxWGJYZVhoWGtY | |
|
3410 | blhxWHRYd1h6WH1YgFiDWIZYiViMWI9YkliVWJhYm1ieWKFYpFinWKpYrViwWLNYtli5WLxYv1jCWMVY | |
|
3411 | yFjLWM5Y0VjUWNdY2ljdWOBY41jmWOlY7FjvWPJY9Vj4WPtY/lkBWQRZB1kKWQ1ZEFkTWRZZGVkcWR9Z | |
|
3412 | IlklWShZK1kuWTFZNFk3WTpZPVlAWUNZRllJWUxZT1lSWVVZWFlbWV5ZYVlkWWdZalltWXBZc1l2WXlZ | |
|
3413 | fFl/WYJZhVmIWYtZjlmRWZRZl1maWZ1ZoFmjWaZZqVmsWa9Zslm1WbhZu1m+WcFZxFnHWcpZzVnQWdNZ | |
|
3414 | 1lnZWdxZ31niWeVZ6FnrWe5Z8Vn0WfdZ+ln9WgBaA1oGWglaDFoPWhJaFVoYWhtaHlohWiRaJ1oqWi1a | |
|
3415 | L1oyWjRaNlo5WjxaPlpAWkJaRFpGWklaTFpOWlBaUlpUWlZaWFpbWl1aYFpiWmRaZlpoWmtabVpwWnJa | |
|
3416 | dFp2WnlafFp+WoBaglqEWoZaiFqKWoxaj1qSWpVamFqbWp5aoVqjWqZaqFqqWqxarlqwWrNatlq5Wrta | |
|
3417 | vVq/WsFaxFrGWshaylrNWtBa0lrVWtda2lrcWt9a4VrjWuVa51rpWuxa71rxWvRa91r6Wvxa/lsAWwNb | |
|
3418 | BlsIWwpbDFsOWxFbE1sWWxhbGlscWx5bIVsjWyZbKVssWy9bMVs0WzdbOVs7Wz1bP1tCW0VbR1tJW0xb | |
|
3419 |
|
|
|
3420 |
|
|
|
3076 | A1UDVoCugLyAwoDIgM6A1IDZgN+A44DogOyA8YD2gPuBAQGBAQaBAQqBAQ+BARWBARqBAR+BASWBASqB | |
|
3077 | AS+BATWBATmBAT2BAUKBAUOBAUiBAUqBAU+BAVSBAViBAVyBAV6BAWKBAWaBAWqBAW6BAXOBAXiBAX2B | |
|
3078 | AY2BAZGBAZSBAZfTAA4DWANZA1oDWwNcWE5TU291cmNlV05TTGFiZWyAu4CvgLrYAA4DXgNfA2ADYQNi | |
|
3079 | A2MDZANlA2YDZwNoA2kDagNrA2xXTlNUaXRsZV8QEU5TS2V5RXF1aXZNb2RNYXNrWk5TS2V5RXF1aXZd | |
|
3080 | TlNNbmVtb25pY0xvY1lOU09uSW1hZ2VcTlNNaXhlZEltYWdlVk5TTWVudYC5gLESABAAAICyEn////+A | |
|
3081 | s4C3gLDUAA4DXgHVA24DbwNwA3EDcltOU01lbnVJdGVtc4EBpIEByoEB2YEBzFhTaG93IEFsbNMADgAy | |
|
3082 | A3UDdgN3A3heTlNSZXNvdXJjZU5hbWWAtoC0gLVXTlNJbWFnZV8QD05TTWVudUNoZWNrbWFya9IANwA4 | |
|
3083 | A3wDfaIDfQA7XxAQTlNDdXN0b21SZXNvdXJjZdMADgAyA3UDdgN3A4GAtoC0gLhfEBBOU01lbnVNaXhl | |
|
3084 | ZFN0YXRl0gA3ADgDhAOFogOFADtaTlNNZW51SXRlbV8QFnVuaGlkZUFsbEFwcGxpY2F0aW9uczrSADcA | |
|
3085 | OAOIA4mjA4kDigA7XxAVTlNOaWJDb250cm9sQ29ubmVjdG9yXk5TTmliQ29ubmVjdG9y0wAOA1gDWQNa | |
|
3086 | A40DjoC7gL2AwdgADgNeA18DYANhA2IDYwNkA2UDkQNnA5IDaQNqA2sDlYC5gL+AwICzgLeAvtMADgNe | |
|
3087 | A24DbwOYA5mBAaSBAauBAa1eQ2hlY2sgU3BlbGxpbmdRO15jaGVja1NwZWxsaW5nOtMADgNYA1kDWgOf | |
|
3088 | A6CAu4DDgMfYAA4DXgNfA2ADYQNiA2MDZANlA6MDZwOkA2kDagNrA6eAuYDFgMaAs4C3gMTTAA4DXgNu | |
|
3089 | A28DqgOrgQGkgQHbgQHdZgBQAHIAaQBuAHQgJlFwVnByaW50OtMADgNYA1kDWgOxA7KAu4DJgM3ZAA4D | |
|
3090 | XgNfA2ADYQNiA2MDZAO0A2UDtgO3A7gDaQNqA2sDuwFYVU5TVGFngLmAyxIAEgAAgMyAs4C3gMrTAA4D | |
|
3091 | XgNuA28DvgO/gQGkgQHAgQHCW1NtYXJ0IExpbmtzUUdfEB10b2dnbGVBdXRvbWF0aWNMaW5rRGV0ZWN0 | |
|
3092 | aW9uOtMADgNYA1kDWgPFA8aAu4DPgNPYAA4DXgNfA2ADYQNiA2MDZANlA8kDtwPKA2kDagNrA82AuYDR | |
|
3093 | gNKAs4C3gNDTAA4DXgNuA28D0APRgQGkgQGvgQGxVFJlZG9RWlVyZWRvOtMADgNYA1kDWgPXA9iAu4DV | |
|
3094 | gNjYAA4DXgNfA2ADYQNiA2MDZANlA9sDZwNoA2kDagNrA9+AuYDXgLKAs4C3gNbTAA4DXgNuA28D4gPj | |
|
3095 | gQGkgQHEgQHGXlN0YXJ0IFNwZWFraW5nXnN0YXJ0U3BlYWtpbmc60wAOA1gDWQNaA+gD6YC7gNqA3tgA | |
|
3096 | DgNeA18DYANhA2IDYwNkA2UD7ANnA+0DaQNqA2sD8IC5gNyA3YCzgLeA29MADgNeA24DbwPzA/SBAaSB | |
|
3097 | AfGBAfNfEBRJUHl0aG9uMVNhbmRib3ggSGVscFE/WXNob3dIZWxwOtMADgNYA1kDWgP6A/uAu4DggOLY | |
|
3098 | AA4DXgNfA2ADYQNiA2MDZANlA/4DZwNoA2kDagNrA5WAuYDhgLKAs4C3gL5fEBtDaGVjayBTcGVsbGlu | |
|
3099 | ZyBXaGlsZSBUeXBpbmdfEB50b2dnbGVDb250aW51b3VzU3BlbGxDaGVja2luZzrTAA4DWANZA1oEBwQI | |
|
3100 | gLuA5IDn2AAOA14DXwNgA2EDYgNjA2QDZQQLA2cEDANpA2oDawPNgLmA5YDmgLOAt4DQWlNlbGVjdCBB | |
|
3101 | bGxRYVpzZWxlY3RBbGw60wAOA1gDWQNaBBUEFoC7gOmA69gADgNeA18DYANhA2IDYwNkA2UEGQNnA2gD | |
|
3102 | aQNqA2sDlYC5gOqAsoCzgLeAvl8QG0NoZWNrIEdyYW1tYXIgV2l0aCBTcGVsbGluZ18QFnRvZ2dsZUdy | |
|
3103 | YW1tYXJDaGVja2luZzrTAA4DWANZA1oEIgQjgLuA7YDw2AAOA14DXwNgA2EDYgNjA2QDZQQmA2cDaANp | |
|
3104 | A2oDawQqgLmA74CygLOAt4Du0wAOA14DbgNvBC0ELoEBpIEB54EB6W8QEgBDAHUAcwB0AG8AbQBpAHoA | |
|
3105 | ZQAgAFQAbwBvAGwAYgBhAHIgJl8QH3J1blRvb2xiYXJDdXN0b21pemF0aW9uUGFsZXR0ZTrTAA4DWANZ | |
|
3106 | A1oEMwQ0gLuA8oD12AAOA14DXwNgA2EDYgNjA2QDZQQ3BDgEOQNpA2oDawQqgLmA8xIAGAAAgPSAs4C3 | |
|
3107 | gO5cU2hvdyBUb29sYmFyUXRfEBN0b2dnbGVUb29sYmFyU2hvd2460wAOA1gDWQNaBEIEQ4C7gPeA+tgA | |
|
3108 | DgNeA18DYANhA2IDYwNkA2UERgNnBEcDaQNqA2sDp4C5gPiA+YCzgLeAxFRTYXZlUXNdc2F2ZURvY3Vt | |
|
3109 | ZW50OtQADgRPA1gDWQRQBFEEUgRTXU5TRGVzdGluYXRpb26BAQCA/YD8gP/SAA4AMgAzADSABIAD0gAO | |
|
3110 | ADIAMwRZgASA/l8QGklQeXRob24xU2FuZGJveEFwcERlbGVnYXRlWGRlbGVnYXRl0gA3ADgEXQReowRe | |
|
3111 | A4oAO18QFE5TTmliT3V0bGV0Q29ubmVjdG9y0wAOA1gDWQNaBGEEYoC7gQECgQEF2QAOA14DXwNgA2ED | |
|
3112 | YgNjA2QDtANlBGUDZwRmA2kDagNrA7sAVYC5gQEDgQEEgLOAt4DKXFNtYXJ0IFF1b3Rlc1FnXxAhdG9n | |
|
3113 | Z2xlQXV0b21hdGljUXVvdGVTdWJzdGl0dXRpb2461AAOBE8DWANZBFAEbwRRBHGBAQCBAQeA/YEBCdIA | |
|
3114 | DgAyADMEdIAEgQEIXxAWSVB5dGhvbkNvY29hQ29udHJvbGxlcl8QEWlweXRob25Db250cm9sbGVy0wAO | |
|
3115 | A1gDWQNaBHkEeoC7gQELgQEO2AAOA14DXwNgA2EDYgNjA2QDZQR9A2cEfgNpA2oDawNsgLmBAQyBAQ2A | |
|
3116 | s4C3gLBfEBRRdWl0IElQeXRob24xU2FuZGJveFFxWnRlcm1pbmF0ZTrTAA4DWANZA1oEhwSIgLuBARCB | |
|
3117 | ARTYAA4DXgNfA2ADYQNiA2MDZANlBIsDZwSMA2kDagNrBI+AuYEBEoEBE4CzgLeBARHUAA4DXgHVA24D | |
|
3118 | bwSSBJMElIEBpIEB64EB74EB7VhNaW5pbWl6ZVFtXxATcGVyZm9ybU1pbmlhdHVyaXplOtMADgNYA1kD | |
|
3119 | WgSaBJuAu4EBFoEBGdgADgNeA18DYANhA2IDYwNkA2UEngNnBJ8DaQNqA2sDzYC5gQEXgQEYgLOAt4DQ | |
|
3120 | VFVuZG9RelV1bmRvOtMADgNYA1kDWgSoBKmAu4EBG4EBHtgADgNeA18DYANhA2IDYwNkA2UErANnBK0D | |
|
3121 | aQNqA2sDlYC5gQEcgQEdgLOAt4C+bgBTAGgAbwB3ACAAUwBwAGUAbABsAGkAbgBnICZROl8QD3Nob3dH | |
|
3122 | dWVzc1BhbmVsOtMADgNYA1kDWgS2BLeAu4EBIIEBJNgADgNeA18DYANhA2IDYwNkA2UEugO3BLsDaQNq | |
|
3123 | A2sEvoC5gQEigQEjgLOAt4EBIdMADgNeA24DbwTBBMKBAaSBAZ+BAaFbU2hvdyBDb2xvcnNRQ18QFW9y | |
|
3124 | ZGVyRnJvbnRDb2xvclBhbmVsOtMADgNYA1kDWgTIBMmAu4EBJoEBKdgADgNeA18DYANhA2IDYwNkA2UE | |
|
3125 | zAQ4BM0DaQNqA2sDbIC5gQEngQEogLOAt4CwW0hpZGUgT3RoZXJzUWhfEBZoaWRlT3RoZXJBcHBsaWNh | |
|
3126 | dGlvbnM60wAOA1gDWQNaBNYE14C7gQErgQEu2AAOA14DXwNgA2EDYgNjA2QDZQTaA2cE2wNpA2oDawPN | |
|
3127 | gLmBASyBAS2As4C3gNBUQ29weVFjVWNvcHk60wAOA1gDWQNaBOQE5YC7gQEwgQE02QAOA14DXwNgA2ED | |
|
3128 | YgNjA2QDtANlBOgDZwTpA2kDagNrBOwAkIC5gQEygQEzgLOAt4EBMdMADgNeA24DbwTvBPCBAaSBAbWB | |
|
3129 | AbdlAEYAaQBuAGQgJlFmXxAXcGVyZm9ybUZpbmRQYW5lbEFjdGlvbjrTAA4DWANZA1oE9gT3gLuBATaB | |
|
3130 | ATjYAA4DXgNfA2ADYQNiA2MDZANlBPoDZwNoA2kDagNrA9+AuYEBN4CygLOAt4DWXVN0b3AgU3BlYWtp | |
|
3131 | bmddc3RvcFNwZWFraW5nOtQADgRPA1gDWQNaAB8FBAUFgLuAAoEBOoEBPNcADgNeA2ADYQNiA2MDZANl | |
|
3132 | BQgDaANpA2oDawNsgLmBATuAsoCzgLeAsF8QFUFib3V0IElQeXRob24xU2FuZGJveF8QHW9yZGVyRnJv | |
|
3133 | bnRTdGFuZGFyZEFib3V0UGFuZWw60wAOA1gDWQNaBREFEoC7gQE+gQFB2QAOBRQDXgNfA2ADYQNiA2MD | |
|
3134 | ZANlA2gFFwO3BRgDaQNqA2sDp1lOU1Rvb2xUaXCAuYCygQE/gQFAgLOAt4DEXVBhZ2UgU2V0dXAuLi5R | |
|
3135 | UF5ydW5QYWdlTGF5b3V0OtQADgRPA1gDWQRQBG8AQQRTgQEAgQEHgAeA/9MADgNYA1kDWgUmBSeAu4EB | |
|
3136 | RIEBR9gADgNeA18DYANhA2IDYwNkA2UFKgNnBSsDaQNqA2sDzYC5gQFFgQFGgLOAt4DQVVBhc3RlUXZW | |
|
3137 | cGFzdGU61AAOBE8DWANZBFAAyABBBTaBAQCAGIAHgQFJXxAVaW5pdGlhbEZpcnN0UmVzcG9uZGVy0wAO | |
|
3138 | A1gDWQNaBToFO4C7gQFLgQFO2AAOA14DXwNgA2EDYgNjA2QDZQU+A2cFPwNpA2oDawTsgLmBAUyBAU2A | |
|
3139 | s4C3gQExXxARSnVtcCB0byBTZWxlY3Rpb25Ral8QHWNlbnRlclNlbGVjdGlvbkluVmlzaWJsZUFyZWE6 | |
|
3140 | 0wAOA1gDWQNaBUgFSYC7gQFQgQFT2AAOA14DXwNgA2EDYgNjA2QDZQVMA2cDaANpA2oDawVQgLmBAVKA | |
|
3141 | soCzgLeBAVHUAA4DXgHVA24DbwVTBVQFVYEBpIEBpYEBp4EBplpDbGVhciBNZW51XxAVY2xlYXJSZWNl | |
|
3142 | bnREb2N1bWVudHM60wAOA1gDWQNaBVoFW4C7gQFVgQFX2AAOA14DXwNgA2EDYgNjA2QDZQVeA2cDaANp | |
|
3143 | A2oDawPNgLmBAVaAsoCzgLeA0FZEZWxldGVXZGVsZXRlOtMADgNYA1kDWgVnBWiAu4EBWYEBW9cADgNe | |
|
3144 | A2ADYQNiA2MDZANlBWsDaANpA2oDawOngLmBAVqAsoCzgLeAxF8QD1JldmVydCB0byBTYXZlZF8QFnJl | |
|
3145 | dmVydERvY3VtZW50VG9TYXZlZDrUAA4ETwNYA1kEUADIBG8FdoEBAIAYgQEHgQFdWHRleHRWaWV30wAO | |
|
3146 | A1gDWQNaBXoFe4C7gQFfgQFh2AAOA14DXwNgA2EDYgNjA2QDZQV+A2cDaANpA2oDawSPgLmBAWCAsoCz | |
|
3147 | gLeBARFfEBJCcmluZyBBbGwgdG8gRnJvbnRfEA9hcnJhbmdlSW5Gcm9udDrTAA4DWANZA1oFhwWIgLuB | |
|
3148 | AWOBAWXYAA4DXgNfA2ADYQNiA2MDZANlBYsDZwTNA2kDagNrA2yAuYEBZIEBKICzgLeAsF8QFEhpZGUg | |
|
3149 | SVB5dGhvbjFTYW5kYm94VWhpZGU60wAOA1gDWQNaBZQFlYC7gQFngQFp2AAOA14DXwNgA2EDYgNjA2QD | |
|
3150 | ZQWYA2cDaANpA2oDawSPgLmBAWiAsoCzgLeBARFUWm9vbVxwZXJmb3JtWm9vbTrTAA4DWANZA1oFoQWi | |
|
3151 | gLuBAWuBAW3ZAA4DXgNfA2ADYQNiA2MDZAO0A2UFpQNnBOkDaQNqA2sDuwCQgLmBAWyBATOAs4C3gMpf | |
|
3152 | EBBTbWFydCBDb3B5L1Bhc3RlXxAYdG9nZ2xlU21hcnRJbnNlcnREZWxldGU60wAOA1gDWQNaBa4Fr4C7 | |
|
3153 | gQFvgQFy2AAOA14DXwNgA2EDYgNjA2QDZQWyA7cFswNpA2oDawOngLmBAXCBAXGAs4C3gMRoAFMAYQB2 | |
|
3154 | AGUAIABBAHMgJlFTXxAPc2F2ZURvY3VtZW50QXM60wAOA1gDWQNaBbwFvYC7gQF0gQF32AAOA14DXwNg | |
|
3155 | A2EDYgNjA2QDZQXAA2cFwQNpA2oDawPNgLmBAXWBAXaAs4C3gNBTQ3V0UXhUY3V0OtMADgNYA1kDWgXK | |
|
3156 | BcuAu4EBeYEBfNgADgNeA18DYANhA2IDYwNkA2UFzgNnBc8DaQNqA2sDp4C5gQF6gQF7gLOAt4DEVUNs | |
|
3157 | b3NlUXddcGVyZm9ybUNsb3NlOtcADgRPBdcF2ANYA1kF2QXaBFEF3AXdBd4F3wBVWU5TS2V5UGF0aFlO | |
|
3158 | U0JpbmRpbmdfEBxOU05pYkJpbmRpbmdDb25uZWN0b3JWZXJzaW9ugQGMgP2BAYuBAYqBAX6BAYnbBeEA | |
|
3159 | DgXiBeMF5AXlBeYF5wXoBekF6gB6BewAegXuAHoF8AXxAHoAegB6BfVfEBpOU0ZpbHRlclJlc3RyaWN0 | |
|
3160 | c0luc2VydGlvbl8QFE5TUHJlc2VydmVzU2VsZWN0aW9uXE5TSW5pdGlhbEtleVpOU0VkaXRhYmxlXk5T | |
|
3161 | RGVjbGFyZWRLZXlzXk5TSW5pdGlhbFZhbHVlXxAiTlNDbGVhcnNGaWx0ZXJQcmVkaWNhdGVPbkluc2Vy | |
|
3162 | dGlvbl8QGE5TU2VsZWN0c0luc2VydGVkT2JqZWN0c18QFk5TQXZvaWRzRW1wdHlTZWxlY3Rpb25fEBFO | |
|
3163 | U1NvcnREZXNjcmlwdG9ycwmBAYgJgQGBCYEBf4EBggkJCYEBg9IADgA+AGkF+IA0owX5Be4F8YEBgIEB | |
|
3164 | gYEBglRrZXlzU2tleVV2YWx1ZdIADgA+BgAGAYEBh6EGAoEBhNQADgYEBgUGBgYHBe4GCQB6VU5TS2V5 | |
|
3165 | Wk5TU2VsZWN0b3JbTlNBc2NlbmRpbmeBAYaBAYGBAYUJWGNvbXBhcmU60gA3ADgGDQYOogYOADtfEBBO | |
|
3166 | U1NvcnREZXNjcmlwdG9y0gA3ADgGEAE4ogE4ADvSADcAOAYSBhOlBhMGFAYVBhYAO18QFk5TRGljdGlv | |
|
3167 | bmFyeUNvbnRyb2xsZXJfEBFOU0FycmF5Q29udHJvbGxlcl8QEk5TT2JqZWN0Q29udHJvbGxlclxOU0Nv | |
|
3168 | bnRyb2xsZXJfEClmaWx0ZXJQcmVkaWNhdGU6IHdvcmtzcGFjZUZpbHRlclByZWRpY2F0ZV8QD2ZpbHRl | |
|
3169 | clByZWRpY2F0ZV8QGHdvcmtzcGFjZUZpbHRlclByZWRpY2F0ZdIANwA4BhsGHKMGHAOKADtfEBVOU05p | |
|
3170 | YkJpbmRpbmdDb25uZWN0b3LXAA4ETwXXBdgDWANZBdkF2gRvBiAGIQXeBiMAVYEBjIEBB4EBkIEBj4EB | |
|
3171 | foEBjl8QGWNvbnRlbnREaWN0aW9uYXJ5OiB1c2VyTlNfEBFjb250ZW50RGljdGlvbmFyeVZ1c2VyTlPX | |
|
3172 | AA4ETwXXBdgDWANZBdkF2gXeBioF8QJ2Bi0AVYEBjIEBfoEBk4EBgoCLgQGSXxAcdmFsdWU6IGFycmFu | |
|
3173 | Z2VkT2JqZWN0cy52YWx1ZV8QFWFycmFuZ2VkT2JqZWN0cy52YWx1ZdcADgRPBdcF2ANYA1kF2QXaBd4G | |
|
3174 | MwXxAnUGNgBVgQGMgQF+gQGWgQGCgHyBAZVfEBp2YWx1ZTogYXJyYW5nZWRPYmplY3RzLmtleV8QE2Fy | |
|
3175 | cmFuZ2VkT2JqZWN0cy5rZXnXAA4ETwXXBdgDWANZBdkF2gRvBjwGPQBsBj8AVYEBjIEBB4EBmoEBmYCj | |
|
3176 | gQGYXxAZYW5pbWF0ZTogd2FpdGluZ0ZvckVuZ2luZVdhbmltYXRlXxAQd2FpdGluZ0ZvckVuZ2luZdIA | |
|
3177 | DgA+BgAGRYEBh68QZwZGAGsE5AVaBkoCwAVQBk0CgwZPBlAE1gZSBlMGVARCAE0AfgPwA7sEBwT2A7EE | |
|
3178 | FQP6AgoAfwNsBJoGYwOnAEECKgTIA1sEeQPfBSYFegRSBm4EbwPoAMgF3gWuBnQE7AONBUgGeAZ5BGED | |
|
3179 | nwOVA80GfgQqBoAEUQaCBREEMwIaBoYGhwaIBokAqgaLBCIFBASoA9cAbAWHBcoCRAaUA8UGlgJ2ALEF | |
|
3180 | OgS+BpsFvAJ1Bp4FZwagBIcFoQS2AKMGpQIQBqcGqAWUBqoGqwSPgQGcgA6BATCBAVWBAZ2AjoEBUYEB | |
|
3181 | qICDgQGqgQGugQErgQGygQGegQG/gPeAC4AQgNuAyoDkgQE2gMmA6YDggG6AaoCwgQEWgQHYgMSAB4By | |
|
3182 | gQEmgK+BAQuA1oEBRIEBX4D8gQHVgQEHgNqAGIEBfoEBb4EB6oEBMYC9gQFQgQHlgQHugQECgMOAvoDQ | |
|
3183 | gQG4gO6BAeGA/YEBzoEBPoDygJSBAbyBAcmBAd6BAeaAWIEBtIDtgQE6gQEbgNWAo4EBY4EBeYB0gQHN | |
|
3184 | gM+BAdqAi4BUgQFLgQEhgQHwgQF0gHyBAbOBAVmBAcOBARCBAWuBASCAFIEB0YCWgQHSgQGigQFngQG6 | |
|
3185 | gQHkgQER2gAOA14DXwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2xdTlNJc1NlcGFyYXRv | |
|
3186 | clxOU0lzRGlzYWJsZWSAuYCyCYCyCYCzgLeAsNoADga5A14DXwNgA2EDYgNjA2QBoANlBL4EwQNnA2gD | |
|
3187 | aQNqA2sGUwbBWU5TU3VibWVudYC5gQEhgQGfgLKAs4C3gQGegQGg1AAOA14B1QNuA28GxAbFBsaBAaSB | |
|
3188 | AceBAfSBAchWRm9ybWF0XnN1Ym1lbnVBY3Rpb2460gAOAD4AaQbLgDSiBqgEtoEBooEBINgADgNeA18D | |
|
3189 | YANhA2IDYwNkA2UG0ANnBDkDaQNqA2sEvoC5gQGjgPSAs4C3gQEhWlNob3cgRm9udHPSADcAOAbXA2Si | |
|
3190 | A2QAO1tPcGVuIFJlY2VudNIADgA+AGkG24A0oQVIgQFQXxAWX05TUmVjZW50RG9jdW1lbnRzTWVuddoA | |
|
3191 | Dga5A14DXwNgA2EDYgNjA2QBoANlBVAFUwNnA2gDaQNqA2sDpwbmgLmBAVGBAaWAsoCzgLeAxIEBqdoA | |
|
3192 | Dga5A14DXwNgA2EDYgNjA2QBoANlA5UDmANnA2gDaQNqA2sDzQbvgLmAvoEBq4CygLOAt4DQgQGsXxAU | |
|
3193 | U3BlbGxpbmcgYW5kIEdyYW1tYXLSAA4APgBpBvOANKQEqAONA/oEFYEBG4C9gOCA6doADga5A14DXwNg | |
|
3194 | A2EDYgNjA2QBoANlA80D0ANnA2gDaQNqA2sGUwcAgLmA0IEBr4CygLOAt4EBnoEBsFRFZGl00gAOAD4A | |
|
3195 | aQcEgDStBJoDxQZSBbwE1gUmBVoEBwaeBosGTwZUBqCBARaAz4EBsoEBdIEBK4EBRIEBVYDkgQGzgQG0 | |
|
3196 | gQGqgQG/gQHD2gAOA14DXwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA82AuYCyCYCyCYCz | |
|
3197 | gLeA0NoADgNeA18GrgNgBq8DYQNiA2MDZANlA2gDZwB6A2gAegNpA2oDawPNgLmAsgmAsgmAs4C3gNDa | |
|
3198 | AA4GuQNeA18DYANhA2IDYwNkAaADZQTsBO8DZwNoA2kDagNrA80HLIC5gQExgQG1gLKAs4C3gNCBAbZU | |
|
3199 | RmluZNIADgA+AGkHMIA0pQTkBn4GqgaGBTqBATCBAbiBAbqBAbyBAUvZAA4DXgNfA2ADYQNiA2MDZAO0 | |
|
3200 | A2UHOANnBGYDaQNqA2sE7ABVgLmBAbmBAQSAs4C3gQExWUZpbmQgTmV4dNkADgNeA18DYANhA2IDYwNk | |
|
3201 | A7QDZQdAA7cDuANpA2oDawTsAViAuYEBu4DMgLOAt4EBMV1GaW5kIFByZXZpb3Vz2QAOA14DXwNgA2ED | |
|
3202 | YgNjA2QDtANlB0gDZwdJA2kDagNrBOwHTYC5gQG9gQG+gLOAt4EBMRAHXxAWVXNlIFNlbGVjdGlvbiBm | |
|
3203 | b3IgRmluZFFl2gAOBrkDXgNfA2ADYQNiA2MDZAGgA2UDuwO+A2cDaANpA2oDawPNB1iAuYDKgQHAgLKA | |
|
3204 | s4C3gNCBAcFdU3Vic3RpdHV0aW9uc9IADgA+AGkHXIA0owWhBGEDsYEBa4EBAoDJ2gAOBrkDXgNfA2AD | |
|
3205 | YQNiA2MDZAGgA2UD3wPiA2cDaANpA2oDawPNB2iAuYDWgQHEgLKAs4C3gNCBAcVWU3BlZWNo0gAOAD4A | |
|
3206 | aQdsgDSiA9cE9oDVgQE2WUFNYWluTWVuddIADgA+AGkHcoA0pwaHBpYGUAZKBokGdAabgQHJgQHagQGu | |
|
3207 | gQGdgQHmgQHqgQHw2gAOBrkDXgNfA2ADYQNiA2MDZAGgA2UDbANwA2cDaANpA2oDawZTB4KAuYCwgQHK | |
|
3208 | gLKAs4C3gQGegQHLXxAPSVB5dGhvbjFTYW5kYm940gAOAD4AaQeGgDSrBQQGlAaCBqUGpwZGBYcEyANb | |
|
3209 | BmMEeYEBOoEBzYEBzoEB0YEB0oEBnIEBY4EBJoCvgQHYgQEL2gAOA14DXwauA2AGrwNhA2IDYwNkA2UD | |
|
3210 | aANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsNgADgNeA18DYANhA2IDYwNkA2UHnQNnB54DaQNq | |
|
3211 | A2sDbIC5gQHPgQHQgLOAt4CwbABQAHIAZQBmAGUAcgBlAG4AYwBlAHMgJlEs2gAOA14DXwauA2AGrwNh | |
|
3212 | A2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsNoADga5A14DXwNgA2EDYgNjA2QB | |
|
3213 | oANlBm4HsANnA2gDaQNqA2sDbAe1gLmBAdWBAdOAsoCzgLeAsIEB1FhTZXJ2aWNlc9QADgNeAdUDbgNv | |
|
3214 | B7AHuge7gQGkgQHTgQHXgQHW0gAOAD4AaQe+gDSgXxAPX05TU2VydmljZXNNZW512gAOA14DXwauA2AG | |
|
3215 | rwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA2yAuYCyCYCyCYCzgLeAsFxfTlNBcHBsZU1lbnXaAA4G | |
|
3216 | uQNeA18DYANhA2IDYwNkAaADZQOnA6oDZwNoA2kDagNrBlMH0oC5gMSBAduAsoCzgLeBAZ6BAdxURmls | |
|
3217 | ZdIADgA+AGkH1oA0qwaIBoAGTQarBcoEQgWuBWcGeAURA5+BAd6BAeGBAaiBAeSBAXmA94EBb4EBWYEB | |
|
3218 | 5YEBPoDD2AAOA14DXwNgA2EDYgNjA2QDZQfkA2cH5QNpA2oDawOngLmBAd+BAeCAs4C3gMRTTmV3UW7Y | |
|
3219 | AA4DXgNfA2ADYQNiA2MDZANlB+0DZwfuA2kDagNrA6eAuYEB4oEB44CzgLeAxGUATwBwAGUAbiAmUW/a | |
|
3220 | AA4DXgNfBq4DYAavA2EDYgNjA2QDZQNoA2cAegNoAHoDaQNqA2sDp4C5gLIJgLIJgLOAt4DE2gAOA14D | |
|
3221 | XwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrA6eAuYCyCYCyCYCzgLeAxNoADga5A14DXwNg | |
|
3222 | A2EDYgNjA2QBoANlBCoELQNnA2gDaQNqA2sGUwgOgLmA7oEB54CygLOAt4EBnoEB6FRWaWV30gAOAD4A | |
|
3223 | aQgSgDSiBDMEIoDygO3aAA4GuQNeA18DYANhA2IDYwNkAaADZQSPBJIDZwNoA2kDagNrBlMIHYC5gQER | |
|
3224 | gQHrgLKAs4C3gQGegQHsVldpbmRvd9IADgA+AGkIIYA0pASHBZQGeQV6gQEQgQFngQHugQFf2gAOA14D | |
|
3225 | XwauA2AGrwNhA2IDYwNkA2UDaANnAHoDaAB6A2kDagNrBI+AuYCyCYCyCYCzgLeBARFeX05TV2luZG93 | |
|
3226 | c01lbnXaAA4GuQNeA18DYANhA2IDYwNkAaADZQPwA/MDZwNoA2kDagNrBlMIOIC5gNuBAfGAsoCzgLeB | |
|
3227 | AZ6BAfJUSGVscNIADgA+AGkIPIA0oQPogNpbX05TTWFpbk1lbnXSAA4APgYACEGBAYevEGcDbABNBOwD | |
|
3228 | zQZTAnYGTQOnAnUDzQZTA80DzQAfA80DpwBBAGsGmwZUA80D3wO7A5UDlQB/AGsGhwPNA2wGlgAfAgoD | |
|
3229 | bANsA2wGoAPNBI8AHwanAB8D8ACjAB8DpwZTBosDlQVQA6cEjwO7A6cGTwZQBOwGiQOnAB8DbAOnBCoC | |
|
3230 | CgTsBlMDpwZTAKMDzQQqA2wDlQPfAE0DbAOnAgoDbAPNBlMCKgCjBOwGSgZTA80CKgPNA6cDzQSPA7sE | |
|
3231 | vgB+A2wCCgNsBL4EjwTsA6cGdICwgAuBATGA0IEBnoCLgQGogMSAfIDQgQGegNCA0IACgNCAxIAHgA6B | |
|
3232 | AfCBAb+A0IDWgMqAvoC+gGqADoEByYDQgLCBAdqAAoBugLCAsICwgQHDgNCBARGAAoEB0oACgNuAFIAC | |
|
3233 | gMSBAZ6BAbSAvoEBUYDEgQERgMqAxIEBqoEBroEBMYEB5oDEgAKAsIDEgO6AboEBMYEBnoDEgQGegBSA | |
|
3234 | 0IDugLCAvoDWgAuAsIDEgG6AsIDQgQGegHKAFIEBMYEBnYEBnoDQgHKA0IDEgNCBARGAyoEBIYAQgLCA | |
|
3235 | boCwgQEhgQERgQExgMSBAerSAA4APgYACKuBAYevEGgAawZGBOQFWgZKAsAFUAZNAoMGTwZQBNYGUgZT | |
|
3236 | BlQATQRCAH4D8AO7BAcE9gOxBBUCCgP6AH8DbABBA6cEmgZjAioEyANbBHkD3wUmBXoEUgZuBG8D6ADI | |
|
3237 | Bd4AHwWuBnQGeATsA40FSAZ5BGEDnwOVA80EKgZ+BoAEUQaCBREEMwIaBoYGhwaJBogAqgaLBCIFBABs | |
|
3238 | BKgD1wWHBcoCRAaUA8UGlgJ2ALEEvgU6BpsFvAJ1Bp4FZwagBIcFoQS2AKMGpQIQBqcGqAWUBqoGqwSP | |
|
3239 | gA6BAZyBATCBAVWBAZ2AjoEBUYEBqICDgQGqgQGugQErgQGygQGegQG/gAuA94AQgNuAyoDkgQE2gMmA | |
|
3240 | 6YBugOCAaoCwgAeAxIEBFoEB2IBygQEmgK+BAQuA1oEBRIEBX4D8gQHVgQEHgNqAGIEBfoACgQFvgQHq | |
|
3241 | gQHlgQExgL2BAVCBAe6BAQKAw4C+gNCA7oEBuIEB4YD9gQHOgQE+gPKAlIEBvIEByYEB5oEB3oBYgQG0 | |
|
3242 | gO2BATqAo4EBG4DVgQFjgQF5gHSBAc2Az4EB2oCLgFSBASGBAUuBAfCBAXSAfIEBs4EBWYEBw4EBEIEB | |
|
3243 | a4EBIIAUgQHRgJaBAdKBAaKBAWeBAbqBAeSBARHSAA4APgYACRaBAYevEGgJFwkYCRkJGgkbCRwJHQke | |
|
3244 | CR8JIAkhCSIJIwkkCSUJJgknCSgJKQkqCSsJLAktCS4JLwkwCTEJMgkzCTQJNQk2CTcJOAk5CToJOwk8 | |
|
3245 | CT0JPgk/CUAJQQlCCUMJRAlFCUYJRwlICUkJSglLCUwJTQlOCU8JUAlRCVIEWQlUCVUJVglXCVgJWQla | |
|
3246 | CVsJXAldCV4JXwlgCWEJYgljCWQJZQlmCWcJaAlpCWoJawlsCW0JbglvCXAJcQlyCXMJdAl1CXYJdwl4 | |
|
3247 | CXkJegl7CXwJfQl+gQH4gQH5gQH6gQH7gQH8gQH9gQH+gQH/gQIAgQIBgQICgQIDgQIEgQIFgQIGgQIH | |
|
3248 | gQIIgQIJgQIKgQILgQIMgQINgQIOgQIPgQIQgQIRgQISgQITgQIUgQIVgQIWgQIXgQIYgQIZgQIagQIb | |
|
3249 | gQIcgQIdgQIegQIfgQIggQIhgQIigQIjgQIkgQIlgQImgQIngQIogQIpgQIqgQIrgQIsgQItgQIugQIv | |
|
3250 | gQIwgQIxgQIygQIzgP6BAjSBAjWBAjaBAjeBAjiBAjmBAjqBAjuBAjyBAj2BAj6BAj+BAkCBAkGBAkKB | |
|
3251 | AkOBAkSBAkWBAkaBAkeBAkiBAkmBAkqBAkuBAkyBAk2BAk6BAk+BAlCBAlGBAlKBAlOBAlSBAlWBAlaB | |
|
3252 | AleBAliBAlmBAlqBAluBAlyBAl2BAl5aU3BsaXQgVmlld1tTZXBhcmF0b3ItM28QEQBNAGUAbgB1ACAA | |
|
3253 | SQB0AGUAbQAgACgARgBpAG4AZCAmAClfEBJNZW51IEl0ZW0gKERlbGV0ZSlfEBJNZW51IEl0ZW0gKEZv | |
|
3254 | cm1hdClfEBtUZXh0IEZpZWxkIENlbGwgKFRleHQgQ2VsbClfEBJNZW51IChPcGVuIFJlY2VudClfEBdN | |
|
3255 | ZW51IEl0ZW0gKE9wZW4gUmVjZW50KV8QHVRleHQgRmllbGQgQ2VsbCAoVGV4dCBDZWxsKS0xXxAgTWVu | |
|
3256 | dSBJdGVtIChTcGVsbGluZyBhbmQgR3JhbW1hcilfEBBNZW51IEl0ZW0gKEVkaXQpXxAQTWVudSBJdGVt | |
|
3257 | IChDb3B5KVlTZXBhcmF0b3JYTWFpbk1lbnVfEBlNZW51IEl0ZW0gKFN1YnN0aXR1dGlvbnMpXENvbnRl | |
|
3258 | bnQgVmlld1EzXUJveCAoQ29uc29sZSlRMl8QFE1lbnUgKFN1YnN0aXR1dGlvbnMpXxAWTWVudSBJdGVt | |
|
3259 | IChTZWxlY3QgQWxsKV8QGU1lbnUgSXRlbSAoU3RvcCBTcGVha2luZylfEBdNZW51IEl0ZW0gKFNtYXJ0 | |
|
3260 | IExpbmtzKV8QJ01lbnUgSXRlbSAoQ2hlY2sgR3JhbW1hciBXaXRoIFNwZWxsaW5nKV1TY3JvbGwgVmll | |
|
3261 | dy0xXxAnTWVudSBJdGVtIChDaGVjayBTcGVsbGluZyBXaGlsZSBUeXBpbmcpXxAPQm94IChXb3Jrc3Bh | |
|
3262 | Y2UpXxAWTWVudSAoSVB5dGhvbjFTYW5kYm94KV8QGVdpbmRvdyAoSVB5dGhvbjEgKENvY29hKSlbTWVu | |
|
3263 | dSAoRmlsZSlfEBBNZW51IEl0ZW0gKFVuZG8pW1NlcGFyYXRvci00XxAcVGFibGUgVmlldyAoVmFyaWFi | |
|
3264 | bGUsIFZhbHVlKV8QF01lbnUgSXRlbSAoSGlkZSBPdGhlcnMpXxAUTWVudSBJdGVtIChTaG93IEFsbClU | |
|
3265 | MTExMV1NZW51IChTcGVlY2gpXxARTWVudSBJdGVtIChQYXN0ZSlfEB5NZW51IEl0ZW0gKEJyaW5nIEFs | |
|
3266 | bCB0byBGcm9udClbQXBwbGljYXRpb25fEA9NZW51IChTZXJ2aWNlcylfEBdQeXRob24gQ29jb2EgQ29u | |
|
3267 | dHJvbGxlcl8QIE1lbnUgSXRlbSAoSVB5dGhvbjFTYW5kYm94IEhlbHApWVRleHQgVmlld18QGVVzZXIg | |
|
3268 | TmFtZXNwYWNlIENvbnRyb2xsZXJcRmlsZSdzIE93bmVyUThfEBJNZW51IEl0ZW0gKFdpbmRvdylTMi0x | |
|
3269 | W01lbnUgKEZpbmQpXxAaTWVudSBJdGVtIChDaGVjayBTcGVsbGluZylfEBZNZW51IEl0ZW0gKENsZWFy | |
|
3270 | IE1lbnUpW1NlcGFyYXRvci0yXxAYTWVudSBJdGVtIChTbWFydCBRdW90ZXMpUTZfEBtNZW51IChTcGVs | |
|
3271 | bGluZyBhbmQgR3JhbW1hcilbTWVudSAoRWRpdClbTWVudSAoVmlldylfEBVNZW51IEl0ZW0gKEZpbmQg | |
|
3272 | TmV4dClvEBEATQBlAG4AdQAgAEkAdABlAG0AIAAoAE8AcABlAG4gJgApUzEyMVE1XxAYTWVudSBJdGVt | |
|
3273 | IChTaG93IFRvb2xiYXIpXxATVmVydGljYWwgU2Nyb2xsZXItMV8QIk1lbnUgSXRlbSAoVXNlIFNlbGVj | |
|
3274 | dGlvbiBmb3IgRmluZClfEBtNZW51IEl0ZW0gKElQeXRob24xU2FuZGJveClfEBBNZW51IEl0ZW0gKFZp | |
|
3275 | ZXcpUTlfEBNIb3Jpem9udGFsIFNjcm9sbGVyXxAQTWVudSBJdGVtIChGaW5kKW8QHgBNAGUAbgB1ACAA | |
|
3276 | SQB0AGUAbQAgACgAQwB1AHMAdABvAG0AaQB6AGUAIABUAG8AbwBsAGIAYQByICYAKV8QIU1lbnUgSXRl | |
|
3277 | bSAoQWJvdXQgSVB5dGhvbjFTYW5kYm94KVxBc3luYyBBcnJvd3NvEBoATQBlAG4AdQAgAEkAdABlAG0A | |
|
3278 | IAAoAFMAaABvAHcAIABTAHAAZQBsAGwAaQBuAGcgJgApXxAaTWVudSBJdGVtIChTdGFydCBTcGVha2lu | |
|
3279 | ZylfECBNZW51IEl0ZW0gKEhpZGUgSVB5dGhvbjFTYW5kYm94KVMxLTFfEBFUYWJsZSBIZWFkZXIgVmll | |
|
3280 | d1tTZXBhcmF0b3ItNV8QEE1lbnUgSXRlbSAoUmVkbylfEBBNZW51IEl0ZW0gKEZpbGUpXxAUVGFibGUg | |
|
3281 | Q29sdW1uIChWYWx1ZSlfEBFWZXJ0aWNhbCBTY3JvbGxlcl1NZW51IChGb3JtYXQpXxAdTWVudSBJdGVt | |
|
3282 | IChKdW1wIHRvIFNlbGVjdGlvbilRMV8QD01lbnUgSXRlbSAoQ3V0KV8QF1RhYmxlIENvbHVtbiAoVmFy | |
|
3283 | aWFibGUpW1NlcGFyYXRvci0xUjEwXxASTWVudSBJdGVtIChTcGVlY2gpXxAUTWVudSBJdGVtIChNaW5p | |
|
3284 | bWl6ZSlfEBxNZW51IEl0ZW0gKFNtYXJ0IENvcHkvUGFzdGUpXxAXTWVudSBJdGVtIChTaG93IENvbG9y | |
|
3285 | cylbU2Nyb2xsIFZpZXdbU2VwYXJhdG9yLTZfEBVIb3Jpem9udGFsIFNjcm9sbGVyLTFfEBRNZW51IEl0 | |
|
3286 | ZW0gKFNlcnZpY2VzKV8QFk1lbnUgSXRlbSAoU2hvdyBGb250cylfEBBNZW51IEl0ZW0gKFpvb20pXxAZ | |
|
3287 | TWVudSBJdGVtIChGaW5kIFByZXZpb3VzKVE3XU1lbnUgKFdpbmRvdynSAA4APgYACeiBAYeg0gAOAD4G | |
|
3288 | AAnrgQGHoNIADgA+BgAJ7oEBh68QlwZGAGsDUATkBVoGSgM8Az8CwAVQBk0DLQNHA1UCgwNEBk8GUAMr | |
|
3289 | A08E1gZSAygDSAZTBlQEQgBNAH4D8AO7BAcE9gOxA0kEFQP6AgoAfwNsBJoGYwOnAEECKgTIA0EDWwNG | |
|
3290 | BHkD3wNKBSYFegRSAzQDTgNUA1EDMgM3A00GbgRvA+gAyAXeAB8FrgZ0BOwDjQVIBngDMQM6BnkEYQOf | |
|
3291 | AzsDlQPNAzkGfgQqAykGgARRBoIFEQQzAhoDOANFAyoGhgMwBocGiAaJAKoGiwQiAywFBASoA9cAbAWH | |
|
3292 | A0wFygM2AkQGlAPFBpYCdgNCAzMDLgCxBToEvgabBbwCdQaeBWcGoAM1Az0EhwNLBaEEtgM+AKMDUgal | |
|
3293 | AhADVganBqgDQANDBZQGqgMvA1MGqwSPgQGcgA6BAXOBATCBAVWBAZ2BAR+BAS+AjoEBUYEBqIDUgQFP | |
|
3294 | gQGUgIOBAUOBAaqBAa6AyIEBboEBK4EBsoCugQFUgQGegQG/gPeAC4AQgNuAyoDkgQE2gMmBAViA6YDg | |
|
3295 | gG6AaoCwgQEWgQHYgMSAB4BygQEmgQE5gK+BAUqBAQuA1oEBXIEBRIEBX4D8gPaBAWqBAZGBAXiA7IEB | |
|
3296 | BoEBZoEB1YEBB4DagBiBAX6AAoEBb4EB6oEBMYC9gQFQgQHlgOiBARWBAe6BAQKAw4EBGoC+gNCBAQ+B | |
|
3297 | AbiA7oC8gQHhgP2BAc6BAT6A8oCUgQEKgQFIgMKBAbyA44EByYEB3oEB5oBYgQG0gO2AzoEBOoEBG4DV | |
|
3298 | gKOBAWOBAWKBAXmBAQGAdIEBzYDPgQHagIuBAT2A8YDZgFSBAUuBASGBAfCBAXSAfIEBs4EBWYEBw4D7 | |
|
3299 | gQElgQEQgQFegQFrgQEggQEqgBSBAX2BAdGAloEBl4EB0oEBooEBNYEBQoEBZ4EBuoDfgQGNgQHkgQER | |
|
3300 | 0gAOAD4GAAqIgQGHrxCXCokKigqLCowKjQqOCo8KkAqRCpIKkwqUCpUKlgqXCpgKmQqaCpsKnAqdCp4K | |
|
3301 | nwqgCqEKogqjCqQKpQqmCqcKqAqpCqoKqwqsCq0KrgqvCrAKsQqyCrMKtAq1CrYKtwq4CrkKugq7CrwK | |
|
3302 | vQq+Cr8KwArBCsIKwwrECsUKxgrHCsgKyQrKCssKzArNCs4KzwrQCtEK0grTCtQK1QrWCtcK2ArZCtoK | |
|
3303 | 2wrcCt0K3grfCuAK4QriCuMK5ArlCuYK5wroCukK6grrCuwK7QruCu8K8ArxCvIK8wr0CvUK9gr3CvgK | |
|
3304 | +Qr6CvsK/Ar9Cv4K/wsACwELAgsDCwQLBQsGCwcLCAsJCwoLCwsMCw0LDgsPCxALEQsSCxMLFAsVCxYL | |
|
3305 | FwsYCxkLGgsbCxwLHQseCx+BAmOBAmSBAmWBAmaBAmeBAmiBAmmBAmqBAmuBAmyBAm2BAm6BAm+BAnCB | |
|
3306 | AnGBAnKBAnOBAnSBAnWBAnaBAneBAniBAnmBAnqBAnuBAnyBAn2BAn6BAn+BAoCBAoGBAoKBAoOBAoSB | |
|
3307 | AoWBAoaBAoeBAoiBAomBAoqBAouBAoyBAo2BAo6BAo+BApCBApGBApKBApOBApSBApWBApaBApeBApiB | |
|
3308 | ApmBApqBApuBApyBAp2BAp6BAp+BAqCBAqGBAqKBAqOBAqSBAqWBAqaBAqeBAqiBAqmBAqqBAquBAqyB | |
|
3309 | Aq2BAq6BAq+BArCBArGBArKBArOBArSBArWBAraBAreBAriBArmBArqBAruBAryBAr2BAr6BAr+BAsCB | |
|
3310 | AsGBAsKBAsOBAsSBAsWBAsaBAseBAsiBAsmBAsqBAsuBAsyBAs2BAs6BAs+BAtCBAtGBAtKBAtOBAtSB | |
|
3311 | AtWBAtaBAteBAtiBAtmBAtqBAtuBAtyBAt2BAt6BAt+BAuCBAuGBAuKBAuOBAuSBAuWBAuaBAueBAuiB | |
|
3312 | AumBAuqBAuuBAuyBAu2BAu6BAu+BAvCBAvGBAvKBAvOBAvSBAvWBAvaBAveBAviBAvkQkBEBpRDkENEQ | |
|
3313 | yhEBKxEBaRDxEQGeEH0QfBDpEH8RAawRAZ8Q4hDYENkRAWURAWsQxRDOEQFyEOsQHREBXBBLEQF0EQGk | |
|
3314 | EGoRAV0QxhDDEQFiEQFsEQFaENsRAZcRAZYQORDPEJUQUREBcxEBmxCREI4QlhD1EIgQ1BEBvBDLEAUT | |
|
3315 | //////////0RAWoRAWMRAasQwREBbREBuRDwEIIRAaYQbxEBoxEBgREBvhBQEBMQ3BDJEH4QShEBWxDf | |
|
3316 | EFwRAV8QThDmEMgQzRAlENARASgQ4RBIEQF1EIEQTREBKREBmREBcREBvRBWEN0Q6BA4EFIRAScRAaIQ | |
|
3317 | 2hEBKhDnEDoQzBDEEQG0EIYRAW8QSREBZBEBmBDsENcQUxEBnRBXEQFuEQFoEQGhENIRASwQZxDHEQGc | |
|
3318 | ENYQcBDTEQF2EQFwEBcQJxEBXhEBWRDgEQGgEQG4EI8RAZoRAbUQgxEBWBDjEQGtEO8Q1RDeEQGoEE8Q | |
|
3319 | GNIADgA+AGkLuYA0oNIADgA+BgALvIEBh6DSAA4APgYAC7+BAYeg0gA3ADgLwQvCogvCADteTlNJQk9i | |
|
3320 | amVjdERhdGEACAAZACIAJwAxADoAPwBEAFIAVABmBmYGbAa3Br4GxQbTBuUHAQcPBxsHJwc1B0AHTgdq | |
|
3321 | B3gHiwedB7cHwQfOB9AH0wfWB9kH3AfeB+EH4wfmB+kH7AfvB/EH8wf2B/kH/Af/CAgIFAgWCBgIJggv | |
|
3322 | CDgIQwhICFcIYAhzCHwIhwiJCIwIjgi7CMgI1QjrCPkJAwkRCR4JMAlECVAJUglUCVYJWAlaCV8JYQlj | |
|
3323 | CWUJZwlpCYQJlwmgCb0JzwnaCeMJ7wn7Cf0J/woBCgQKBgoICgoKEwoVChoKHAoeCkcKTwpeCm0Kegp8 | |
|
3324 | Cn4KgAqCCoUKhwqJCosKjAqVCpcKnAqeCqAK2QrjCu8K/QsKCxQLJgs0CzYLOAs6CzwLPQs/C0ELQwtF | |
|
3325 | C0cLSQtLC00LVgtYC1sLXQt6C3wLfguAC4ILhAuGC48LkQuUC5YLxwvTC9wL6Av2C/gL+gv8C/4MAQwD | |
|
3326 | DAUMBwwJDAsMDQwWDBgMHwwhDCMMJQxaDGMMbAx2DIAMigyMDI4MkAySDJQMlgyYDJsMnQyfDKEMowyl | |
|
3327 | DK4MsAyzDLUM6gz8DQYNEw0fDSkNMg09DT8NQQ1DDUUNRw1JDUsNTg1QDVINVA1WDVgNYQ1jDYgNig2M | |
|
3328 | DY4NkA2SDZQNlg2YDZoNnA2eDaANog2kDaYNqA2qDcYN2w34DhkONQ5bDoEOnw67DtcO9A8MDyYPWg93 | |
|
3329 | D5MPwA/JD9AP3Q/jD/oQDxAZECQQLBA+EEAQQhBLEE0QYhB1EIMQjRCPEJEQkxCVEKIQqxCtEK8QsRC6 | |
|
3330 | EMQQxhDHENAQ1xDpEPIQ+xEXESwRNRE3EToRPBFFEUwRWxFjEWwRcRF6EX8RoBGoEcIR1RHpEgASFRIo | |
|
3331 | EioSLxIxEjMSNRI3EjkSOxJIElUSWxJdEngSgRKGEo4SmxKjEqUSpxKqErcSvxLBEsYSyBLKEs8S0RLT | |
|
3332 | EugS9BMCEwQTBhMIEwoTERMvEzwTPhNKE18TYRNjE2UTZxN7E4QTiROWE6MTpROqE6wTrhOzE7UTtxPD | |
|
3333 | E9AT0hPZE+IT5xP+FAsUExQcFCcULhQ1FEEUWBRwFH0UfxSCFI8UmRSmFKgUqhSyFLsUwBTJFNIU3RUC | |
|
3334 | FQsVFBUeFSAVIhUkFSYVLxUxFTMVNRU+FVYVYxVsFXcVghWMFbkVxBXGFcgVyhXMFc4V0BXSFdsV5BX/ | |
|
3335 | FhgWIRYqFjcWThZXFl4WaRZwFo0WmRakFq4WuxbHFswWzhbQFtIW1BbWFt4W7xb2Fv0XBhcIFxEXExcW | |
|
3336 | FyMXLBcxFzgXTRdPF1EXUxdVF2sXeBd6F4gXkReaF6wXuRfAF8kX0hfYGBEYExgVGBcYGRgaGBwYHhgg | |
|
3337 | GCIYJBgmGC8YMRg0GDYYUxhVGFcYWRhbGF0YXxhoGGoYbRhvGK4YuxjOGNsY3RjfGOEY4xjlGOcY6Rjr | |
|
3338 | GP4ZABkCGQQZBhkIGREZExkeGSAZIhkkGSYZKBlVGVcZWRlbGV0ZXxlhGWMZZRlnGXAZchl1GXcZzhnw | |
|
3339 | GfoaBxocGjYaUhptGncagxqVGqQawxrPGtEa0xrcGt4a4BrhGuMa7Br1Gvca+Br6Gvwa/hsAGwkbFBsx | |
|
3340 | Gz0bPxtBG0MbRRtHG0kbdht4G3obfBt+G4AbghuEG4YbiBuSG5sbpBu4G9Eb0xvVG9cb2RvbG/Ib+xwE | |
|
3341 | HBIcGxwdHCIcJBwmHE8cXhxrHHYchRyQHJscqBypHKscrRy2HLgcwRzKHMsczRzqHO8c8RzzHPUc9xz5 | |
|
3342 | HQIdDx0RHR0dMh00HTYdOB06HUwdVR1gHXQdlR2jHagdqh2sHa4dsB2yHbUdtx3BHdId1B3dHd8d4h33 | |
|
3343 | Hfkd+x39Hf8eGB4tHi8eMR4zHjUeSB5RHlYeZB6NHo4ekB6SHpsenR6eHqAevR6/HsEewx7FHscezR7u | |
|
3344 | HvAe8h70HvYe+B76Hw8fER8THxUfFx8hHy4fMB81Hz4fSR9hH4YfiB+KH4wfjh+QH5IflB+dH7Yf3x/h | |
|
3345 | H+Mf5R/nH+kf6x/tH/YgDiAXIBkgHCAeIDQgTSBkIH0gmiCcIJ4goCCiIKQgriC7IL0g1iD5IQIhCyEX | |
|
3346 | IUAhSyFWIWAhbSFvIXEhcyF8IYUhiCGKIY0hjyGRIZYhmCGhIaYhsSHJIdIh2yHxIfwiFCInIjAiNSJI | |
|
3347 | IlEiUyK0IrYiuCK6IrwiviLAIsIixCLGIsgiyiLMIs4i0CLTItYi2SLcIt8i4iLlIugi6yLuIvEi9CL3 | |
|
3348 | Ivoi/SMAIwMjBiMJIwwjDyMSIxUjGCMbIx4jISMkIycjKiMtIzAjMyNAI0kjUSNTI1UjVyN4I4AjlCOf | |
|
3349 | I60jtyPEI8sjzSPPI9Qj1iPbI90j3yPhI/Ij/iQBJAQkByQKJBMkICQvJDEkMyQ1JD0kTyRYJF0kcCR9 | |
|
3350 | JH8kgSSDJJYknySkJK8kyCTRJNgk8CT/JQwlDiUQJRIlMyU1JTclOSU7JT0lPyVMJU8lUiVVJWQlZiV1 | |
|
3351 | JYIlhCWGJYglqSWrJa0lryWxJbMltSXCJcUlyCXLJdgl2iXhJe4l8CXyJfQmGSYfJiEmIyYoJiomLCYu | |
|
3352 | JjAmPSZAJkMmRiZSJlQmdCaBJoMmhSaHJqgmqiasJq4msCayJrQmwSbEJscmyibPJtEm1ybkJuYm6Cbq | |
|
3353 | JwsnDScPJxEnEycVJxcnJCcnJyonLSc8J0snWCdaJ1wnXid/J4EngyeFJ4cniSeLJ5gnmyeeJ6EnuCe6 | |
|
3354 | J8Qn0SfTJ9Un1yf4J/on/Cf+KAAoAigEKCIoQyhQKFIoVChWKHcoeSh7KH0ofyiBKIMojiiQKJsoqCiq | |
|
3355 | KKworijPKNEo0yjVKNco2SjbKPkpEikfKSEpIyklKUYpSClKKUwpTilQKVIpXyliKWUpaCmPKbEpvinA | |
|
3356 | KcIpxCnlKecp6SnuKfAp8in0KfYqAyoFKhsqKCoqKiwqLipPKlEqUypVKlcqWSpbKmAqYipwKoEqjyqS | |
|
3357 | KpQqliqYKqEqoyqlKq4qsCqyKs8q2CrhKugq/ysMKw4rESsUKzkrOys+K0ErQytFK0crVCtWK3oriyuO | |
|
3358 | K5ErkyuWK58roSukK70r0SveK+Ar4yvmLAcsCSwMLA8sESwTLBUsLCwuLDksRixILEssTixvLHEsdCx3 | |
|
3359 | LHkseyx+LI8skiyVLJgsmyykLKYsvCzJLMsszizRLPIs9Cz3LPos/Cz+LQAtBS0HLQ0tGi0cLR8tIi1D | |
|
3360 | LUUtSC1LLU0tTy1RLW4tcC2CLY8tkS2ULZctuC26Lb0twC3CLcQtxy3ULdct2i3dLekt6y4DLhAuEi4V | |
|
3361 | LhguOS47Lj4uQS5DLkUuRy5TLlUubi57Ln0ugC6DLqQupi6pLqwuri6wLrIuty65Lr8uzC7OLtEu1C75 | |
|
3362 | Lvsu/i8BLwMvBS8ILxUvGC8bLx4vKS8rL0UvUi9UL1cvWi97L30vgC+CL4Qvhi+IL5YvpC+1L7cvuS+8 | |
|
3363 | L78v3C/eL+Ev4y/lL+cv6TABMCEwLjAwMDMwNjBbMGUwZzBpMGwwbzBxMHMwdTCDMIUwlDClMKgwqzCt | |
|
3364 | MK8wvDC+MMEwxDDlMOcw6jDtMO8w8TDzMPkw+zECMRMxFjEYMRoxHTE1MUIxRDFHMUoxazFtMXAxczF1 | |
|
3365 | MXcxejGOMZAxsDG9Mb8xwjHFMeYx6DHrMe0x7zHxMfQyBTIIMgsyDjIRMhwyNDJBMkMyRjJJMmoybDJv | |
|
3366 | MnEyczJ1MncyfjKGMpMylTKYMpsyuDK6Mr0yvzLBMsMyxTLXMvAzATMEMwYzCTMMMxUzIjMkMyczKjNL | |
|
3367 | M00zUDNSM1QzVjNZM24zgDONM48zkjOVM7YzuDO7M74zwDPCM8Qz2zPhM+4z8DPzM/Y0FzQZNBw0HjQg | |
|
3368 | NCI0JTQqNDc0RDRGNEk0TDRxNHM0djR5NHs0fTR/NJI0rTS6NLw0vzTCNOM05TToNOs07TTvNPE1AjUE | |
|
3369 | NRY1IzUlNSg1KzVMNU41UTVUNVY1WDVaNV41YDVlNXI1dDV3NXo1mzWdNaA1ozWlNac1qTWvNbE1vzXc | |
|
3370 | NeY18DYPNhI2FDYXNho2HTYgNk02ajaBNo42mTaoNrc23Db3NxA3JDclNyg3KTcsNy03MDczNzQ3NTc2 | |
|
3371 | Nzk3QjdEN0s3TjdRN1Q3WTddN2M3bDdvN3I3dTeGN4w3lzejN6Y3qTesN603tje/N8Q31zfgN+U37jf5 | |
|
3372 | OBI4Jjg7OEg4dDiGOKE4qjixOMk45jjpOOw47zjyOPU4+DkUOSg5LzlMOU85UjlVOVg5WjldOXw5lDmx | |
|
3373 | ObQ5tzm6Ob05vznCOd859ToSOhU6GDobOh46IDojOj86RzpaOmM6Zjs3Ozo7PDs/O0I7RTtHO0o7TTtP | |
|
3374 | O1I7VTtYO1s7XjthO2M7ZTtnO2k7azttO3A7cjt0O3Y7eDt6O3w7fzuCO4Q7hjuIO4s7jTuQO5I7lTuY | |
|
3375 | O5o7nTugO6I7pDunO6o7rTuwO7I7tTu4O7s7vjvAO8I7xDvHO8k7zDvOO9E71DvWO9g72zveO+E75Dvm | |
|
3376 | O+k76zvuO/E78zv1O/g7+zv9PAA8AjwFPAc8CTwMPA88EjwVPBc8GjwdPCA8IzwmPCk8KzwuPDA8Mzw2 | |
|
3377 | PDk8PDw/PEI8azx5PIY8iDyKPIs8jTyOPJA8kjyUPL08xzzJPMw8zzzRPNM81TzYPNs87DzvPPI89Tz4 | |
|
3378 | PP89Dj0XPRk9Hj0hPSQ9RT1HPUo9TD1OPVA9Uz1ePWc9bD14PYE9gz2GPYk9oj3LPc090D3TPdU91z3Z | |
|
3379 | Pds93j4HPgk+Cz4OPhA+Ej4UPhY+GT4wPjk+Oz5EPkc+ST5LPk0+dj54Pno+fT5/PoE+gz6GPok+jj6X | |
|
3380 | Ppk+tD63Prk+vD6/PsI+xT7IPso+zT7QPtM+1j7ZPwI/BD8GPwc/CT8KPww/Dj8QPzk/Oz89Pz4/QD9B | |
|
3381 | P0M/RT9HP3A/cj91P3g/ej98P34/gD+DP4g/kT+TP54/oT+kP6c/qj+tP9I/1D/XP9o/3D/eP+E/60AQ | |
|
3382 | QBJAFUAXQBlAG0AeQCxAUUBTQFZAWUBbQF1AYEBiQHtAfUCmQKhAqkCtQK9AsUCzQLVAuEDGQM9A0UDY | |
|
3383 | QNtA3kDgQQlBC0ENQRBBEkEUQRZBGEEbQSJBK0EtQTJBNEE3QUFBSkFMQVtBXkFhQWRBZ0FqQW1BcEGZ | |
|
3384 | QZtBnUGgQaJBpEGmQalBrEG+QcdByUHgQeNB5kHpQexB70HyQfVB+EH6Qf1CAEIpQitCLUIuQjBCMUIz | |
|
3385 | QjVCN0JYQlpCXUJgQmJCZEJmQn9CgUKqQqxCrkKvQrFCskK0QrZCuELhQuNC5kLpQutC7ULvQvFC9EL9 | |
|
3386 | Qw5DEUMUQxdDGkMjQyVDJkM4Q2FDY0NlQ2ZDaENpQ2tDbUNvQ3xDpUOnQ6lDrEOuQ7BDskO1Q7hDvUPG | |
|
3387 | Q8hD30PiQ+VD6EPrQ+5D8EPzQ/ZD+UP8Q/5EH0QhRCREJ0QpRCtELUQxRDNEVERWRFlEXEReRGBEYkRt | |
|
3388 | RG9EmESaRJxEnUSfRKBEokSkRKZEz0TRRNNE1ETWRNdE2UTbRN1FBkUIRQpFDUUPRRFFE0UWRRlFHkUn | |
|
3389 | RSlFLkUwRTJFW0VdRWBFY0VlRWdFaUVsRW9FdkV/RYFFikWNRZBFk0WWRb9FwUXDRcRFxkXHRclFy0XO | |
|
3390 | Rd1GBkYIRgpGDUYPRhFGE0YWRhlGHkYnRilGLEYuRjpGQ0ZGRxdHGUcbRx5HIEcjRyVHKEcqRyxHLkcx | |
|
3391 | RzNHNUc3RzlHO0c9Rz9HQkdFR0dHSUdLR01HT0dRR1NHVkdYR1pHXUdfR2FHY0dlR2dHakdsR29HcUd0 | |
|
3392 | R3ZHeEd6R3xHfkeBR4RHhkeJR4tHjkeQR5JHlUeYR5tHnkegR6JHpEemR6hHqketR7BHske1R7dHuUe7 | |
|
3393 | R71Hv0fBR8NHxUfHR8lHy0fNR9BH0kfUR9dH2kfdR99H4UfjR+VH50fqR+xH70fxR/NH9Uf3R/pH/UgA | |
|
3394 | SAJIBUgOSBFI5EjmSOlI7EjvSPJI9Ej3SPpI/Ej/SQJJBUkISQtJDkkQSRJJFEkWSRhJGkkdSR9JIUkj | |
|
3395 | SSVJJ0kpSStJLUkwSTNJNUk4STpJPUk/SUJJRUlHSUpJTUlPSVFJVElWSVlJXElfSWJJZElnSWpJbUlv | |
|
3396 | SXFJc0l1SXhJe0l9SYBJg0mFSYdJikmNSZBJk0mVSZhJmkmdSZ9JokmkSadJqkmsSa9JsUm0SbZJuEm7 | |
|
3397 | Sb5JwUnEScZJyUnMSc9J0knVSdhJ2kndSd9J4knlSehJ60nuSfFJ+kn9StBK00rWStlK3ErfSuJK5Uro | |
|
3398 | SutK7krxSvRK90r6Sv1LAEsDSwZLCUsMSw9LEksVSxhLG0seSyFLJEsnSypLLUswSzNLNks5SzxLP0tC | |
|
3399 | S0VLSEtLS05LUUtUS1dLWktdS2BLY0tmS2lLbEtvS3JLdUt4S3tLfkuBS4RLhkuJS4xLj0uSS5VLmEub | |
|
3400 | S55LoUukS6dLqkutS7BLs0u2S7lLvEu/S8JLxUvIS8tLzkvRS9RL10vaS91L4EvjS+ZL6UvsS+9L8kv1 | |
|
3401 | S/hL+0v+TAFMBEwHTBJMHkxDTFhMbUyLTKBMukzaTP1NEE0jTS1NNk1STV9NYU1vTXFNiE2hTb1N104B | |
|
3402 | Tg9OOU5LTmROgE6MTp9Oq07KTuRO+08ATw5PIk9DT09PYU97T55PqE/ET9FP00/oT+xP+FAVUC5QOlBV | |
|
3403 | UFdQdVCBUI1QpVDKUM5Q0FDrUQFRJlFEUVdRWVFvUYJRwVHlUfJSKVJGUmlSbVKBUo1SoFKzUspS3lLs | |
|
3404 | UwxTDlMgUzpTRlNJU15TdVOUU65TulPGU95T9VQOVCFUPVQ/VE1UVlRZVFpUY1RmVGdUcFRzVaRVp1Wp | |
|
3405 | VaxVr1WyVbVVuFW7Vb1VwFXDVcVVyFXLVc1V0FXTVdZV2FXbVd5V4VXjVeZV6VXsVe5V8FXyVfRV9lX4 | |
|
3406 | VftV/VYAVgJWBFYGVghWClYNVhBWElYUVhZWGVYcVh5WIVYkViZWKVYsVi9WMVYzVjZWOVY8Vj5WQVZE | |
|
3407 | VkdWSlZMVk5WUVZTVlZWWVZcVl5WYVZkVmZWaVZsVm9WcVZ0VnZWeFZ7Vn5WgFaCVoVWh1aKVo1Wj1aR | |
|
3408 | VpRWl1aZVpxWnlahVqRWp1apVqxWrlawVrNWtla4VrpWvVbAVsNWxlbIVstWzVbQVtJW1VbXVtlW21be | |
|
3409 | VuFW5FbnVulW7FbvVvJW9Fb3VvpW/VcAVwNXBlcIVwtXDlcQVxNXFlcZVxxXH1ciVyVXJ1cqVy1XMFc5 | |
|
3410 | VzxYbVhwWHNYdlh5WHxYf1iCWIVYiFiLWI5YkViUWJdYmlidWKBYo1imWKlYrFivWLJYtVi4WLtYvljB | |
|
3411 | WMRYx1jKWM1Y0FjTWNZY2VjcWN9Y4ljlWOhY61juWPFY9Fj3WPpY/VkAWQNZBlkJWQxZD1kSWRVZGFkb | |
|
3412 | WR5ZIVkkWSdZKlktWTBZM1k2WTlZPFk/WUJZRVlIWUtZTllRWVRZV1laWV1ZYFljWWZZaVlsWW9Zcll1 | |
|
3413 | WXhZe1l+WYFZhFmHWYpZjVmQWZNZllmZWZxZn1miWaVZqFmrWa5ZsVm0WbdZulm9WcBZw1nGWclZzFnP | |
|
3414 | WdJZ1VnYWdtZ3lnhWeRZ51nqWe1Z8FnzWfZZ+Vn8Wf9aAloFWghaC1oOWhFaFFoXWhpaHVogWiNaJlop | |
|
3415 | WixaL1oyWjRaN1o5WjtaPVpAWkNaRVpIWkpaTFpOWlBaU1pWWlhaWlpcWl9aYlpkWmZaaVprWm1acFpy | |
|
3416 | WnVaeFp6Wn1af1qBWoRah1qKWoxaj1qSWpRallqYWppanVqgWqJapFqmWqhaqlqsWq9asVqzWrxav1rC | |
|
3417 | WsVax1rKWs1az1rRWtRa1lrZWtxa31rhWuNa5VrnWula61ruWvBa8lr1Wvda+Vr7Wv1a/1sBWwRbBlsI | |
|
3418 | WwtbDVsPWxJbFVsYWxtbHVsfWyFbI1slWyhbK1stWzBbMls0WzZbOFs7Wz1bQFtCW0VbSFtKW0xbTltR | |
|
3419 | W1NbVltZW1xbXlthW2NbZVtoW2pbbFtuW3FbdFt2W3hbe1t+W4Bbg1uGW4hbi1uOW5Bbk1uVW5hbmluc | |
|
3420 | W55boVujW6VbrluwW7Fbulu9W75bx1vKW8tb1FvZAAAAAAAAAgIAAAAAAAALwwAAAAAAAAAAAAAAAAAA | |
|
3421 | W+g</bytes> | |
|
3421 | 3422 | </object> |
|
3422 | 3423 | </data> |
|
3423 | 3424 | </archive> |
@@ -28,6 +28,7 b' from zopeinterface import Interface, Attribute, implements, classProvides' | |||
|
28 | 28 | |
|
29 | 29 | from IPython.kernel.core.history import FrontEndHistory |
|
30 | 30 | from IPython.kernel.core.util import Bunch |
|
31 | from IPython.kernel.engineservice import IEngineCore | |
|
31 | 32 | |
|
32 | 33 | ############################################################################## |
|
33 | 34 | # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or |
@@ -284,7 +285,6 b' class FrontEndBase(object):' | |||
|
284 | 285 | |
|
285 | 286 | def _add_block_id_for_failure(self, failure, blockID): |
|
286 | 287 | """_add_block_id_for_failure""" |
|
287 | ||
|
288 | 288 | failure.blockID = blockID |
|
289 | 289 | return failure |
|
290 | 290 | |
@@ -348,6 +348,7 b' class FrontEndBase(object):' | |||
|
348 | 348 | |
|
349 | 349 | |
|
350 | 350 | def render_error(self, failure): |
|
351 | <<<<<<< TREE | |
|
351 | 352 | """Subclasses must override to render the failure. |
|
352 | 353 | |
|
353 | 354 | In asynchronous frontends, this method will be called as a |
@@ -359,4 +360,63 b' class FrontEndBase(object):' | |||
|
359 | 360 | |
|
360 | 361 | |
|
361 | 362 | |
|
363 | ======= | |
|
364 | """Subclasses must override to render the failure. Since this method | |
|
365 | will be called as a twisted.internet.defer.Deferred's callback, | |
|
366 | implementations should return result when finished. | |
|
367 | """ | |
|
368 | ||
|
369 | return failure | |
|
370 | ||
|
371 | ||
|
372 | ||
|
373 | class AsyncFrontEndBase(FrontEndBase): | |
|
374 | """ | |
|
375 | Overrides FrontEndBase to wrap execute in a deferred result. | |
|
376 | All callbacks are made as callbacks on the deferred result. | |
|
377 | """ | |
|
378 | ||
|
379 | implements(IFrontEnd) | |
|
380 | classProvides(IFrontEndFactory) | |
|
381 | ||
|
382 | def __init__(self, engine=None, history=None): | |
|
383 | assert(engine==None or IEngineCore.providedBy(engine)) | |
|
384 | self.engine = IEngineCore(engine) | |
|
385 | if history is None: | |
|
386 | self.history = FrontEndHistory(input_cache=['']) | |
|
387 | else: | |
|
388 | self.history = history | |
|
389 | ||
|
390 | ||
|
391 | def execute(self, block, blockID=None): | |
|
392 | """Execute the block and return the deferred result. | |
|
393 | ||
|
394 | Parameters: | |
|
395 | block : {str, AST} | |
|
396 | blockID : any | |
|
397 | Caller may provide an ID to identify this block. | |
|
398 | result['blockID'] := blockID | |
|
399 | ||
|
400 | Result: | |
|
401 | Deferred result of self.interpreter.execute | |
|
402 | """ | |
|
403 | ||
|
404 | if(not self.is_complete(block)): | |
|
405 | from twisted.python.failure import Failure | |
|
406 | return Failure(Exception("Block is not compilable")) | |
|
407 | ||
|
408 | if(blockID == None): | |
|
409 | blockID = uuid.uuid4() #random UUID | |
|
410 | ||
|
411 | d = self.engine.execute(block) | |
|
412 | d.addCallback(self._add_history, block=block) | |
|
413 | d.addCallback(self._add_block_id_for_result, blockID) | |
|
414 | d.addErrback(self._add_block_id_for_failure, blockID) | |
|
415 | d.addBoth(self.update_cell_prompt, blockID=blockID) | |
|
416 | d.addCallbacks(self.render_result, | |
|
417 | errback=self.render_error) | |
|
418 | ||
|
419 | return d | |
|
420 | ||
|
421 | >>>>>>> MERGE-SOURCE | |
|
362 | 422 |
|
1 | NO CONTENT: modified file |
@@ -477,10 +477,6 b' class SystemExec:' | |||
|
477 | 477 | |
|
478 | 478 | An instance can then be created as: |
|
479 | 479 |
|
|
480 | ||
|
481 | And used as: | |
|
482 | >>> sysexec.xsys('pwd') | |
|
483 | >>> dirlist = sysexec.bq('ls -l') | |
|
484 | 480 | """ |
|
485 | 481 | |
|
486 | 482 | def __init__(self,verbose=0,debug=0,header='',split=0): |
@@ -684,8 +680,7 b' def optstr2types(ostr):' | |||
|
684 | 680 | |
|
685 | 681 | #---------------------------------------------------------------------------- |
|
686 | 682 | def read_dict(filename,type_conv=None,**opt): |
|
687 | ||
|
688 | """Read a dictionary of key=value pairs from an input file, optionally | |
|
683 | r"""Read a dictionary of key=value pairs from an input file, optionally | |
|
689 | 684 | performing conversions on the resulting values. |
|
690 | 685 | |
|
691 | 686 | read_dict(filename,type_conv,**opt) -> dict |
@@ -731,20 +726,33 b' def read_dict(filename,type_conv=None,**opt):' | |||
|
731 | 726 | to make a list of all appearances. |
|
732 | 727 | |
|
733 | 728 | Example: |
|
734 | If the input file test.ini has: | |
|
735 | i 3 | |
|
736 | x 4.5 | |
|
737 | y 5.5 | |
|
738 | s hi ho | |
|
739 | Then: | |
|
740 | 729 | |
|
730 | If the input file test.ini contains (we put it in a string to keep the test | |
|
731 | self-contained): | |
|
732 | ||
|
733 | >>> test_ini = '''\ | |
|
734 | ... i 3 | |
|
735 | ... x 4.5 | |
|
736 | ... y 5.5 | |
|
737 | ... s hi ho''' | |
|
738 | ||
|
739 | Then we can use it as follows: | |
|
741 | 740 | >>> type_conv={int:'i',float:'x',None:'s'} |
|
742 | >>> read_dict('test.ini') | |
|
743 | {'i': '3', 's': 'hi ho', 'x': '4.5', 'y': '5.5'} | |
|
744 | >>> read_dict('test.ini',type_conv) | |
|
745 | {'i': 3, 's': 'hi ho', 'x': 4.5, 'y': '5.5'} | |
|
746 | >>> read_dict('test.ini',type_conv,purge=1) | |
|
747 | {'i': 3, 's': 'hi ho', 'x': 4.5} | |
|
741 | ||
|
742 | >>> d = read_dict(test_ini) | |
|
743 | ||
|
744 | >>> sorted(d.items()) | |
|
745 | [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')] | |
|
746 | ||
|
747 | >>> d = read_dict(test_ini,type_conv) | |
|
748 | ||
|
749 | >>> sorted(d.items()) | |
|
750 | [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')] | |
|
751 | ||
|
752 | >>> d = read_dict(test_ini,type_conv,purge=True) | |
|
753 | ||
|
754 | >>> sorted(d.items()) | |
|
755 | [('i', 3), ('s', 'hi ho'), ('x', 4.5)] | |
|
748 | 756 | """ |
|
749 | 757 | |
|
750 | 758 | # starting config |
@@ -762,9 +770,15 b' def read_dict(filename,type_conv=None,**opt):' | |||
|
762 | 770 | raise ValueError, 'Unique keys must be given as a string, List or Tuple' |
|
763 | 771 | |
|
764 | 772 | dict = {} |
|
773 | ||
|
765 | 774 | # first read in table of values as strings |
|
775 | if '\n' in filename: | |
|
776 | lines = filename.splitlines() | |
|
777 | file = None | |
|
778 | else: | |
|
766 | 779 | file = open(filename,'r') |
|
767 |
|
|
|
780 | lines = file.readlines() | |
|
781 | for line in lines: | |
|
768 | 782 | line = line.strip() |
|
769 | 783 | if len(line) and line[0]=='#': continue |
|
770 | 784 | if len(line)>0: |
@@ -1307,8 +1321,11 b' class EvalDict:' | |||
|
1307 | 1321 | |
|
1308 | 1322 | Usage: |
|
1309 | 1323 | >>>number = 19 |
|
1324 | ||
|
1310 | 1325 | >>>text = "python" |
|
1326 | ||
|
1311 | 1327 | >>>print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict() |
|
1328 | Python 2.1 rules! | |
|
1312 | 1329 | """ |
|
1313 | 1330 | |
|
1314 | 1331 | # This version is due to sismex01@hebmex.com on c.l.py, and is basically a |
@@ -1328,14 +1345,19 b' def qw(words,flat=0,sep=None,maxsplit=-1):' | |||
|
1328 | 1345 | qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit) |
|
1329 | 1346 | |
|
1330 | 1347 | words can also be a list itself, and with flat=1, the output will be |
|
1331 |
recursively flattened. |
|
|
1348 | recursively flattened. | |
|
1349 | ||
|
1350 | Examples: | |
|
1332 | 1351 | |
|
1333 | 1352 | >>> qw('1 2') |
|
1334 | 1353 | ['1', '2'] |
|
1354 | ||
|
1335 | 1355 | >>> qw(['a b','1 2',['m n','p q']]) |
|
1336 | 1356 | [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]] |
|
1357 | ||
|
1337 | 1358 | >>> qw(['a b','1 2',['m n','p q']],flat=1) |
|
1338 |
['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] |
|
|
1359 | ['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] | |
|
1360 | """ | |
|
1339 | 1361 | |
|
1340 | 1362 | if type(words) in StringTypes: |
|
1341 | 1363 | return [word.strip() for word in words.split(sep,maxsplit) |
@@ -1804,20 +1826,6 b' def sort_compare(lst1,lst2,inplace = 1):' | |||
|
1804 | 1826 | return lst1 == lst2 |
|
1805 | 1827 | |
|
1806 | 1828 | #---------------------------------------------------------------------------- |
|
1807 | def mkdict(**kwargs): | |
|
1808 | """Return a dict from a keyword list. | |
|
1809 | ||
|
1810 | It's just syntactic sugar for making ditcionary creation more convenient: | |
|
1811 | # the standard way | |
|
1812 | >>>data = { 'red' : 1, 'green' : 2, 'blue' : 3 } | |
|
1813 | # a cleaner way | |
|
1814 | >>>data = dict(red=1, green=2, blue=3) | |
|
1815 | ||
|
1816 | If you need more than this, look at the Struct() class.""" | |
|
1817 | ||
|
1818 | return kwargs | |
|
1819 | ||
|
1820 | #---------------------------------------------------------------------------- | |
|
1821 | 1829 | def list2dict(lst): |
|
1822 | 1830 | """Takes a list of (key,value) pairs and turns it into a dict.""" |
|
1823 | 1831 |
@@ -1,4 +1,4 b'' | |||
|
1 |
|
|
|
1 | """IPython customization API | |
|
2 | 2 | |
|
3 | 3 | Your one-stop module for configuring & extending ipython |
|
4 | 4 | |
@@ -29,49 +29,49 b' import IPython.ipapi' | |||
|
29 | 29 | ip = IPython.ipapi.get() |
|
30 | 30 | |
|
31 | 31 | def ankka_f(self, arg): |
|
32 |
print |
|
|
32 | print 'Ankka',self,'says uppercase:',arg.upper() | |
|
33 | 33 | |
|
34 |
ip.expose_magic( |
|
|
34 | ip.expose_magic('ankka',ankka_f) | |
|
35 | 35 | |
|
36 | 36 | ip.magic('alias sayhi echo "Testing, hi ok"') |
|
37 | 37 | ip.magic('alias helloworld echo "Hello world"') |
|
38 | 38 | ip.system('pwd') |
|
39 | 39 | |
|
40 | 40 | ip.ex('import re') |
|
41 |
ip.ex( |
|
|
41 | ip.ex(''' | |
|
42 | 42 | def funcci(a,b): |
|
43 | 43 | print a+b |
|
44 | 44 | print funcci(3,4) |
|
45 | """) | |
|
46 |
ip.ex( |
|
|
45 | ''') | |
|
46 | ip.ex('funcci(348,9)') | |
|
47 | 47 | |
|
48 | 48 | def jed_editor(self,filename, linenum=None): |
|
49 |
print |
|
|
49 | print 'Calling my own editor, jed ... via hook!' | |
|
50 | 50 | import os |
|
51 | 51 | if linenum is None: linenum = 0 |
|
52 | 52 | os.system('jed +%d %s' % (linenum, filename)) |
|
53 |
print |
|
|
53 | print 'exiting jed' | |
|
54 | 54 | |
|
55 | 55 | ip.set_hook('editor',jed_editor) |
|
56 | 56 | |
|
57 | 57 | o = ip.options |
|
58 | 58 | o.autocall = 2 # FULL autocall mode |
|
59 | 59 | |
|
60 |
print |
|
|
61 | ''' | |
|
60 | print 'done!' | |
|
61 | """ | |
|
62 | ||
|
63 | #----------------------------------------------------------------------------- | |
|
64 | # Modules and globals | |
|
62 | 65 | |
|
63 | 66 | # stdlib imports |
|
64 | 67 | import __builtin__ |
|
65 | 68 | import sys |
|
66 | 69 | |
|
67 | try: # Python 2.3 compatibility | |
|
68 | set | |
|
69 | except NameError: | |
|
70 | import sets | |
|
71 | set = sets.Set | |
|
70 | # contains the most recently instantiated IPApi | |
|
71 | _RECENT_IP = None | |
|
72 | 72 | |
|
73 | # our own | |
|
74 | #from IPython.genutils import warn,error | |
|
73 | #----------------------------------------------------------------------------- | |
|
74 | # Code begins | |
|
75 | 75 | |
|
76 | 76 | class TryNext(Exception): |
|
77 | 77 | """Try next hook exception. |
@@ -86,6 +86,7 b' class TryNext(Exception):' | |||
|
86 | 86 | self.args = args |
|
87 | 87 | self.kwargs = kwargs |
|
88 | 88 | |
|
89 | ||
|
89 | 90 | class UsageError(Exception): |
|
90 | 91 | """ Error in magic function arguments, etc. |
|
91 | 92 | |
@@ -93,6 +94,7 b' class UsageError(Exception):' | |||
|
93 | 94 | nevertheless interrupt a macro / batch file. |
|
94 | 95 | """ |
|
95 | 96 | |
|
97 | ||
|
96 | 98 | class IPyAutocall: |
|
97 | 99 | """ Instances of this class are always autocalled |
|
98 | 100 | |
@@ -109,8 +111,6 b' class IPyAutocall:' | |||
|
109 | 111 | self._ip = ip |
|
110 | 112 | |
|
111 | 113 | |
|
112 | # contains the most recently instantiated IPApi | |
|
113 | ||
|
114 | 114 | class IPythonNotRunning: |
|
115 | 115 | """Dummy do-nothing class. |
|
116 | 116 | |
@@ -144,8 +144,6 b' class IPythonNotRunning:' | |||
|
144 | 144 | """Dummy function, which doesn't do anything and emits no warnings.""" |
|
145 | 145 | pass |
|
146 | 146 | |
|
147 | _recent = None | |
|
148 | ||
|
149 | 147 | |
|
150 | 148 | def get(allow_dummy=False,dummy_warn=True): |
|
151 | 149 | """Get an IPApi object. |
@@ -159,12 +157,13 b' def get(allow_dummy=False,dummy_warn=True):' | |||
|
159 | 157 | can be imported as normal modules. You can then direct all the |
|
160 | 158 | configuration operations against the returned object. |
|
161 | 159 | """ |
|
162 |
global _ |
|
|
163 |
if allow_dummy and not _ |
|
|
164 |
_ |
|
|
165 |
return _ |
|
|
160 | global _RECENT_IP | |
|
161 | if allow_dummy and not _RECENT_IP: | |
|
162 | _RECENT_IP = IPythonNotRunning(dummy_warn) | |
|
163 | return _RECENT_IP | |
|
166 | 164 | |
|
167 | class IPApi: | |
|
165 | ||
|
166 | class IPApi(object): | |
|
168 | 167 | """ The actual API class for configuring IPython |
|
169 | 168 | |
|
170 | 169 | You should do all of the IPython configuration by getting an IPApi object |
@@ -173,6 +172,8 b' class IPApi:' | |||
|
173 | 172 | |
|
174 | 173 | def __init__(self,ip): |
|
175 | 174 | |
|
175 | global _RECENT_IP | |
|
176 | ||
|
176 | 177 | # All attributes exposed here are considered to be the public API of |
|
177 | 178 | # IPython. As needs dictate, some of these may be wrapped as |
|
178 | 179 | # properties. |
@@ -201,8 +202,7 b' class IPApi:' | |||
|
201 | 202 | |
|
202 | 203 | self.dbg = DebugTools(self) |
|
203 | 204 | |
|
204 | global _recent | |
|
205 | _recent = self | |
|
205 | _RECENT_IP = self | |
|
206 | 206 | |
|
207 | 207 | # Use a property for some things which are added to the instance very |
|
208 | 208 | # late. I don't have time right now to disentangle the initialization |
@@ -218,8 +218,8 b' class IPApi:' | |||
|
218 | 218 | """All configurable variables.""" |
|
219 | 219 | |
|
220 | 220 | # catch typos by disabling new attribute creation. If new attr creation |
|
221 |
# is in fact wanted (e.g. when exposing new options), do |
|
|
222 | # for the received rc struct. | |
|
221 | # is in fact wanted (e.g. when exposing new options), do | |
|
222 | # allow_new_attr(True) for the received rc struct. | |
|
223 | 223 | |
|
224 | 224 | self.IP.rc.allow_new_attr(False) |
|
225 | 225 | return self.IP.rc |
@@ -227,22 +227,23 b' class IPApi:' | |||
|
227 | 227 | options = property(get_options,None,None,get_options.__doc__) |
|
228 | 228 | |
|
229 | 229 | def expose_magic(self,magicname, func): |
|
230 |
|
|
|
230 | """Expose own function as magic function for ipython | |
|
231 | 231 | |
|
232 | 232 | def foo_impl(self,parameter_s=''): |
|
233 |
|
|
|
234 |
print 'Magic function. Passed parameter is between < >: |
|
|
233 | 'My very own magic!. (Use docstrings, IPython reads them).' | |
|
234 | print 'Magic function. Passed parameter is between < >:' | |
|
235 | print '<%s>' % parameter_s | |
|
235 | 236 | print 'The self object is:',self |
|
236 | 237 | |
|
237 |
ipapi.expose_magic( |
|
|
238 |
|
|
|
238 | ipapi.expose_magic('foo',foo_impl) | |
|
239 | """ | |
|
239 | 240 |
|
|
240 | 241 | import new |
|
241 | 242 | im = new.instancemethod(func,self.IP, self.IP.__class__) |
|
242 | 243 | old = getattr(self.IP, "magic_" + magicname, None) |
|
243 | 244 | if old: |
|
244 |
self.dbg.debug_stack("Magic redefinition '%s', old %s" % |
|
|
245 | old)) | |
|
245 | self.dbg.debug_stack("Magic redefinition '%s', old %s" % | |
|
246 | (magicname,old) ) | |
|
246 | 247 | |
|
247 | 248 | setattr(self.IP, "magic_" + magicname, im) |
|
248 | 249 | |
@@ -267,10 +268,10 b' class IPApi:' | |||
|
267 | 268 | def cleanup_ipy_script(script): |
|
268 | 269 | """ Make a script safe for _ip.runlines() |
|
269 | 270 | |
|
270 | - Removes empty lines | |
|
271 |
- |
|
|
272 | ||
|
271 | - Removes empty lines Suffixes all indented blocks that end with | |
|
272 | - unindented lines with empty lines | |
|
273 | 273 | """ |
|
274 | ||
|
274 | 275 | res = [] |
|
275 | 276 | lines = script.splitlines() |
|
276 | 277 | |
@@ -290,7 +291,8 b' class IPApi:' | |||
|
290 | 291 | s.startswith('finally')): |
|
291 | 292 | return True |
|
292 | 293 | |
|
293 |
if level > 0 and newlevel == 0 and |
|
|
294 | if level > 0 and newlevel == 0 and \ | |
|
295 | not is_secondary_block_start(stripped): | |
|
294 | 296 | # add empty line |
|
295 | 297 | res.append('') |
|
296 | 298 | |
@@ -305,6 +307,7 b' class IPApi:' | |||
|
305 | 307 | clean=cleanup_ipy_script(script) |
|
306 | 308 | # print "_ip.runlines() script:\n",clean #dbg |
|
307 | 309 | self.IP.runlines(clean) |
|
310 | ||
|
308 | 311 | def to_user_ns(self,vars, interactive = True): |
|
309 | 312 | """Inject a group of variables into the IPython user namespace. |
|
310 | 313 | |
@@ -392,7 +395,6 b' class IPApi:' | |||
|
392 | 395 | for name,val in vdict.iteritems(): |
|
393 | 396 | config_ns[name] = val |
|
394 | 397 | |
|
395 | ||
|
396 | 398 | def expand_alias(self,line): |
|
397 | 399 | """ Expand an alias in the command line |
|
398 | 400 | |
@@ -425,11 +427,9 b' class IPApi:' | |||
|
425 | 427 | |
|
426 | 428 | self.dbg.check_hotname(name) |
|
427 | 429 | |
|
428 | ||
|
429 | 430 | if name in self.IP.alias_table: |
|
430 |
self.dbg.debug_stack("Alias redefinition: '%s' => '%s' (old '%s')" |
|
|
431 | (name, cmd, self.IP.alias_table[name])) | |
|
432 | ||
|
431 | self.dbg.debug_stack("Alias redefinition: '%s' => '%s' (old '%s')" | |
|
432 | % (name, cmd, self.IP.alias_table[name])) | |
|
433 | 433 | |
|
434 | 434 | if callable(cmd): |
|
435 | 435 | self.IP.alias_table[name] = cmd |
@@ -440,8 +440,8 b' class IPApi:' | |||
|
440 | 440 | if isinstance(cmd,basestring): |
|
441 | 441 | nargs = cmd.count('%s') |
|
442 | 442 | if nargs>0 and cmd.find('%l')>=0: |
|
443 |
raise Exception('The %s and %l specifiers are mutually |
|
|
444 | 'in alias definitions.') | |
|
443 | raise Exception('The %s and %l specifiers are mutually ' | |
|
444 | 'exclusive in alias definitions.') | |
|
445 | 445 | |
|
446 | 446 | self.IP.alias_table[name] = (nargs,cmd) |
|
447 | 447 | return |
@@ -494,8 +494,8 b' class IPApi:' | |||
|
494 | 494 | |
|
495 | 495 | - run init_ipython(ip) |
|
496 | 496 | - run ipython_firstrun(ip) |
|
497 | ||
|
498 | 497 | """ |
|
498 | ||
|
499 | 499 | if mod in self.extensions: |
|
500 | 500 | # just to make sure we don't init it twice |
|
501 | 501 | # note that if you 'load' a module that has already been |
@@ -545,6 +545,7 b' class DebugTools:' | |||
|
545 | 545 | if name in self.hotnames: |
|
546 | 546 | self.debug_stack( "HotName '%s' caught" % name) |
|
547 | 547 | |
|
548 | ||
|
548 | 549 | def launch_new_instance(user_ns = None,shellclass = None): |
|
549 | 550 | """ Make and start a new ipython instance. |
|
550 | 551 |
@@ -213,12 +213,6 b' class InteractiveShell(object,Magic):' | |||
|
213 | 213 | # log system |
|
214 | 214 | self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate') |
|
215 | 215 | |
|
216 | # some minimal strict typechecks. For some core data structures, I | |
|
217 | # want actual basic python types, not just anything that looks like | |
|
218 | # one. This is especially true for namespaces. | |
|
219 | for ns in (user_ns,user_global_ns): | |
|
220 | if ns is not None and type(ns) != types.DictType: | |
|
221 | raise TypeError,'namespace must be a dictionary' | |
|
222 | 216 | # Job manager (for jobs run as background threads) |
|
223 | 217 | self.jobs = BackgroundJobManager() |
|
224 | 218 | |
@@ -1007,10 +1001,17 b' class InteractiveShell(object,Magic):' | |||
|
1007 | 1001 | |
|
1008 | 1002 | Simple usage example: |
|
1009 | 1003 | |
|
1010 |
In [ |
|
|
1004 | In [7]: x = 'hello' | |
|
1011 | 1005 | |
|
1012 |
In [ |
|
|
1013 | Out[2]: ['x.ljust', 'x.lower', 'x.lstrip']""" | |
|
1006 | In [8]: x | |
|
1007 | Out[8]: 'hello' | |
|
1008 | ||
|
1009 | In [9]: print x | |
|
1010 | hello | |
|
1011 | ||
|
1012 | In [10]: _ip.IP.complete('x.l') | |
|
1013 | Out[10]: ['x.ljust', 'x.lower', 'x.lstrip'] # random | |
|
1014 | """ | |
|
1014 | 1015 | |
|
1015 | 1016 | complete = self.Completer.complete |
|
1016 | 1017 | state = 0 |
@@ -1026,6 +1027,8 b' class InteractiveShell(object,Magic):' | |||
|
1026 | 1027 | state += 1 |
|
1027 | 1028 | outcomps = comps.keys() |
|
1028 | 1029 | outcomps.sort() |
|
1030 | #print "T:",text,"OC:",outcomps # dbg | |
|
1031 | #print "vars:",self.user_ns.keys() | |
|
1029 | 1032 | return outcomps |
|
1030 | 1033 | |
|
1031 | 1034 | def set_completer_frame(self, frame=None): |
@@ -1636,6 +1639,7 b' want to merge them back into the new files.""" % locals()' | |||
|
1636 | 1639 | # previous call (which most likely existed in a separate scope). |
|
1637 | 1640 | local_varnames = local_ns.keys() |
|
1638 | 1641 | self.user_ns.update(local_ns) |
|
1642 | #self.user_ns['local_ns'] = local_ns # dbg | |
|
1639 | 1643 | |
|
1640 | 1644 | # Patch for global embedding to make sure that things don't overwrite |
|
1641 | 1645 | # user globals accidentally. Thanks to Richard <rxe@renre-europe.com> |
@@ -2362,7 +2366,6 b' want to merge them back into the new files.""" % locals()' | |||
|
2362 | 2366 | def handle_auto(self, line_info): |
|
2363 | 2367 | """Hande lines which can be auto-executed, quoting if requested.""" |
|
2364 | 2368 | |
|
2365 | #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg | |
|
2366 | 2369 | line = line_info.line |
|
2367 | 2370 | iFun = line_info.iFun |
|
2368 | 2371 | theRest = line_info.theRest |
@@ -2370,6 +2373,8 b' want to merge them back into the new files.""" % locals()' | |||
|
2370 | 2373 | continue_prompt = line_info.continue_prompt |
|
2371 | 2374 | obj = line_info.ofind(self)['obj'] |
|
2372 | 2375 | |
|
2376 | #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg | |
|
2377 | ||
|
2373 | 2378 | # This should only be active for single-line input! |
|
2374 | 2379 | if continue_prompt: |
|
2375 | 2380 | self.log(line,line,continue_prompt) |
@@ -88,8 +88,8 b' class Struct:' | |||
|
88 | 88 | initialization): keys can't be numbers. But numeric keys can be used and |
|
89 | 89 | accessed using the dictionary syntax. Again, an example: |
|
90 | 90 | |
|
91 | This doesn't work: | |
|
92 | >>> s=Struct(4='hi') #doctest: +IGNORE_EXCEPTION_DETAIL | |
|
91 | This doesn't work (prompt changed to avoid confusing the test system): | |
|
92 | ->> s=Struct(4='hi') | |
|
93 | 93 | Traceback (most recent call last): |
|
94 | 94 | ... |
|
95 | 95 | SyntaxError: keyword can't be an expression |
@@ -27,7 +27,7 b' from IPython.kernel import codeutil' | |||
|
27 | 27 | from IPython.kernel.clientconnector import ClientConnector |
|
28 | 28 | |
|
29 | 29 | # Other things that the user will need |
|
30 | from IPython.kernel.task import Task | |
|
30 | from IPython.kernel.task import MapTask, StringTask | |
|
31 | 31 | from IPython.kernel.error import CompositeError |
|
32 | 32 | |
|
33 | 33 | #------------------------------------------------------------------------------- |
@@ -44,7 +44,7 b' from IPython.kernel import codeutil' | |||
|
44 | 44 | import IPython.kernel.magic |
|
45 | 45 | |
|
46 | 46 | # Other things that the user will need |
|
47 | from IPython.kernel.task import Task | |
|
47 | from IPython.kernel.task import MapTask, StringTask | |
|
48 | 48 | from IPython.kernel.error import CompositeError |
|
49 | 49 | |
|
50 | 50 | #------------------------------------------------------------------------------- |
@@ -141,38 +141,3 b' class RemoteMultiEngine(RemoteContextBase):' | |||
|
141 | 141 | def __enter__(self): |
|
142 | 142 | src = self.findsource(sys._getframe(1)) |
|
143 | 143 | return self.mec.execute(src) |
|
144 | ||
|
145 | ||
|
146 | # XXX - Temporary hackish testing, we'll move this into proper tests right | |
|
147 | # away | |
|
148 | ||
|
149 | if __name__ == '__main__': | |
|
150 | ||
|
151 | # XXX - for now, we need a running cluster to be started separately. The | |
|
152 | # daemon work is almost finished, and will make much of this unnecessary. | |
|
153 | from IPython.kernel import client | |
|
154 | mec = client.MultiEngineClient(('127.0.0.1',10105)) | |
|
155 | ||
|
156 | try: | |
|
157 | mec.get_ids() | |
|
158 | except ConnectionRefusedError: | |
|
159 | import os, time | |
|
160 | os.system('ipcluster -n 2 &') | |
|
161 | time.sleep(2) | |
|
162 | mec = client.MultiEngineClient(('127.0.0.1',10105)) | |
|
163 | ||
|
164 | mec.block = False | |
|
165 | ||
|
166 | import itertools | |
|
167 | c = itertools.count() | |
|
168 | ||
|
169 | parallel = RemoteMultiEngine(mec) | |
|
170 | ||
|
171 | with parallel as pr: | |
|
172 | # A comment | |
|
173 | remote() # this means the code below only runs remotely | |
|
174 | print 'Hello remote world' | |
|
175 | x = 3.14 | |
|
176 | # Comments are OK | |
|
177 | # Even misindented. | |
|
178 | y = x+1 |
@@ -226,29 +226,31 b' class IEngineThreaded(zi.Interface):' | |||
|
226 | 226 | class StrictDict(dict): |
|
227 | 227 | """This is a strict copying dictionary for use as the interface to the |
|
228 | 228 | properties of an Engine. |
|
229 | ||
|
229 | 230 | :IMPORTANT: |
|
230 | 231 | This object copies the values you set to it, and returns copies to you |
|
231 | 232 | when you request them. The only way to change properties os explicitly |
|
232 | 233 | through the setitem and getitem of the dictionary interface. |
|
234 | ||
|
233 | 235 |
|
|
234 |
>>> e = |
|
|
235 |
>>> L = |
|
|
236 | >>> e = get_engine(id) | |
|
237 | >>> L = [1,2,3] | |
|
236 | 238 | >>> e.properties['L'] = L |
|
237 | 239 | >>> L == e.properties['L'] |
|
238 |
|
|
|
239 |
>>> L.append( |
|
|
240 | True | |
|
241 | >>> L.append(99) | |
|
240 | 242 | >>> L == e.properties['L'] |
|
241 |
|
|
|
243 | False | |
|
244 | ||
|
245 | Note that getitem copies, so calls to methods of objects do not affect | |
|
246 | the properties, as seen here: | |
|
242 | 247 | |
|
243 | getitem copies, so calls to methods of objects do not affect the | |
|
244 | properties, as in the following example: | |
|
245 | 248 | >>> e.properties[1] = range(2) |
|
246 | 249 | >>> print e.properties[1] |
|
247 |
|
|
|
250 | [0, 1] | |
|
248 | 251 | >>> e.properties[1].append(2) |
|
249 | 252 | >>> print e.properties[1] |
|
250 |
|
|
|
251 | ||
|
253 | [0, 1] | |
|
252 | 254 | """ |
|
253 | 255 | def __init__(self, *args, **kwargs): |
|
254 | 256 | dict.__init__(self, *args, **kwargs) |
@@ -395,6 +397,7 b' class EngineService(object, service.Service):' | |||
|
395 | 397 | |
|
396 | 398 | return d |
|
397 | 399 | |
|
400 | ||
|
398 | 401 | # The IEngine methods. See the interface for documentation. |
|
399 | 402 | |
|
400 | 403 | def execute(self, lines): |
@@ -862,6 +865,30 b' class ThreadedEngineService(EngineService):' | |||
|
862 | 865 | def __init__(self, shellClass=Interpreter, mpi=None): |
|
863 | 866 | EngineService.__init__(self, shellClass, mpi) |
|
864 | 867 | |
|
868 | def wrapped_execute(self, msg, lines): | |
|
869 | """Wrap self.shell.execute to add extra information to tracebacks""" | |
|
870 | ||
|
871 | try: | |
|
872 | result = self.shell.execute(lines) | |
|
873 | except Exception,e: | |
|
874 | # This gives the following: | |
|
875 | # et=exception class | |
|
876 | # ev=exception class instance | |
|
877 | # tb=traceback object | |
|
878 | et,ev,tb = sys.exc_info() | |
|
879 | # This call adds attributes to the exception value | |
|
880 | et,ev,tb = self.shell.formatTraceback(et,ev,tb,msg) | |
|
881 | # Add another attribute | |
|
882 | ||
|
883 | # Create a new exception with the new attributes | |
|
884 | e = et(ev._ipython_traceback_text) | |
|
885 | e._ipython_engine_info = msg | |
|
886 | ||
|
887 | # Re-raise | |
|
888 | raise e | |
|
889 | ||
|
890 | return result | |
|
891 | ||
|
865 | 892 | |
|
866 | 893 | def execute(self, lines): |
|
867 | 894 | # Only import this if we are going to use this class |
@@ -871,6 +898,6 b' class ThreadedEngineService(EngineService):' | |||
|
871 | 898 | 'method':'execute', |
|
872 | 899 | 'args':[lines]} |
|
873 | 900 | |
|
874 |
d = threads.deferToThread(self. |
|
|
901 | d = threads.deferToThread(self.wrapped_execute, msg, lines) | |
|
875 | 902 | d.addCallback(self.addIDToResult) |
|
876 | 903 | return d |
@@ -79,7 +79,7 b" def magic_px(self,parameter_s=''):" | |||
|
79 | 79 | except AttributeError: |
|
80 | 80 | print NO_ACTIVE_CONTROLLER |
|
81 | 81 | else: |
|
82 | print "Executing command on Controller" | |
|
82 | print "Parallel execution on engines: %s" % activeController.targets | |
|
83 | 83 | result = activeController.execute(parameter_s) |
|
84 | 84 | return result |
|
85 | 85 |
@@ -115,7 +115,7 b' class RoundRobinMap(Map):' | |||
|
115 | 115 | # result.append(concat[i:totalLength:maxPartitionLength]) |
|
116 | 116 | return self.concatenate(listOfPartitions) |
|
117 | 117 | |
|
118 |
st |
|
|
118 | dists = {'b':Map} | |
|
119 | 119 | |
|
120 | 120 | |
|
121 | 121 |
@@ -653,67 +653,55 b' components.registerAdapter(SynchronousMultiEngine, IMultiEngine, ISynchronousMul' | |||
|
653 | 653 | class IMultiEngineCoordinator(Interface): |
|
654 | 654 | """Methods that work on multiple engines explicitly.""" |
|
655 | 655 | |
|
656 |
def scatter(key, seq, st |
|
|
657 | """Partition and distribute a sequence to targets. | |
|
656 | def scatter(key, seq, dist='b', flatten=False, targets='all'): | |
|
657 | """Partition and distribute a sequence to targets.""" | |
|
658 | 658 | |
|
659 | :Parameters: | |
|
660 | key : str | |
|
661 | The variable name to call the scattered sequence. | |
|
662 | seq : list, tuple, array | |
|
663 | The sequence to scatter. The type should be preserved. | |
|
664 | style : string | |
|
665 | A specification of how the sequence is partitioned. Currently | |
|
666 | only 'basic' is implemented. | |
|
667 | flatten : boolean | |
|
668 | Should single element sequences be converted to scalars. | |
|
669 | """ | |
|
659 | def gather(key, dist='b', targets='all'): | |
|
660 | """Gather object key from targets.""" | |
|
670 | 661 |
|
|
671 |
def |
|
|
672 | """Gather object key from targets. | |
|
673 | ||
|
674 | :Parameters: | |
|
675 | key : string | |
|
676 | The name of a sequence on the targets to gather. | |
|
677 | style : string | |
|
678 | A specification of how the sequence is partitioned. Currently | |
|
679 | only 'basic' is implemented. | |
|
662 | def raw_map(func, seqs, dist='b', targets='all'): | |
|
680 | 663 |
|
|
664 | A parallelized version of Python's builtin `map` function. | |
|
681 | 665 | |
|
682 | def map(func, seq, style='basic', targets='all'): | |
|
683 | """A parallelized version of Python's builtin map. | |
|
666 | This has a slightly different syntax than the builtin `map`. | |
|
667 | This is needed because we need to have keyword arguments and thus | |
|
668 | can't use *args to capture all the sequences. Instead, they must | |
|
669 | be passed in a list or tuple. | |
|
684 | 670 | |
|
685 | This function implements the following pattern: | |
|
671 | The equivalence is: | |
|
686 | 672 | |
|
687 | 1. The sequence seq is scattered to the given targets. | |
|
688 | 2. map(functionSource, seq) is called on each engine. | |
|
689 | 3. The resulting sequences are gathered back to the local machine. | |
|
673 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |
|
690 | 674 |
|
|
691 | :Parameters: | |
|
692 | targets : int, list or 'all' | |
|
693 | The engine ids the action will apply to. Call `get_ids` to see | |
|
694 | a list of currently available engines. | |
|
695 | func : str, function | |
|
696 | An actual function object or a Python string that names a | |
|
697 | callable defined on the engines. | |
|
698 | seq : list, tuple or numpy array | |
|
699 | The local sequence to be scattered. | |
|
700 | style : str | |
|
701 | Only 'basic' is supported for now. | |
|
702 | ||
|
703 | :Returns: A list of len(seq) with functionSource called on each element | |
|
704 | of seq. | |
|
705 | ||
|
706 | Example | |
|
707 | ======= | |
|
708 | ||
|
709 | >>> rc.mapAll('lambda x: x*x', range(10000)) | |
|
710 | [0,2,4,9,25,36,...] | |
|
675 | Most users will want to use parallel functions or the `mapper` | |
|
676 | and `map` methods for an API that follows that of the builtin | |
|
677 | `map`. | |
|
711 | 678 | """ |
|
712 | 679 | |
|
713 | 680 | |
|
714 | 681 | class ISynchronousMultiEngineCoordinator(IMultiEngineCoordinator): |
|
715 | 682 | """Methods that work on multiple engines explicitly.""" |
|
716 | pass | |
|
683 | ||
|
684 | def scatter(key, seq, dist='b', flatten=False, targets='all', block=True): | |
|
685 | """Partition and distribute a sequence to targets.""" | |
|
686 | ||
|
687 | def gather(key, dist='b', targets='all', block=True): | |
|
688 | """Gather object key from targets""" | |
|
689 | ||
|
690 | def raw_map(func, seqs, dist='b', targets='all', block=True): | |
|
691 | """ | |
|
692 | A parallelized version of Python's builtin map. | |
|
693 | ||
|
694 | This has a slightly different syntax than the builtin `map`. | |
|
695 | This is needed because we need to have keyword arguments and thus | |
|
696 | can't use *args to capture all the sequences. Instead, they must | |
|
697 | be passed in a list or tuple. | |
|
698 | ||
|
699 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |
|
700 | ||
|
701 | Most users will want to use parallel functions or the `mapper` | |
|
702 | and `map` methods for an API that follows that of the builtin | |
|
703 | `map`. | |
|
704 | """ | |
|
717 | 705 | |
|
718 | 706 | |
|
719 | 707 | #------------------------------------------------------------------------------- |
@@ -722,46 +710,31 b' class ISynchronousMultiEngineCoordinator(IMultiEngineCoordinator):' | |||
|
722 | 710 | |
|
723 | 711 | class IMultiEngineExtras(Interface): |
|
724 | 712 | |
|
725 |
def zip_pull(targets, |
|
|
726 | """Pull, but return results in a different format from `pull`. | |
|
713 | def zip_pull(targets, keys): | |
|
714 | """ | |
|
715 | Pull, but return results in a different format from `pull`. | |
|
727 | 716 | |
|
728 | 717 | This method basically returns zip(pull(targets, *keys)), with a few |
|
729 | 718 | edge cases handled differently. Users of chainsaw will find this format |
|
730 | 719 | familiar. |
|
731 | ||
|
732 | :Parameters: | |
|
733 | targets : int, list or 'all' | |
|
734 | The engine ids the action will apply to. Call `get_ids` to see | |
|
735 | a list of currently available engines. | |
|
736 | keys: list or tuple of str | |
|
737 | A list of variable names as string of the Python objects to be pulled | |
|
738 | back to the client. | |
|
739 | ||
|
740 | :Returns: A list of pulled Python objects for each target. | |
|
741 | 720 | """ |
|
742 | 721 | |
|
743 | 722 | def run(targets, fname): |
|
744 | """Run a .py file on targets. | |
|
745 | ||
|
746 | :Parameters: | |
|
747 | targets : int, list or 'all' | |
|
748 | The engine ids the action will apply to. Call `get_ids` to see | |
|
749 | a list of currently available engines. | |
|
750 | fname : str | |
|
751 | The filename of a .py file on the local system to be sent to and run | |
|
752 | on the engines. | |
|
753 | block : boolean | |
|
754 | Should I block or not. If block=True, wait for the action to | |
|
755 | complete and return the result. If block=False, return a | |
|
756 | `PendingResult` object that can be used to later get the | |
|
757 | result. If block is not specified, the block attribute | |
|
758 | will be used instead. | |
|
759 | """ | |
|
723 | """Run a .py file on targets.""" | |
|
760 | 724 | |
|
761 | 725 | |
|
762 | 726 | class ISynchronousMultiEngineExtras(IMultiEngineExtras): |
|
763 | pass | |
|
727 | def zip_pull(targets, keys, block=True): | |
|
728 | """ | |
|
729 | Pull, but return results in a different format from `pull`. | |
|
730 | ||
|
731 | This method basically returns zip(pull(targets, *keys)), with a few | |
|
732 | edge cases handled differently. Users of chainsaw will find this format | |
|
733 | familiar. | |
|
734 | """ | |
|
764 | 735 | |
|
736 | def run(targets, fname, block=True): | |
|
737 | """Run a .py file on targets.""" | |
|
765 | 738 | |
|
766 | 739 | #------------------------------------------------------------------------------- |
|
767 | 740 | # The full MultiEngine interface |
@@ -31,6 +31,11 b' from IPython.ColorANSI import TermColors' | |||
|
31 | 31 | from IPython.kernel.twistedutil import blockingCallFromThread |
|
32 | 32 | from IPython.kernel import error |
|
33 | 33 | from IPython.kernel.parallelfunction import ParallelFunction |
|
34 | from IPython.kernel.mapper import ( | |
|
35 | MultiEngineMapper, | |
|
36 | IMultiEngineMapperFactory, | |
|
37 | IMapper | |
|
38 | ) | |
|
34 | 39 | from IPython.kernel import map as Map |
|
35 | 40 | from IPython.kernel import multiengine as me |
|
36 | 41 | from IPython.kernel.multiengine import (IFullMultiEngine, |
@@ -186,6 +191,10 b' class ResultList(list):' | |||
|
186 | 191 | |
|
187 | 192 | def __repr__(self): |
|
188 | 193 | output = [] |
|
194 | # These colored prompts were not working on Windows | |
|
195 | if sys.platform == 'win32': | |
|
196 | blue = normal = red = green = '' | |
|
197 | else: | |
|
189 | 198 | blue = TermColors.Blue |
|
190 | 199 | normal = TermColors.Normal |
|
191 | 200 | red = TermColors.Red |
@@ -295,34 +304,6 b' class InteractiveMultiEngineClient(object):' | |||
|
295 | 304 | """Return the number of available engines.""" |
|
296 | 305 | return len(self.get_ids()) |
|
297 | 306 |
|
|
298 | def parallelize(self, func, targets=None, block=None): | |
|
299 | """Build a `ParallelFunction` object for functionName on engines. | |
|
300 | ||
|
301 | The returned object will implement a parallel version of functionName | |
|
302 | that takes a local sequence as its only argument and calls (in | |
|
303 | parallel) functionName on each element of that sequence. The | |
|
304 | `ParallelFunction` object has a `targets` attribute that controls | |
|
305 | which engines the function is run on. | |
|
306 | ||
|
307 | :Parameters: | |
|
308 | targets : int, list or 'all' | |
|
309 | The engine ids the action will apply to. Call `get_ids` to see | |
|
310 | a list of currently available engines. | |
|
311 | functionName : str | |
|
312 | A Python string that names a callable defined on the engines. | |
|
313 | ||
|
314 | :Returns: A `ParallelFunction` object. | |
|
315 | ||
|
316 | Examples | |
|
317 | ======== | |
|
318 | ||
|
319 | >>> psin = rc.parallelize('all','lambda x:sin(x)') | |
|
320 | >>> psin(range(10000)) | |
|
321 | [0,2,4,9,25,36,...] | |
|
322 | """ | |
|
323 | targets, block = self._findTargetsAndBlock(targets, block) | |
|
324 | return ParallelFunction(func, self, targets, block) | |
|
325 | ||
|
326 | 307 | #--------------------------------------------------------------------------- |
|
327 | 308 | # Make this a context manager for with |
|
328 | 309 | #--------------------------------------------------------------------------- |
@@ -422,7 +403,11 b' class FullBlockingMultiEngineClient(InteractiveMultiEngineClient):' | |||
|
422 | 403 | engine, run code on it, etc. |
|
423 | 404 | """ |
|
424 | 405 | |
|
425 | implements(IFullBlockingMultiEngineClient) | |
|
406 | implements( | |
|
407 | IFullBlockingMultiEngineClient, | |
|
408 | IMultiEngineMapperFactory, | |
|
409 | IMapper | |
|
410 | ) | |
|
426 | 411 | |
|
427 | 412 | def __init__(self, smultiengine): |
|
428 | 413 | self.smultiengine = smultiengine |
@@ -779,29 +764,100 b' class FullBlockingMultiEngineClient(InteractiveMultiEngineClient):' | |||
|
779 | 764 | # IMultiEngineCoordinator |
|
780 | 765 | #--------------------------------------------------------------------------- |
|
781 | 766 | |
|
782 |
def scatter(self, key, seq, st |
|
|
767 | def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None): | |
|
783 | 768 | """ |
|
784 | 769 | Partition a Python sequence and send the partitions to a set of engines. |
|
785 | 770 | """ |
|
786 | 771 | targets, block = self._findTargetsAndBlock(targets, block) |
|
787 | 772 | return self._blockFromThread(self.smultiengine.scatter, key, seq, |
|
788 |
st |
|
|
773 | dist, flatten, targets=targets, block=block) | |
|
789 | 774 | |
|
790 |
def gather(self, key, st |
|
|
775 | def gather(self, key, dist='b', targets=None, block=None): | |
|
791 | 776 | """ |
|
792 | 777 | Gather a partitioned sequence on a set of engines as a single local seq. |
|
793 | 778 | """ |
|
794 | 779 | targets, block = self._findTargetsAndBlock(targets, block) |
|
795 |
return self._blockFromThread(self.smultiengine.gather, key, st |
|
|
780 | return self._blockFromThread(self.smultiengine.gather, key, dist, | |
|
796 | 781 | targets=targets, block=block) |
|
797 | 782 | |
|
798 |
def map(self, func, seq, st |
|
|
783 | def raw_map(self, func, seq, dist='b', targets=None, block=None): | |
|
784 | """ | |
|
785 | A parallelized version of Python's builtin map. | |
|
786 | ||
|
787 | This has a slightly different syntax than the builtin `map`. | |
|
788 | This is needed because we need to have keyword arguments and thus | |
|
789 | can't use *args to capture all the sequences. Instead, they must | |
|
790 | be passed in a list or tuple. | |
|
791 | ||
|
792 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |
|
793 | ||
|
794 | Most users will want to use parallel functions or the `mapper` | |
|
795 | and `map` methods for an API that follows that of the builtin | |
|
796 | `map`. | |
|
797 | """ | |
|
798 | targets, block = self._findTargetsAndBlock(targets, block) | |
|
799 | return self._blockFromThread(self.smultiengine.raw_map, func, seq, | |
|
800 | dist, targets=targets, block=block) | |
|
801 | ||
|
802 | def map(self, func, *sequences): | |
|
803 | """ | |
|
804 | A parallel version of Python's builtin `map` function. | |
|
805 | ||
|
806 | This method applies a function to sequences of arguments. It | |
|
807 | follows the same syntax as the builtin `map`. | |
|
808 | ||
|
809 | This method creates a mapper objects by calling `self.mapper` with | |
|
810 | no arguments and then uses that mapper to do the mapping. See | |
|
811 | the documentation of `mapper` for more details. | |
|
812 | """ | |
|
813 | return self.mapper().map(func, *sequences) | |
|
814 | ||
|
815 | def mapper(self, dist='b', targets='all', block=None): | |
|
816 | """ | |
|
817 | Create a mapper object that has a `map` method. | |
|
818 | ||
|
819 | This method returns an object that implements the `IMapper` | |
|
820 | interface. This method is a factory that is used to control how | |
|
821 | the map happens. | |
|
822 | ||
|
823 | :Parameters: | |
|
824 | dist : str | |
|
825 | What decomposition to use, 'b' is the only one supported | |
|
826 | currently | |
|
827 | targets : str, int, sequence of ints | |
|
828 | Which engines to use for the map | |
|
829 | block : boolean | |
|
830 | Should calls to `map` block or not | |
|
831 | """ | |
|
832 | return MultiEngineMapper(self, dist, targets, block) | |
|
833 | ||
|
834 | def parallel(self, dist='b', targets=None, block=None): | |
|
799 | 835 | """ |
|
800 | A parallelized version of Python's builtin map | |
|
836 | A decorator that turns a function into a parallel function. | |
|
837 | ||
|
838 | This can be used as: | |
|
839 | ||
|
840 | @parallel() | |
|
841 | def f(x, y) | |
|
842 | ... | |
|
843 | ||
|
844 | f(range(10), range(10)) | |
|
845 | ||
|
846 | This causes f(0,0), f(1,1), ... to be called in parallel. | |
|
847 | ||
|
848 | :Parameters: | |
|
849 | dist : str | |
|
850 | What decomposition to use, 'b' is the only one supported | |
|
851 | currently | |
|
852 | targets : str, int, sequence of ints | |
|
853 | Which engines to use for the map | |
|
854 | block : boolean | |
|
855 | Should calls to `map` block or not | |
|
801 | 856 | """ |
|
802 | 857 | targets, block = self._findTargetsAndBlock(targets, block) |
|
803 | return self._blockFromThread(self.smultiengine.map, func, seq, | |
|
804 | style, targets=targets, block=block) | |
|
858 | mapper = self.mapper(dist, targets, block) | |
|
859 | pf = ParallelFunction(mapper) | |
|
860 | return pf | |
|
805 | 861 | |
|
806 | 862 | #--------------------------------------------------------------------------- |
|
807 | 863 | # IMultiEngineExtras |
@@ -29,6 +29,12 b' from foolscap import Referenceable' | |||
|
29 | 29 | from IPython.kernel import error |
|
30 | 30 | from IPython.kernel.util import printer |
|
31 | 31 | from IPython.kernel import map as Map |
|
32 | from IPython.kernel.parallelfunction import ParallelFunction | |
|
33 | from IPython.kernel.mapper import ( | |
|
34 | MultiEngineMapper, | |
|
35 | IMultiEngineMapperFactory, | |
|
36 | IMapper | |
|
37 | ) | |
|
32 | 38 | from IPython.kernel.twistedutil import gatherBoth |
|
33 | 39 | from IPython.kernel.multiengine import (MultiEngine, |
|
34 | 40 | IMultiEngine, |
@@ -280,7 +286,12 b' components.registerAdapter(FCSynchronousMultiEngineFromMultiEngine,' | |||
|
280 | 286 | |
|
281 | 287 | class FCFullSynchronousMultiEngineClient(object): |
|
282 | 288 | |
|
283 | implements(IFullSynchronousMultiEngine, IBlockingClientAdaptor) | |
|
289 | implements( | |
|
290 | IFullSynchronousMultiEngine, | |
|
291 | IBlockingClientAdaptor, | |
|
292 | IMultiEngineMapperFactory, | |
|
293 | IMapper | |
|
294 | ) | |
|
284 | 295 | |
|
285 | 296 | def __init__(self, remote_reference): |
|
286 | 297 | self.remote_reference = remote_reference |
@@ -475,7 +486,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||
|
475 | 486 | d.addCallback(create_targets) |
|
476 | 487 | return d |
|
477 | 488 | |
|
478 |
def scatter(self, key, seq, st |
|
|
489 | def scatter(self, key, seq, dist='b', flatten=False, targets='all', block=True): | |
|
479 | 490 | |
|
480 | 491 | # Note: scatter and gather handle pending deferreds locally through self.pdm. |
|
481 | 492 | # This enables us to collect a bunch fo deferred ids and make a secondary |
@@ -483,7 +494,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||
|
483 | 494 | # difficult to get right though. |
|
484 | 495 | def do_scatter(engines): |
|
485 | 496 | nEngines = len(engines) |
|
486 |
mapClass = Map.st |
|
|
497 | mapClass = Map.dists[dist] | |
|
487 | 498 | mapObject = mapClass() |
|
488 | 499 | d_list = [] |
|
489 | 500 | # Loop through and push to each engine in non-blocking mode. |
@@ -541,7 +552,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||
|
541 | 552 | d.addCallback(do_scatter) |
|
542 | 553 | return d |
|
543 | 554 | |
|
544 |
def gather(self, key, st |
|
|
555 | def gather(self, key, dist='b', targets='all', block=True): | |
|
545 | 556 | |
|
546 | 557 | # Note: scatter and gather handle pending deferreds locally through self.pdm. |
|
547 | 558 | # This enables us to collect a bunch fo deferred ids and make a secondary |
@@ -549,7 +560,7 b' class FCFullSynchronousMultiEngineClient(object):' | |||
|
549 | 560 | # difficult to get right though. |
|
550 | 561 | def do_gather(engines): |
|
551 | 562 | nEngines = len(engines) |
|
552 |
mapClass = Map.st |
|
|
563 | mapClass = Map.dists[dist] | |
|
553 | 564 | mapObject = mapClass() |
|
554 | 565 | d_list = [] |
|
555 | 566 | # Loop through and push to each engine in non-blocking mode. |
@@ -604,25 +615,103 b' class FCFullSynchronousMultiEngineClient(object):' | |||
|
604 | 615 | d.addCallback(do_gather) |
|
605 | 616 | return d |
|
606 | 617 | |
|
607 |
def map(self, func, seq, st |
|
|
608 | d_list = [] | |
|
618 | def raw_map(self, func, sequences, dist='b', targets='all', block=True): | |
|
619 | """ | |
|
620 | A parallelized version of Python's builtin map. | |
|
621 | ||
|
622 | This has a slightly different syntax than the builtin `map`. | |
|
623 | This is needed because we need to have keyword arguments and thus | |
|
624 | can't use *args to capture all the sequences. Instead, they must | |
|
625 | be passed in a list or tuple. | |
|
626 | ||
|
627 | raw_map(func, seqs) -> map(func, seqs[0], seqs[1], ...) | |
|
628 | ||
|
629 | Most users will want to use parallel functions or the `mapper` | |
|
630 | and `map` methods for an API that follows that of the builtin | |
|
631 | `map`. | |
|
632 | """ | |
|
633 | if not isinstance(sequences, (list, tuple)): | |
|
634 | raise TypeError('sequences must be a list or tuple') | |
|
635 | max_len = max(len(s) for s in sequences) | |
|
636 | for s in sequences: | |
|
637 | if len(s)!=max_len: | |
|
638 | raise ValueError('all sequences must have equal length') | |
|
609 | 639 | if isinstance(func, FunctionType): |
|
610 | 640 | d = self.push_function(dict(_ipython_map_func=func), targets=targets, block=False) |
|
611 | 641 | d.addCallback(lambda did: self.get_pending_deferred(did, True)) |
|
612 | sourceToRun = '_ipython_map_seq_result = map(_ipython_map_func, _ipython_map_seq)' | |
|
642 | sourceToRun = '_ipython_map_seq_result = map(_ipython_map_func, *zip(*_ipython_map_seq))' | |
|
613 | 643 | elif isinstance(func, str): |
|
614 | 644 | d = defer.succeed(None) |
|
615 | 645 | sourceToRun = \ |
|
616 | '_ipython_map_seq_result = map(%s, _ipython_map_seq)' % func | |
|
646 | '_ipython_map_seq_result = map(%s, *zip(*_ipython_map_seq))' % func | |
|
617 | 647 | else: |
|
618 | 648 | raise TypeError("func must be a function or str") |
|
619 | 649 | |
|
620 |
d.addCallback(lambda _: self.scatter('_ipython_map_seq', seq, st |
|
|
650 | d.addCallback(lambda _: self.scatter('_ipython_map_seq', zip(*sequences), dist, targets=targets)) | |
|
621 | 651 | d.addCallback(lambda _: self.execute(sourceToRun, targets=targets, block=False)) |
|
622 | 652 | d.addCallback(lambda did: self.get_pending_deferred(did, True)) |
|
623 |
d.addCallback(lambda _: self.gather('_ipython_map_seq_result', st |
|
|
653 | d.addCallback(lambda _: self.gather('_ipython_map_seq_result', dist, targets=targets, block=block)) | |
|
624 | 654 | return d |
|
625 | 655 | |
|
656 | def map(self, func, *sequences): | |
|
657 | """ | |
|
658 | A parallel version of Python's builtin `map` function. | |
|
659 | ||
|
660 | This method applies a function to sequences of arguments. It | |
|
661 | follows the same syntax as the builtin `map`. | |
|
662 | ||
|
663 | This method creates a mapper objects by calling `self.mapper` with | |
|
664 | no arguments and then uses that mapper to do the mapping. See | |
|
665 | the documentation of `mapper` for more details. | |
|
666 | """ | |
|
667 | return self.mapper().map(func, *sequences) | |
|
668 | ||
|
669 | def mapper(self, dist='b', targets='all', block=True): | |
|
670 | """ | |
|
671 | Create a mapper object that has a `map` method. | |
|
672 | ||
|
673 | This method returns an object that implements the `IMapper` | |
|
674 | interface. This method is a factory that is used to control how | |
|
675 | the map happens. | |
|
676 | ||
|
677 | :Parameters: | |
|
678 | dist : str | |
|
679 | What decomposition to use, 'b' is the only one supported | |
|
680 | currently | |
|
681 | targets : str, int, sequence of ints | |
|
682 | Which engines to use for the map | |
|
683 | block : boolean | |
|
684 | Should calls to `map` block or not | |
|
685 | """ | |
|
686 | return MultiEngineMapper(self, dist, targets, block) | |
|
687 | ||
|
688 | def parallel(self, dist='b', targets='all', block=True): | |
|
689 | """ | |
|
690 | A decorator that turns a function into a parallel function. | |
|
691 | ||
|
692 | This can be used as: | |
|
693 | ||
|
694 | @parallel() | |
|
695 | def f(x, y) | |
|
696 | ... | |
|
697 | ||
|
698 | f(range(10), range(10)) | |
|
699 | ||
|
700 | This causes f(0,0), f(1,1), ... to be called in parallel. | |
|
701 | ||
|
702 | :Parameters: | |
|
703 | dist : str | |
|
704 | What decomposition to use, 'b' is the only one supported | |
|
705 | currently | |
|
706 | targets : str, int, sequence of ints | |
|
707 | Which engines to use for the map | |
|
708 | block : boolean | |
|
709 | Should calls to `map` block or not | |
|
710 | """ | |
|
711 | mapper = self.mapper(dist, targets, block) | |
|
712 | pf = ParallelFunction(mapper) | |
|
713 | return pf | |
|
714 | ||
|
626 | 715 | #--------------------------------------------------------------------------- |
|
627 | 716 | # ISynchronousMultiEngineExtras related methods |
|
628 | 717 | #--------------------------------------------------------------------------- |
@@ -16,17 +16,92 b' __docformat__ = "restructuredtext en"' | |||
|
16 | 16 | #------------------------------------------------------------------------------- |
|
17 | 17 | |
|
18 | 18 | from types import FunctionType |
|
19 | from zope.interface import Interface, implements | |
|
19 | 20 | |
|
20 | class ParallelFunction: | |
|
21 | """A function that operates in parallel on sequences.""" | |
|
22 | def __init__(self, func, multiengine, targets, block): | |
|
23 | """Create a `ParallelFunction`. | |
|
21 | ||
|
22 | class IMultiEngineParallelDecorator(Interface): | |
|
23 | """A decorator that creates a parallel function.""" | |
|
24 | ||
|
25 | def parallel(dist='b', targets=None, block=None): | |
|
26 | """ | |
|
27 | A decorator that turns a function into a parallel function. | |
|
28 | ||
|
29 | This can be used as: | |
|
30 | ||
|
31 | @parallel() | |
|
32 | def f(x, y) | |
|
33 | ... | |
|
34 | ||
|
35 | f(range(10), range(10)) | |
|
36 | ||
|
37 | This causes f(0,0), f(1,1), ... to be called in parallel. | |
|
38 | ||
|
39 | :Parameters: | |
|
40 | dist : str | |
|
41 | What decomposition to use, 'b' is the only one supported | |
|
42 | currently | |
|
43 | targets : str, int, sequence of ints | |
|
44 | Which engines to use for the map | |
|
45 | block : boolean | |
|
46 | Should calls to `map` block or not | |
|
47 | """ | |
|
48 | ||
|
49 | class ITaskParallelDecorator(Interface): | |
|
50 | """A decorator that creates a parallel function.""" | |
|
51 | ||
|
52 | def parallel(clear_before=False, clear_after=False, retries=0, | |
|
53 | recovery_task=None, depend=None, block=True): | |
|
54 | """ | |
|
55 | A decorator that turns a function into a parallel function. | |
|
56 | ||
|
57 | This can be used as: | |
|
58 | ||
|
59 | @parallel() | |
|
60 | def f(x, y) | |
|
61 | ... | |
|
62 | ||
|
63 | f(range(10), range(10)) | |
|
64 | ||
|
65 | This causes f(0,0), f(1,1), ... to be called in parallel. | |
|
66 | ||
|
67 | See the documentation for `IPython.kernel.task.BaseTask` for | |
|
68 | documentation on the arguments to this method. | |
|
69 | """ | |
|
70 | ||
|
71 | class IParallelFunction(Interface): | |
|
72 | pass | |
|
73 | ||
|
74 | class ParallelFunction(object): | |
|
75 | """ | |
|
76 | The implementation of a parallel function. | |
|
77 | ||
|
78 | A parallel function is similar to Python's map function: | |
|
79 | ||
|
80 | map(func, *sequences) -> pfunc(*sequences) | |
|
81 | ||
|
82 | Parallel functions should be created by using the @parallel decorator. | |
|
83 | """ | |
|
84 | ||
|
85 | implements(IParallelFunction) | |
|
86 | ||
|
87 | def __init__(self, mapper): | |
|
88 | """ | |
|
89 | Create a parallel function from an `IMapper`. | |
|
90 | ||
|
91 | :Parameters: | |
|
92 | mapper : an `IMapper` implementer. | |
|
93 | The mapper to use for the parallel function | |
|
94 | """ | |
|
95 | self.mapper = mapper | |
|
96 | ||
|
97 | def __call__(self, func): | |
|
98 | """ | |
|
99 | Decorate a function to make it run in parallel. | |
|
24 | 100 | """ |
|
25 | 101 | assert isinstance(func, (str, FunctionType)), "func must be a fuction or str" |
|
26 | 102 | self.func = func |
|
27 | self.multiengine = multiengine | |
|
28 | self.targets = targets | |
|
29 | self.block = block | |
|
103 | def call_function(*sequences): | |
|
104 | return self.mapper.map(self.func, *sequences) | |
|
105 | return call_function | |
|
106 | ||
|
30 | 107 |
|
|
No newline at end of file | ||
|
31 | def __call__(self, sequence): | |
|
32 | return self.multiengine.map(self.func, sequence, targets=self.targets, block=self.block) No newline at end of file |
This diff has been collapsed as it changes many lines, (656 lines changed) Show them Hide them | |||
@@ -5,116 +5,404 b'' | |||
|
5 | 5 | |
|
6 | 6 | __docformat__ = "restructuredtext en" |
|
7 | 7 | |
|
8 |
#----------------------------------------------------------------------------- |
|
|
8 | #----------------------------------------------------------------------------- | |
|
9 | 9 | # Copyright (C) 2008 The IPython Development Team |
|
10 | 10 | # |
|
11 | 11 | # Distributed under the terms of the BSD License. The full license is in |
|
12 | 12 | # the file COPYING, distributed as part of this software. |
|
13 |
#----------------------------------------------------------------------------- |
|
|
13 | #----------------------------------------------------------------------------- | |
|
14 | 14 | |
|
15 |
#----------------------------------------------------------------------------- |
|
|
15 | #----------------------------------------------------------------------------- | |
|
16 | 16 | # Imports |
|
17 |
#----------------------------------------------------------------------------- |
|
|
17 | #----------------------------------------------------------------------------- | |
|
18 | 18 | |
|
19 | 19 | import copy, time |
|
20 |
from types import FunctionType |
|
|
20 | from types import FunctionType | |
|
21 | 21 | |
|
22 | 22 | import zope.interface as zi, string |
|
23 | 23 | from twisted.internet import defer, reactor |
|
24 | 24 | from twisted.python import components, log, failure |
|
25 | 25 | |
|
26 |
|
|
|
27 | ||
|
26 | from IPython.kernel.util import printer | |
|
28 | 27 | from IPython.kernel import engineservice as es, error |
|
29 | 28 | from IPython.kernel import controllerservice as cs |
|
30 | 29 | from IPython.kernel.twistedutil import gatherBoth, DeferredList |
|
31 | 30 | |
|
32 | 31 | from IPython.kernel.pickleutil import can,uncan, CannedFunction |
|
33 | 32 | |
|
34 | def canTask(task): | |
|
35 | t = copy.copy(task) | |
|
36 | t.depend = can(t.depend) | |
|
37 | if t.recovery_task: | |
|
38 | t.recovery_task = canTask(t.recovery_task) | |
|
39 | return t | |
|
40 | ||
|
41 | def uncanTask(task): | |
|
42 | t = copy.copy(task) | |
|
43 | t.depend = uncan(t.depend) | |
|
44 | if t.recovery_task and t.recovery_task is not task: | |
|
45 | t.recovery_task = uncanTask(t.recovery_task) | |
|
46 | return t | |
|
33 | #----------------------------------------------------------------------------- | |
|
34 | # Definition of the Task objects | |
|
35 | #----------------------------------------------------------------------------- | |
|
47 | 36 | |
|
48 | 37 | time_format = '%Y/%m/%d %H:%M:%S' |
|
49 | 38 | |
|
50 |
class Task( |
|
|
51 | """Our representation of a task for the `TaskController` interface. | |
|
39 | class ITask(zi.Interface): | |
|
40 | """ | |
|
41 | This interface provides a generic definition of what constitutes a task. | |
|
42 | ||
|
43 | There are two sides to a task. First a task needs to take input from | |
|
44 | a user to determine what work is performed by the task. Second, the | |
|
45 | task needs to have the logic that knows how to turn that information | |
|
46 | info specific calls to a worker, through the `IQueuedEngine` interface. | |
|
47 | ||
|
48 | Many method in this class get two things passed to them: a Deferred | |
|
49 | and an IQueuedEngine implementer. Such methods should register callbacks | |
|
50 | on the Deferred that use the IQueuedEngine to accomplish something. See | |
|
51 | the existing task objects for examples. | |
|
52 | """ | |
|
53 | ||
|
54 | zi.Attribute('retries','How many times to retry the task') | |
|
55 | zi.Attribute('recovery_task','A task to try if the initial one fails') | |
|
56 | zi.Attribute('taskid','the id of the task') | |
|
57 | ||
|
58 | def start_time(result): | |
|
59 | """ | |
|
60 | Do anything needed to start the timing of the task. | |
|
61 | ||
|
62 | Must simply return the result after starting the timers. | |
|
63 | """ | |
|
64 | ||
|
65 | def stop_time(result): | |
|
66 | """ | |
|
67 | Do anything needed to stop the timing of the task. | |
|
68 | ||
|
69 | Must simply return the result after stopping the timers. This | |
|
70 | method will usually set attributes that are used by `process_result` | |
|
71 | in building result of the task. | |
|
72 | """ | |
|
73 | ||
|
74 | def pre_task(d, queued_engine): | |
|
75 | """Do something with the queued_engine before the task is run. | |
|
76 | ||
|
77 | This method should simply add callbacks to the input Deferred | |
|
78 | that do something with the `queued_engine` before the task is run. | |
|
79 | ||
|
80 | :Parameters: | |
|
81 | d : Deferred | |
|
82 | The deferred that actions should be attached to | |
|
83 | queued_engine : IQueuedEngine implementer | |
|
84 | The worker that has been allocated to perform the task | |
|
85 | """ | |
|
86 | ||
|
87 | def post_task(d, queued_engine): | |
|
88 | """Do something with the queued_engine after the task is run. | |
|
89 | ||
|
90 | This method should simply add callbacks to the input Deferred | |
|
91 | that do something with the `queued_engine` before the task is run. | |
|
92 | ||
|
93 | :Parameters: | |
|
94 | d : Deferred | |
|
95 | The deferred that actions should be attached to | |
|
96 | queued_engine : IQueuedEngine implementer | |
|
97 | The worker that has been allocated to perform the task | |
|
98 | """ | |
|
99 | ||
|
100 | def submit_task(d, queued_engine): | |
|
101 | """Submit a task using the `queued_engine` we have been allocated. | |
|
102 | ||
|
103 | When a task is ready to run, this method is called. This method | |
|
104 | must take the internal information of the task and make suitable | |
|
105 | calls on the queued_engine to have the actual work done. | |
|
106 | ||
|
107 | This method should simply add callbacks to the input Deferred | |
|
108 | that do something with the `queued_engine` before the task is run. | |
|
109 | ||
|
110 | :Parameters: | |
|
111 | d : Deferred | |
|
112 | The deferred that actions should be attached to | |
|
113 | queued_engine : IQueuedEngine implementer | |
|
114 | The worker that has been allocated to perform the task | |
|
115 | """ | |
|
116 | ||
|
117 | def process_result(d, result, engine_id): | |
|
118 | """Take a raw task result. | |
|
119 | ||
|
120 | Objects that implement `ITask` can choose how the result of running | |
|
121 | the task is presented. This method takes the raw result and | |
|
122 | does this logic. Two example are the `MapTask` which simply returns | |
|
123 | the raw result or a `Failure` object and the `StringTask` which | |
|
124 | returns a `TaskResult` object. | |
|
125 | ||
|
126 | :Parameters: | |
|
127 | d : Deferred | |
|
128 | The deferred that actions should be attached to | |
|
129 | result : object | |
|
130 | The raw task result that needs to be wrapped | |
|
131 | engine_id : int | |
|
132 | The id of the engine that did the task | |
|
133 | ||
|
134 | :Returns: | |
|
135 | The result, as a tuple of the form: (success, result). | |
|
136 | Here, success is a boolean indicating if the task | |
|
137 | succeeded or failed and result is the result. | |
|
138 | """ | |
|
52 | 139 | |
|
53 | The user should create instances of this class to represent a task that | |
|
54 | needs to be done. | |
|
140 | def check_depend(properties): | |
|
141 | """Check properties to see if the task should be run. | |
|
142 | ||
|
143 | :Parameters: | |
|
144 | properties : dict | |
|
145 | A dictionary of properties that an engine has set | |
|
146 | ||
|
147 | :Returns: | |
|
148 | True if the task should be run, False otherwise | |
|
149 | """ | |
|
150 | ||
|
151 | def can_task(self): | |
|
152 | """Serialize (can) any functions in the task for pickling. | |
|
153 | ||
|
154 | Subclasses must override this method and make sure that all | |
|
155 | functions in the task are canned by calling `can` on the | |
|
156 | function. | |
|
157 | """ | |
|
158 | ||
|
159 | def uncan_task(self): | |
|
160 | """Unserialize (uncan) any canned function in the task.""" | |
|
161 | ||
|
162 | class BaseTask(object): | |
|
163 | """ | |
|
164 | Common fuctionality for all objects implementing `ITask`. | |
|
165 | """ | |
|
166 | ||
|
167 | zi.implements(ITask) | |
|
168 | ||
|
169 | def __init__(self, clear_before=False, clear_after=False, retries=0, | |
|
170 | recovery_task=None, depend=None): | |
|
171 | """ | |
|
172 | Make a generic task. | |
|
55 | 173 | |
|
56 | 174 | :Parameters: |
|
57 | expression : str | |
|
58 | A str that is valid python code that is the task. | |
|
59 | pull : str or list of str | |
|
60 | The names of objects to be pulled as results. If not specified, | |
|
61 | will return {'result', None} | |
|
62 | push : dict | |
|
63 | A dict of objects to be pushed into the engines namespace before | |
|
64 | execution of the expression. | |
|
65 | 175 | clear_before : boolean |
|
66 |
Should the engine |
|
|
67 | Default=False. | |
|
176 | Should the engines namespace be cleared before the task | |
|
177 | is run | |
|
68 | 178 |
clear_after : boolean |
|
69 |
Should the engine |
|
|
70 | Default=False. | |
|
179 | Should the engines namespace be clear after the task is run | |
|
71 | 180 | retries : int |
|
72 |
The number of times |
|
|
73 |
recovery_task : |
|
|
74 | This is the Task to be run when the task has exhausted its retries | |
|
75 |
|
|
|
76 |
depend : |
|
|
77 | This is the dependency function for the Task, which determines | |
|
78 | whether a task can be run on a Worker. `depend` is called with | |
|
79 | one argument, the worker's properties dict, and should return | |
|
80 | True if the worker meets the dependencies or False if it does | |
|
81 | not. | |
|
82 | Default=None - run on any worker | |
|
83 | options : dict | |
|
84 | Any other keyword options for more elaborate uses of tasks | |
|
85 | ||
|
86 | Examples | |
|
87 | -------- | |
|
181 | The number of times a task should be retries upon failure | |
|
182 | recovery_task : any task object | |
|
183 | If a task fails and it has a recovery_task, that is run | |
|
184 | upon a retry | |
|
185 | depend : FunctionType | |
|
186 | A function that is called to test for properties. This function | |
|
187 | must take one argument, the properties dict and return a boolean | |
|
188 | """ | |
|
189 | self.clear_before = clear_before | |
|
190 | self.clear_after = clear_after | |
|
191 | self.retries = retries | |
|
192 | self.recovery_task = recovery_task | |
|
193 | self.depend = depend | |
|
194 | self.taskid = None | |
|
195 | ||
|
196 | def start_time(self, result): | |
|
197 | """ | |
|
198 | Start the basic timers. | |
|
199 | """ | |
|
200 | self.start = time.time() | |
|
201 | self.start_struct = time.localtime() | |
|
202 | return result | |
|
203 | ||
|
204 | def stop_time(self, result): | |
|
205 | """ | |
|
206 | Stop the basic timers. | |
|
207 | """ | |
|
208 | self.stop = time.time() | |
|
209 | self.stop_struct = time.localtime() | |
|
210 | self.duration = self.stop - self.start | |
|
211 | self.submitted = time.strftime(time_format, self.start_struct) | |
|
212 | self.completed = time.strftime(time_format) | |
|
213 | return result | |
|
214 | ||
|
215 | def pre_task(self, d, queued_engine): | |
|
216 | """ | |
|
217 | Clear the engine before running the task if clear_before is set. | |
|
218 | """ | |
|
219 | if self.clear_before: | |
|
220 | d.addCallback(lambda r: queued_engine.reset()) | |
|
221 | ||
|
222 | def post_task(self, d, queued_engine): | |
|
223 | """ | |
|
224 | Clear the engine after running the task if clear_after is set. | |
|
225 | """ | |
|
226 | def reseter(result): | |
|
227 | queued_engine.reset() | |
|
228 | return result | |
|
229 | if self.clear_after: | |
|
230 | d.addBoth(reseter) | |
|
231 | ||
|
232 | def submit_task(self, d, queued_engine): | |
|
233 | raise NotImplementedError('submit_task must be implemented in a subclass') | |
|
234 | ||
|
235 | def process_result(self, result, engine_id): | |
|
236 | """ | |
|
237 | Process a task result. | |
|
238 | ||
|
239 | This is the default `process_result` that just returns the raw | |
|
240 | result or a `Failure`. | |
|
241 | """ | |
|
242 | if isinstance(result, failure.Failure): | |
|
243 | return (False, result) | |
|
244 | else: | |
|
245 | return (True, result) | |
|
246 | ||
|
247 | def check_depend(self, properties): | |
|
248 | """ | |
|
249 | Calls self.depend(properties) to see if a task should be run. | |
|
250 | """ | |
|
251 | if self.depend is not None: | |
|
252 | return self.depend(properties) | |
|
253 | else: | |
|
254 | return True | |
|
255 | ||
|
256 | def can_task(self): | |
|
257 | self.depend = can(self.depend) | |
|
258 | if isinstance(self.recovery_task, BaseTask): | |
|
259 | self.recovery_task.can_task() | |
|
260 | ||
|
261 | def uncan_task(self): | |
|
262 | self.depend = uncan(self.depend) | |
|
263 | if isinstance(self.recovery_task, BaseTask): | |
|
264 | self.recovery_task.uncan_task() | |
|
265 | ||
|
266 | class MapTask(BaseTask): | |
|
267 | """ | |
|
268 | A task that consists of a function and arguments. | |
|
269 | """ | |
|
88 | 270 | |
|
89 | >>> t = Task('dostuff(args)') | |
|
90 | >>> t = Task('a=5', pull='a') | |
|
91 | >>> t = Task('a=5\nb=4', pull=['a','b']) | |
|
92 | >>> t = Task('os.kill(os.getpid(),9)', retries=100) # this is a bad idea | |
|
93 | # A dependency case: | |
|
94 | >>> def hasMPI(props): | |
|
95 | ... return props.get('mpi') is not None | |
|
96 | >>> t = Task('mpi.send(blah,blah)', depend = hasMPI) | |
|
271 | zi.implements(ITask) | |
|
272 | ||
|
273 | def __init__(self, function, args=None, kwargs=None, clear_before=False, | |
|
274 | clear_after=False, retries=0, recovery_task=None, depend=None): | |
|
275 | """ | |
|
276 | Create a task based on a function, args and kwargs. | |
|
277 | ||
|
278 | This is a simple type of task that consists of calling: | |
|
279 | function(*args, **kwargs) and wrapping the result in a `TaskResult`. | |
|
280 | ||
|
281 | The return value of the function, or a `Failure` wrapping an | |
|
282 | exception is the task result for this type of task. | |
|
283 | """ | |
|
284 | BaseTask.__init__(self, clear_before, clear_after, retries, | |
|
285 | recovery_task, depend) | |
|
286 | if not isinstance(function, FunctionType): | |
|
287 | raise TypeError('a task function must be a FunctionType') | |
|
288 | self.function = function | |
|
289 | if args is None: | |
|
290 | self.args = () | |
|
291 | else: | |
|
292 | self.args = args | |
|
293 | if not isinstance(self.args, (list, tuple)): | |
|
294 | raise TypeError('a task args must be a list or tuple') | |
|
295 | if kwargs is None: | |
|
296 | self.kwargs = {} | |
|
297 | else: | |
|
298 | self.kwargs = kwargs | |
|
299 | if not isinstance(self.kwargs, dict): | |
|
300 | raise TypeError('a task kwargs must be a dict') | |
|
301 | ||
|
302 | def submit_task(self, d, queued_engine): | |
|
303 | d.addCallback(lambda r: queued_engine.push_function( | |
|
304 | dict(_ipython_task_function=self.function)) | |
|
305 | ) | |
|
306 | d.addCallback(lambda r: queued_engine.push( | |
|
307 | dict(_ipython_task_args=self.args,_ipython_task_kwargs=self.kwargs)) | |
|
308 | ) | |
|
309 | d.addCallback(lambda r: queued_engine.execute( | |
|
310 | '_ipython_task_result = _ipython_task_function(*_ipython_task_args,**_ipython_task_kwargs)') | |
|
311 | ) | |
|
312 | d.addCallback(lambda r: queued_engine.pull('_ipython_task_result')) | |
|
313 | ||
|
314 | def can_task(self): | |
|
315 | self.function = can(self.function) | |
|
316 | BaseTask.can_task(self) | |
|
317 | ||
|
318 | def uncan_task(self): | |
|
319 | self.function = uncan(self.function) | |
|
320 | BaseTask.uncan_task(self) | |
|
321 | ||
|
322 | ||
|
323 | class StringTask(BaseTask): | |
|
324 | """ | |
|
325 | A task that consists of a string of Python code to run. | |
|
97 | 326 | """ |
|
98 | 327 | |
|
99 | 328 | def __init__(self, expression, pull=None, push=None, |
|
100 | 329 | clear_before=False, clear_after=False, retries=0, |
|
101 |
recovery_task=None, depend=None |
|
|
330 | recovery_task=None, depend=None): | |
|
331 | """ | |
|
332 | Create a task based on a Python expression and variables | |
|
333 | ||
|
334 | This type of task lets you push a set of variables to the engines | |
|
335 | namespace, run a Python string in that namespace and then bring back | |
|
336 | a different set of Python variables as the result. | |
|
337 | ||
|
338 | Because this type of task can return many results (through the | |
|
339 | `pull` keyword argument) it returns a special `TaskResult` object | |
|
340 | that wraps the pulled variables, statistics about the run and | |
|
341 | any exceptions raised. | |
|
342 | """ | |
|
343 | if not isinstance(expression, str): | |
|
344 | raise TypeError('a task expression must be a string') | |
|
102 | 345 | self.expression = expression |
|
103 | if isinstance(pull, str): | |
|
104 | self.pull = [pull] | |
|
105 | else: | |
|
346 | ||
|
347 | if pull==None: | |
|
348 | self.pull = () | |
|
349 | elif isinstance(pull, str): | |
|
350 | self.pull = (pull,) | |
|
351 | elif isinstance(pull, (list, tuple)): | |
|
106 | 352 | self.pull = pull |
|
353 | else: | |
|
354 | raise TypeError('pull must be str or a sequence of strs') | |
|
355 | ||
|
356 | if push==None: | |
|
357 | self.push = {} | |
|
358 | elif isinstance(push, dict): | |
|
107 | 359 | self.push = push |
|
108 | self.clear_before = clear_before | |
|
109 | self.clear_after = clear_after | |
|
110 | self.retries=retries | |
|
111 | self.recovery_task = recovery_task | |
|
112 | self.depend = depend | |
|
113 | self.options = options | |
|
114 | self.taskid = None | |
|
360 | else: | |
|
361 | raise TypeError('push must be a dict') | |
|
362 | ||
|
363 | BaseTask.__init__(self, clear_before, clear_after, retries, | |
|
364 | recovery_task, depend) | |
|
115 | 365 | |
|
116 | class ResultNS: | |
|
117 | """The result namespace object for use in TaskResult objects as tr.ns. | |
|
366 | def submit_task(self, d, queued_engine): | |
|
367 | if self.push is not None: | |
|
368 | d.addCallback(lambda r: queued_engine.push(self.push)) | |
|
369 | ||
|
370 | d.addCallback(lambda r: queued_engine.execute(self.expression)) | |
|
371 | ||
|
372 | if self.pull is not None: | |
|
373 | d.addCallback(lambda r: queued_engine.pull(self.pull)) | |
|
374 | else: | |
|
375 | d.addCallback(lambda r: None) | |
|
376 | ||
|
377 | def process_result(self, result, engine_id): | |
|
378 | if isinstance(result, failure.Failure): | |
|
379 | tr = TaskResult(result, engine_id) | |
|
380 | else: | |
|
381 | if self.pull is None: | |
|
382 | resultDict = {} | |
|
383 | elif len(self.pull) == 1: | |
|
384 | resultDict = {self.pull[0]:result} | |
|
385 | else: | |
|
386 | resultDict = dict(zip(self.pull, result)) | |
|
387 | tr = TaskResult(resultDict, engine_id) | |
|
388 | # Assign task attributes | |
|
389 | tr.submitted = self.submitted | |
|
390 | tr.completed = self.completed | |
|
391 | tr.duration = self.duration | |
|
392 | if hasattr(self,'taskid'): | |
|
393 | tr.taskid = self.taskid | |
|
394 | else: | |
|
395 | tr.taskid = None | |
|
396 | if isinstance(result, failure.Failure): | |
|
397 | return (False, tr) | |
|
398 | else: | |
|
399 | return (True, tr) | |
|
400 | ||
|
401 | class ResultNS(object): | |
|
402 | """ | |
|
403 | A dict like object for holding the results of a task. | |
|
404 | ||
|
405 | The result namespace object for use in `TaskResult` objects as tr.ns. | |
|
118 | 406 | It builds an object from a dictionary, such that it has attributes |
|
119 | 407 | according to the key,value pairs of the dictionary. |
|
120 | 408 | |
@@ -128,7 +416,7 b' class ResultNS:' | |||
|
128 | 416 | |
|
129 | 417 | >>> ns = ResultNS({'a':17,'foo':range(3)}) |
|
130 | 418 | >>> print ns |
|
131 |
|
|
|
419 | NS{'a': 17, 'foo': [0, 1, 2]} | |
|
132 | 420 | >>> ns.a |
|
133 | 421 |
|
|
134 | 422 | >>> ns['foo'] |
@@ -152,7 +440,7 b' class ResultNS:' | |||
|
152 | 440 | |
|
153 | 441 | class TaskResult(object): |
|
154 | 442 | """ |
|
155 | An object for returning task results. | |
|
443 | An object for returning task results for certain types of tasks. | |
|
156 | 444 | |
|
157 | 445 | This object encapsulates the results of a task. On task |
|
158 | 446 | success it will have a keys attribute that will have a list |
@@ -162,21 +450,21 b' class TaskResult(object):' | |||
|
162 | 450 | |
|
163 | 451 | In task failure, keys will be empty, but failure will contain |
|
164 | 452 | the failure object that encapsulates the remote exception. |
|
165 |
One can also simply call the |
|
|
453 | One can also simply call the `raise_exception` method of | |
|
166 | 454 | this class to re-raise any remote exception in the local |
|
167 | 455 | session. |
|
168 | 456 | |
|
169 | The TaskResult has a .ns member, which is a property for access | |
|
457 | The `TaskResult` has a `.ns` member, which is a property for access | |
|
170 | 458 | to the results. If the Task had pull=['a', 'b'], then the |
|
171 | Task Result will have attributes tr.ns.a, tr.ns.b for those values. | |
|
172 | Accessing tr.ns will raise the remote failure if the task failed. | |
|
459 | Task Result will have attributes `tr.ns.a`, `tr.ns.b` for those values. | |
|
460 | Accessing `tr.ns` will raise the remote failure if the task failed. | |
|
173 | 461 | |
|
174 | The engineid attribute should have the engineid of the engine | |
|
175 |
that ran the task. But, because engines can come and go |
|
|
176 |
the |
|
|
462 | The `engineid` attribute should have the `engineid` of the engine | |
|
463 | that ran the task. But, because engines can come and go, | |
|
464 | the `engineid` may not continue to be | |
|
177 | 465 | valid or accurate. |
|
178 | 466 | |
|
179 | The taskid attribute simply gives the taskid that the task | |
|
467 | The `taskid` attribute simply gives the `taskid` that the task | |
|
180 | 468 | is tracked under. |
|
181 | 469 | """ |
|
182 | 470 | taskid = None |
@@ -188,7 +476,7 b' class TaskResult(object):' | |||
|
188 | 476 | return self._ns |
|
189 | 477 | |
|
190 | 478 | def _setNS(self, v): |
|
191 |
raise Exception(" |
|
|
479 | raise Exception("the ns attribute cannot be changed") | |
|
192 | 480 | |
|
193 | 481 | ns = property(_getNS, _setNS) |
|
194 | 482 | |
@@ -214,15 +502,19 b' class TaskResult(object):' | |||
|
214 | 502 | |
|
215 | 503 | def __getitem__(self, key): |
|
216 | 504 | if self.failure is not None: |
|
217 |
self.raise |
|
|
505 | self.raise_exception() | |
|
218 | 506 | return self.results[key] |
|
219 | 507 | |
|
220 |
def raise |
|
|
508 | def raise_exception(self): | |
|
221 | 509 | """Re-raise any remote exceptions in the local python session.""" |
|
222 | 510 | if self.failure is not None: |
|
223 | 511 | self.failure.raiseException() |
|
224 | 512 | |
|
225 | 513 | |
|
514 | #----------------------------------------------------------------------------- | |
|
515 | # The controller side of things | |
|
516 | #----------------------------------------------------------------------------- | |
|
517 | ||
|
226 | 518 | class IWorker(zi.Interface): |
|
227 | 519 | """The Basic Worker Interface. |
|
228 | 520 | |
@@ -237,12 +529,15 b' class IWorker(zi.Interface):' | |||
|
237 | 529 | :Parameters: |
|
238 | 530 | task : a `Task` object |
|
239 | 531 | |
|
240 |
:Returns: `Deferred` to a |
|
|
532 | :Returns: `Deferred` to a tuple of (success, result) where | |
|
533 | success if a boolean that signifies success or failure | |
|
534 | and result is the task result. | |
|
241 | 535 | """ |
|
242 | 536 | |
|
243 | 537 | |
|
244 | 538 | class WorkerFromQueuedEngine(object): |
|
245 | 539 | """Adapt an `IQueuedEngine` to an `IWorker` object""" |
|
540 | ||
|
246 | 541 | zi.implements(IWorker) |
|
247 | 542 | |
|
248 | 543 | def __init__(self, qe): |
@@ -257,52 +552,26 b' class WorkerFromQueuedEngine(object):' | |||
|
257 | 552 | def run(self, task): |
|
258 | 553 | """Run task in worker's namespace. |
|
259 | 554 | |
|
555 | This takes a task and calls methods on the task that actually | |
|
556 | cause `self.queuedEngine` to do the task. See the methods of | |
|
557 | `ITask` for more information about how these methods are called. | |
|
558 | ||
|
260 | 559 | :Parameters: |
|
261 | 560 | task : a `Task` object |
|
262 | 561 | |
|
263 |
:Returns: `Deferred` to a |
|
|
562 | :Returns: `Deferred` to a tuple of (success, result) where | |
|
563 | success if a boolean that signifies success or failure | |
|
564 | and result is the task result. | |
|
264 | 565 | """ |
|
265 | if task.clear_before: | |
|
266 | d = self.queuedEngine.reset() | |
|
267 | else: | |
|
268 | 566 |
|
|
269 | ||
|
270 | if task.push is not None: | |
|
271 | d.addCallback(lambda r: self.queuedEngine.push(task.push)) | |
|
272 | ||
|
273 | d.addCallback(lambda r: self.queuedEngine.execute(task.expression)) | |
|
274 | ||
|
275 | if task.pull is not None: | |
|
276 | d.addCallback(lambda r: self.queuedEngine.pull(task.pull)) | |
|
277 | else: | |
|
278 | d.addCallback(lambda r: None) | |
|
279 | ||
|
280 | def reseter(result): | |
|
281 | self.queuedEngine.reset() | |
|
282 | return result | |
|
283 | ||
|
284 | if task.clear_after: | |
|
285 | d.addBoth(reseter) | |
|
286 | ||
|
287 | return d.addBoth(self._zipResults, task.pull, time.time(), time.localtime()) | |
|
288 | ||
|
289 | def _zipResults(self, result, names, start, start_struct): | |
|
290 | """Callback for construting the TaskResult object.""" | |
|
291 | if isinstance(result, failure.Failure): | |
|
292 | tr = TaskResult(result, self.queuedEngine.id) | |
|
293 | else: | |
|
294 | if names is None: | |
|
295 | resultDict = {} | |
|
296 | elif len(names) == 1: | |
|
297 | resultDict = {names[0]:result} | |
|
298 | else: | |
|
299 | resultDict = dict(zip(names, result)) | |
|
300 | tr = TaskResult(resultDict, self.queuedEngine.id) | |
|
301 | # the time info | |
|
302 | tr.submitted = time.strftime(time_format, start_struct) | |
|
303 | tr.completed = time.strftime(time_format) | |
|
304 | tr.duration = time.time()-start | |
|
305 | return tr | |
|
567 | d.addCallback(task.start_time) | |
|
568 | task.pre_task(d, self.queuedEngine) | |
|
569 | task.submit_task(d, self.queuedEngine) | |
|
570 | task.post_task(d, self.queuedEngine) | |
|
571 | d.addBoth(task.stop_time) | |
|
572 | d.addBoth(task.process_result, self.queuedEngine.id) | |
|
573 | # At this point, there will be (success, result) coming down the line | |
|
574 | return d | |
|
306 | 575 | |
|
307 | 576 | |
|
308 | 577 | components.registerAdapter(WorkerFromQueuedEngine, es.IEngineQueued, IWorker) |
@@ -319,14 +588,14 b' class IScheduler(zi.Interface):' | |||
|
319 | 588 | """Add a task to the queue of the Scheduler. |
|
320 | 589 | |
|
321 | 590 | :Parameters: |
|
322 |
task : a `Task` |
|
|
591 | task : an `ITask` implementer | |
|
323 | 592 | The task to be queued. |
|
324 | 593 | flags : dict |
|
325 | 594 | General keywords for more sophisticated scheduling |
|
326 | 595 | """ |
|
327 | 596 | |
|
328 | 597 | def pop_task(id=None): |
|
329 |
"""Pops a |
|
|
598 | """Pops a task object from the queue. | |
|
330 | 599 | |
|
331 | 600 | This gets the next task to be run. If no `id` is requested, the highest priority |
|
332 | 601 | task is returned. |
@@ -336,7 +605,7 b' class IScheduler(zi.Interface):' | |||
|
336 | 605 | The id of the task to be popped. The default (None) is to return |
|
337 | 606 | the highest priority task. |
|
338 | 607 | |
|
339 |
:Returns: a `Task` |
|
|
608 | :Returns: an `ITask` implementer | |
|
340 | 609 | |
|
341 | 610 | :Exceptions: |
|
342 | 611 | IndexError : raised if no taskid in queue |
@@ -346,8 +615,9 b' class IScheduler(zi.Interface):' | |||
|
346 | 615 | """Add a worker to the worker queue. |
|
347 | 616 | |
|
348 | 617 | :Parameters: |
|
349 |
worker : an IWorker implement |
|
|
350 | flags : General keywords for more sophisticated scheduling | |
|
618 | worker : an `IWorker` implementer | |
|
619 | flags : dict | |
|
620 | General keywords for more sophisticated scheduling | |
|
351 | 621 | """ |
|
352 | 622 | |
|
353 | 623 | def pop_worker(id=None): |
@@ -370,15 +640,15 b' class IScheduler(zi.Interface):' | |||
|
370 | 640 | """Returns True if there is something to do, False otherwise""" |
|
371 | 641 | |
|
372 | 642 | def schedule(): |
|
373 |
"""Returns |
|
|
374 | task to be run. | |
|
375 | """ | |
|
643 | """Returns (worker,task) pair for the next task to be run.""" | |
|
376 | 644 | |
|
377 | 645 | |
|
378 | 646 | class FIFOScheduler(object): |
|
379 | """A basic First-In-First-Out (Queue) Scheduler. | |
|
380 | This is the default Scheduler for the TaskController. | |
|
381 | See the docstrings for IScheduler for interface details. | |
|
647 | """ | |
|
648 | A basic First-In-First-Out (Queue) Scheduler. | |
|
649 | ||
|
650 | This is the default Scheduler for the `TaskController`. | |
|
651 | See the docstrings for `IScheduler` for interface details. | |
|
382 | 652 | """ |
|
383 | 653 | |
|
384 | 654 | zi.implements(IScheduler) |
@@ -435,7 +705,9 b' class FIFOScheduler(object):' | |||
|
435 | 705 | for t in self.tasks: |
|
436 | 706 | for w in self.workers: |
|
437 | 707 | try:# do not allow exceptions to break this |
|
438 | cando = t.depend is None or t.depend(w.properties) | |
|
708 | # Allow the task to check itself using its | |
|
709 | # check_depend method. | |
|
710 | cando = t.check_depend(w.properties) | |
|
439 | 711 | except: |
|
440 | 712 | cando = False |
|
441 | 713 | if cando: |
@@ -445,9 +717,12 b' class FIFOScheduler(object):' | |||
|
445 | 717 | |
|
446 | 718 | |
|
447 | 719 | class LIFOScheduler(FIFOScheduler): |
|
448 | """A Last-In-First-Out (Stack) Scheduler. This scheduler should naively | |
|
449 | reward fast engines by giving them more jobs. This risks starvation, but | |
|
450 | only in cases with low load, where starvation does not really matter. | |
|
720 | """ | |
|
721 | A Last-In-First-Out (Stack) Scheduler. | |
|
722 | ||
|
723 | This scheduler should naively reward fast engines by giving | |
|
724 | them more jobs. This risks starvation, but only in cases with | |
|
725 | low load, where starvation does not really matter. | |
|
451 | 726 | """ |
|
452 | 727 | |
|
453 | 728 | def add_task(self, task, **flags): |
@@ -462,13 +737,15 b' class LIFOScheduler(FIFOScheduler):' | |||
|
462 | 737 | |
|
463 | 738 | |
|
464 | 739 | class ITaskController(cs.IControllerBase): |
|
465 | """The Task based interface to a `ControllerService` object | |
|
740 | """ | |
|
741 | The Task based interface to a `ControllerService` object | |
|
466 | 742 | |
|
467 | 743 | This adapts a `ControllerService` to the ITaskController interface. |
|
468 | 744 | """ |
|
469 | 745 | |
|
470 | 746 | def run(task): |
|
471 |
""" |
|
|
747 | """ | |
|
748 | Run a task. | |
|
472 | 749 | |
|
473 | 750 | :Parameters: |
|
474 | 751 | task : an IPython `Task` object |
@@ -477,13 +754,14 b' class ITaskController(cs.IControllerBase):' | |||
|
477 | 754 | """ |
|
478 | 755 | |
|
479 | 756 | def get_task_result(taskid, block=False): |
|
480 | """Get the result of a task by its ID. | |
|
757 | """ | |
|
758 | Get the result of a task by its ID. | |
|
481 | 759 | |
|
482 | 760 | :Parameters: |
|
483 | 761 | taskid : int |
|
484 | 762 | the id of the task whose result is requested |
|
485 | 763 | |
|
486 |
:Returns: `Deferred` to |
|
|
764 | :Returns: `Deferred` to the task result if the task is done, and None | |
|
487 | 765 | if not. |
|
488 | 766 | |
|
489 | 767 | :Exceptions: |
@@ -508,23 +786,35 b' class ITaskController(cs.IControllerBase):' | |||
|
508 | 786 | """ |
|
509 | 787 | |
|
510 | 788 | def barrier(taskids): |
|
511 | """Block until the list of taskids are completed. | |
|
789 | """ | |
|
790 | Block until the list of taskids are completed. | |
|
512 | 791 | |
|
513 | 792 | Returns None on success. |
|
514 | 793 | """ |
|
515 | 794 | |
|
516 | 795 | def spin(): |
|
517 | """touch the scheduler, to resume scheduling without submitting | |
|
518 | a task. | |
|
796 | """ | |
|
797 | Touch the scheduler, to resume scheduling without submitting a task. | |
|
519 | 798 | """ |
|
520 | 799 | |
|
521 |
def queue_status( |
|
|
522 | """Get a dictionary with the current state of the task queue. | |
|
800 | def queue_status(verbose=False): | |
|
801 | """ | |
|
802 | Get a dictionary with the current state of the task queue. | |
|
523 | 803 | |
|
524 | 804 | If verbose is True, then return lists of taskids, otherwise, |
|
525 | 805 | return the number of tasks with each status. |
|
526 | 806 | """ |
|
527 | 807 | |
|
808 | def clear(): | |
|
809 | """ | |
|
810 | Clear all previously run tasks from the task controller. | |
|
811 | ||
|
812 | This is needed because the task controller keep all task results | |
|
813 | in memory. This can be a problem is there are many completed | |
|
814 | tasks. Users should call this periodically to clean out these | |
|
815 | cached task results. | |
|
816 | """ | |
|
817 | ||
|
528 | 818 | |
|
529 | 819 | class TaskController(cs.ControllerAdapterBase): |
|
530 | 820 | """The Task based interface to a Controller object. |
@@ -561,7 +851,7 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
561 | 851 | def registerWorker(self, id): |
|
562 | 852 | """Called by controller.register_engine.""" |
|
563 | 853 | if self.workers.get(id): |
|
564 |
raise " |
|
|
854 | raise ValueError("worker with id %s already exists. This should not happen." % id) | |
|
565 | 855 | self.workers[id] = IWorker(self.controller.engines[id]) |
|
566 | 856 | self.workers[id].workerid = id |
|
567 | 857 | if not self.pendingTasks.has_key(id):# if not working |
@@ -586,21 +876,25 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
586 | 876 | #--------------------------------------------------------------------------- |
|
587 | 877 | |
|
588 | 878 | def run(self, task): |
|
589 | """Run a task and return `Deferred` to its taskid.""" | |
|
879 | """ | |
|
880 | Run a task and return `Deferred` to its taskid. | |
|
881 | """ | |
|
590 | 882 | task.taskid = self.taskid |
|
591 | 883 | task.start = time.localtime() |
|
592 | 884 | self.taskid += 1 |
|
593 | 885 | d = defer.Deferred() |
|
594 | 886 | self.scheduler.add_task(task) |
|
595 |
|
|
|
887 | log.msg('Queuing task: %i' % task.taskid) | |
|
596 | 888 | |
|
597 | 889 | self.deferredResults[task.taskid] = [] |
|
598 | 890 | self.distributeTasks() |
|
599 | 891 | return defer.succeed(task.taskid) |
|
600 | 892 | |
|
601 | 893 | def get_task_result(self, taskid, block=False): |
|
602 | """Returns a `Deferred` to a TaskResult tuple or None.""" | |
|
603 | # log.msg("Getting task result: %i" % taskid) | |
|
894 | """ | |
|
895 | Returns a `Deferred` to the task result, or None. | |
|
896 | """ | |
|
897 | log.msg("Getting task result: %i" % taskid) | |
|
604 | 898 | if self.finishedResults.has_key(taskid): |
|
605 | 899 | tr = self.finishedResults[taskid] |
|
606 | 900 | return defer.succeed(tr) |
@@ -615,7 +909,9 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
615 | 909 | return defer.fail(IndexError("task ID not registered: %r" % taskid)) |
|
616 | 910 | |
|
617 | 911 | def abort(self, taskid): |
|
618 | """Remove a task from the queue if it has not been run already.""" | |
|
912 | """ | |
|
913 | Remove a task from the queue if it has not been run already. | |
|
914 | """ | |
|
619 | 915 | if not isinstance(taskid, int): |
|
620 | 916 | return defer.fail(failure.Failure(TypeError("an integer task id expected: %r" % taskid))) |
|
621 | 917 | try: |
@@ -674,8 +970,10 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
674 | 970 | #--------------------------------------------------------------------------- |
|
675 | 971 | |
|
676 | 972 | def _doAbort(self, taskid): |
|
677 | """Helper function for aborting a pending task.""" | |
|
678 | # log.msg("Task aborted: %i" % taskid) | |
|
973 | """ | |
|
974 | Helper function for aborting a pending task. | |
|
975 | """ | |
|
976 | log.msg("Task aborted: %i" % taskid) | |
|
679 | 977 | result = failure.Failure(error.TaskAborted()) |
|
680 | 978 | self._finishTask(taskid, result) |
|
681 | 979 | if taskid in self.abortPending: |
@@ -683,14 +981,16 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
683 | 981 | |
|
684 | 982 | def _finishTask(self, taskid, result): |
|
685 | 983 | dlist = self.deferredResults.pop(taskid) |
|
686 | result.taskid = taskid # The TaskResult should save the taskid | |
|
984 | # result.taskid = taskid # The TaskResult should save the taskid | |
|
687 | 985 | self.finishedResults[taskid] = result |
|
688 | 986 | for d in dlist: |
|
689 | 987 | d.callback(result) |
|
690 | 988 | |
|
691 | 989 | def distributeTasks(self): |
|
692 | """Distribute tasks while self.scheduler has things to do.""" | |
|
693 | # log.msg("distributing Tasks") | |
|
990 | """ | |
|
991 | Distribute tasks while self.scheduler has things to do. | |
|
992 | """ | |
|
993 | log.msg("distributing Tasks") | |
|
694 | 994 | worker, task = self.scheduler.schedule() |
|
695 | 995 | if not worker and not task: |
|
696 | 996 | if self.idleLater and self.idleLater.called:# we are inside failIdle |
@@ -705,7 +1005,7 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
705 | 1005 | self.pendingTasks[worker.workerid] = task |
|
706 | 1006 | # run/link callbacks |
|
707 | 1007 | d = worker.run(task) |
|
708 |
|
|
|
1008 | log.msg("Running task %i on worker %i" %(task.taskid, worker.workerid)) | |
|
709 | 1009 | d.addBoth(self.taskCompleted, task.taskid, worker.workerid) |
|
710 | 1010 | worker, task = self.scheduler.schedule() |
|
711 | 1011 | # check for idle timeout: |
@@ -727,14 +1027,15 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
727 | 1027 | t = self.scheduler.pop_task() |
|
728 | 1028 | msg = "task %i failed to execute due to unmet dependencies"%t.taskid |
|
729 | 1029 | msg += " for %i seconds"%self.timeout |
|
730 |
|
|
|
1030 | log.msg("Task aborted by timeout: %i" % t.taskid) | |
|
731 | 1031 | f = failure.Failure(error.TaskTimeout(msg)) |
|
732 | 1032 | self._finishTask(t.taskid, f) |
|
733 | 1033 | self.idleLater = None |
|
734 | 1034 | |
|
735 | 1035 | |
|
736 | def taskCompleted(self, result, taskid, workerid): | |
|
1036 | def taskCompleted(self, success_and_result, taskid, workerid): | |
|
737 | 1037 | """This is the err/callback for a completed task.""" |
|
1038 | success, result = success_and_result | |
|
738 | 1039 | try: |
|
739 | 1040 | task = self.pendingTasks.pop(workerid) |
|
740 | 1041 | except: |
@@ -751,7 +1052,7 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
751 | 1052 | aborted = True |
|
752 | 1053 | |
|
753 | 1054 | if not aborted: |
|
754 | if result.failure is not None and isinstance(result.failure, failure.Failure): # we failed | |
|
1055 | if not success: | |
|
755 | 1056 | log.msg("Task %i failed on worker %i"% (taskid, workerid)) |
|
756 | 1057 | if task.retries > 0: # resubmit |
|
757 | 1058 | task.retries -= 1 |
@@ -759,7 +1060,7 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
759 | 1060 | s = "Resubmitting task %i, %i retries remaining" %(taskid, task.retries) |
|
760 | 1061 | log.msg(s) |
|
761 | 1062 | self.distributeTasks() |
|
762 | elif isinstance(task.recovery_task, Task) and \ | |
|
1063 | elif isinstance(task.recovery_task, BaseTask) and \ | |
|
763 | 1064 | task.recovery_task.retries > -1: |
|
764 | 1065 | # retries = -1 is to prevent infinite recovery_task loop |
|
765 | 1066 | task.retries = -1 |
@@ -775,17 +1076,18 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
775 | 1076 | # it may have died, and not yet been unregistered |
|
776 | 1077 | reactor.callLater(self.failurePenalty, self.readmitWorker, workerid) |
|
777 | 1078 | else: # we succeeded |
|
778 |
|
|
|
1079 | log.msg("Task completed: %i"% taskid) | |
|
779 | 1080 | self._finishTask(taskid, result) |
|
780 | 1081 | self.readmitWorker(workerid) |
|
781 | 1082 | else:# we aborted the task |
|
782 | if result.failure is not None and isinstance(result.failure, failure.Failure): # it failed, penalize worker | |
|
1083 | if not success: | |
|
783 | 1084 | reactor.callLater(self.failurePenalty, self.readmitWorker, workerid) |
|
784 | 1085 | else: |
|
785 | 1086 | self.readmitWorker(workerid) |
|
786 | 1087 | |
|
787 | 1088 | def readmitWorker(self, workerid): |
|
788 | """Readmit a worker to the scheduler. | |
|
1089 | """ | |
|
1090 | Readmit a worker to the scheduler. | |
|
789 | 1091 | |
|
790 | 1092 | This is outside `taskCompleted` because of the `failurePenalty` being |
|
791 | 1093 | implemented through `reactor.callLater`. |
@@ -795,5 +1097,17 b' class TaskController(cs.ControllerAdapterBase):' | |||
|
795 | 1097 | self.scheduler.add_worker(self.workers[workerid]) |
|
796 | 1098 | self.distributeTasks() |
|
797 | 1099 |
|
|
1100 | def clear(self): | |
|
1101 | """ | |
|
1102 | Clear all previously run tasks from the task controller. | |
|
1103 | ||
|
1104 | This is needed because the task controller keep all task results | |
|
1105 | in memory. This can be a problem is there are many completed | |
|
1106 | tasks. Users should call this periodically to clean out these | |
|
1107 | cached task results. | |
|
1108 | """ | |
|
1109 | self.finishedResults = {} | |
|
1110 | return defer.succeed(None) | |
|
1111 | ||
|
798 | 1112 | |
|
799 | 1113 | components.registerAdapter(TaskController, cs.IControllerBase, ITaskController) |
@@ -1,9 +1,8 b'' | |||
|
1 | 1 | # encoding: utf-8 |
|
2 | 2 | # -*- test-case-name: IPython.kernel.tests.test_taskcontrollerxmlrpc -*- |
|
3 | 3 | |
|
4 | """The Generic Task Client object. | |
|
5 | ||
|
6 | This must be subclassed based on your connection method. | |
|
4 | """ | |
|
5 | A blocking version of the task client. | |
|
7 | 6 | """ |
|
8 | 7 | |
|
9 | 8 | __docformat__ = "restructuredtext en" |
@@ -24,116 +23,97 b' from twisted.python import components, log' | |||
|
24 | 23 | |
|
25 | 24 | from IPython.kernel.twistedutil import blockingCallFromThread |
|
26 | 25 | from IPython.kernel import task, error |
|
26 | from IPython.kernel.mapper import ( | |
|
27 | SynchronousTaskMapper, | |
|
28 | ITaskMapperFactory, | |
|
29 | IMapper | |
|
30 | ) | |
|
31 | from IPython.kernel.parallelfunction import ( | |
|
32 | ParallelFunction, | |
|
33 | ITaskParallelDecorator | |
|
34 | ) | |
|
27 | 35 | |
|
28 | 36 | #------------------------------------------------------------------------------- |
|
29 |
# |
|
|
37 | # The task client | |
|
30 | 38 | #------------------------------------------------------------------------------- |
|
31 | 39 | |
|
32 | class InteractiveTaskClient(object): | |
|
33 | ||
|
34 | def irun(self, *args, **kwargs): | |
|
35 | """Run a task on the `TaskController`. | |
|
36 | ||
|
37 | This method is a shorthand for run(task) and its arguments are simply | |
|
38 | passed onto a `Task` object: | |
|
39 | ||
|
40 | irun(*args, **kwargs) -> run(Task(*args, **kwargs)) | |
|
41 | ||
|
42 | :Parameters: | |
|
43 | expression : str | |
|
44 | A str that is valid python code that is the task. | |
|
45 | pull : str or list of str | |
|
46 | The names of objects to be pulled as results. | |
|
47 | push : dict | |
|
48 | A dict of objects to be pushed into the engines namespace before | |
|
49 | execution of the expression. | |
|
50 | clear_before : boolean | |
|
51 | Should the engine's namespace be cleared before the task is run. | |
|
52 | Default=False. | |
|
53 | clear_after : boolean | |
|
54 | Should the engine's namespace be cleared after the task is run. | |
|
55 | Default=False. | |
|
56 | retries : int | |
|
57 | The number of times to resumbit the task if it fails. Default=0. | |
|
58 | options : dict | |
|
59 | Any other keyword options for more elaborate uses of tasks | |
|
60 | ||
|
61 | :Returns: A `TaskResult` object. | |
|
62 | """ | |
|
63 | block = kwargs.pop('block', False) | |
|
64 | if len(args) == 1 and isinstance(args[0], task.Task): | |
|
65 | t = args[0] | |
|
66 | else: | |
|
67 | t = task.Task(*args, **kwargs) | |
|
68 | taskid = self.run(t) | |
|
69 | print "TaskID = %i"%taskid | |
|
70 | if block: | |
|
71 | return self.get_task_result(taskid, block) | |
|
72 | else: | |
|
73 | return taskid | |
|
74 | ||
|
75 | 40 | class IBlockingTaskClient(Interface): |
|
76 | 41 | """ |
|
77 |
A |
|
|
42 | A vague interface of the blocking task client | |
|
78 | 43 | """ |
|
79 | 44 | pass |
|
80 | 45 | |
|
81 | ||
|
82 | class BlockingTaskClient(InteractiveTaskClient): | |
|
46 | class BlockingTaskClient(object): | |
|
83 | 47 | """ |
|
84 | This class provides a blocking task client. | |
|
48 | A blocking task client that adapts a non-blocking one. | |
|
85 | 49 | """ |
|
86 | 50 | |
|
87 |
implements( |
|
|
51 | implements( | |
|
52 | IBlockingTaskClient, | |
|
53 | ITaskMapperFactory, | |
|
54 | IMapper, | |
|
55 | ITaskParallelDecorator | |
|
56 | ) | |
|
88 | 57 | |
|
89 | 58 | def __init__(self, task_controller): |
|
90 | 59 | self.task_controller = task_controller |
|
91 | 60 | self.block = True |
|
92 | 61 | |
|
93 | def run(self, task): | |
|
94 | """ | |
|
95 | Run a task and return a task id that can be used to get the task result. | |
|
62 | def run(self, task, block=False): | |
|
63 | """Run a task on the `TaskController`. | |
|
64 | ||
|
65 | See the documentation of the `MapTask` and `StringTask` classes for | |
|
66 | details on how to build a task of different types. | |
|
96 | 67 | |
|
97 | 68 | :Parameters: |
|
98 | task : `Task` | |
|
99 | The `Task` object to run | |
|
69 | task : an `ITask` implementer | |
|
70 | ||
|
71 | :Returns: The int taskid of the submitted task. Pass this to | |
|
72 | `get_task_result` to get the `TaskResult` object. | |
|
100 | 73 | """ |
|
101 |
|
|
|
74 | tid = blockingCallFromThread(self.task_controller.run, task) | |
|
75 | if block: | |
|
76 | return self.get_task_result(tid, block=True) | |
|
77 | else: | |
|
78 | return tid | |
|
102 | 79 | |
|
103 | 80 | def get_task_result(self, taskid, block=False): |
|
104 | 81 | """ |
|
105 |
Get |
|
|
82 | Get a task result by taskid. | |
|
106 | 83 | |
|
107 | 84 | :Parameters: |
|
108 | 85 | taskid : int |
|
109 |
The id of the task |
|
|
86 | The taskid of the task to be retrieved. | |
|
110 | 87 | block : boolean |
|
111 |
|
|
|
112 | `TaskResult` object. If False, just poll for the result and | |
|
113 | return None if the task is not done. | |
|
88 | Should I block until the task is done? | |
|
89 | ||
|
90 | :Returns: A `TaskResult` object that encapsulates the task result. | |
|
114 | 91 | """ |
|
115 | 92 | return blockingCallFromThread(self.task_controller.get_task_result, |
|
116 | 93 | taskid, block) |
|
117 | 94 | |
|
118 | 95 | def abort(self, taskid): |
|
119 | 96 | """ |
|
120 |
Abort a task by task |
|
|
97 | Abort a task by taskid. | |
|
98 | ||
|
99 | :Parameters: | |
|
100 | taskid : int | |
|
101 | The taskid of the task to be aborted. | |
|
121 | 102 | """ |
|
122 | 103 | return blockingCallFromThread(self.task_controller.abort, taskid) |
|
123 | 104 | |
|
124 | 105 | def barrier(self, taskids): |
|
125 | """ | |
|
126 | Wait for a set of tasks to finish. | |
|
106 | """Block until a set of tasks are completed. | |
|
127 | 107 | |
|
128 | 108 | :Parameters: |
|
129 |
taskids : list |
|
|
130 |
A |
|
|
109 | taskids : list, tuple | |
|
110 | A sequence of taskids to block on. | |
|
131 | 111 | """ |
|
132 | 112 | return blockingCallFromThread(self.task_controller.barrier, taskids) |
|
133 | 113 | |
|
134 | 114 | def spin(self): |
|
135 | 115 | """ |
|
136 |
|
|
|
116 | Touch the scheduler, to resume scheduling without submitting a task. | |
|
137 | 117 | |
|
138 | 118 | This method only needs to be called in unusual situations where the |
|
139 | 119 | scheduler is idle for some reason. |
@@ -154,6 +134,45 b' class BlockingTaskClient(InteractiveTaskClient):' | |||
|
154 | 134 | """ |
|
155 | 135 | return blockingCallFromThread(self.task_controller.queue_status, verbose) |
|
156 | 136 | |
|
137 | def clear(self): | |
|
138 | """ | |
|
139 | Clear all previously run tasks from the task controller. | |
|
140 | ||
|
141 | This is needed because the task controller keep all task results | |
|
142 | in memory. This can be a problem is there are many completed | |
|
143 | tasks. Users should call this periodically to clean out these | |
|
144 | cached task results. | |
|
145 | """ | |
|
146 | return blockingCallFromThread(self.task_controller.clear) | |
|
147 | ||
|
148 | def map(self, func, *sequences): | |
|
149 | """ | |
|
150 | Apply func to *sequences elementwise. Like Python's builtin map. | |
|
151 | ||
|
152 | This version is load balanced. | |
|
153 | """ | |
|
154 | return self.mapper().map(func, *sequences) | |
|
155 | ||
|
156 | def mapper(self, clear_before=False, clear_after=False, retries=0, | |
|
157 | recovery_task=None, depend=None, block=True): | |
|
158 | """ | |
|
159 | Create an `IMapper` implementer with a given set of arguments. | |
|
160 | ||
|
161 | The `IMapper` created using a task controller is load balanced. | |
|
162 | ||
|
163 | See the documentation for `IPython.kernel.task.BaseTask` for | |
|
164 | documentation on the arguments to this method. | |
|
165 | """ | |
|
166 | return SynchronousTaskMapper(self, clear_before=clear_before, | |
|
167 | clear_after=clear_after, retries=retries, | |
|
168 | recovery_task=recovery_task, depend=depend, block=block) | |
|
169 | ||
|
170 | def parallel(self, clear_before=False, clear_after=False, retries=0, | |
|
171 | recovery_task=None, depend=None, block=True): | |
|
172 | mapper = self.mapper(clear_before, clear_after, retries, | |
|
173 | recovery_task, depend, block) | |
|
174 | pf = ParallelFunction(mapper) | |
|
175 | return pf | |
|
157 | 176 | |
|
158 | 177 | components.registerAdapter(BlockingTaskClient, |
|
159 | 178 | task.ITaskController, IBlockingTaskClient) |
@@ -34,6 +34,15 b' from IPython.kernel.clientinterfaces import (' | |||
|
34 | 34 | IFCClientInterfaceProvider, |
|
35 | 35 | IBlockingClientAdaptor |
|
36 | 36 | ) |
|
37 | from IPython.kernel.mapper import ( | |
|
38 | TaskMapper, | |
|
39 | ITaskMapperFactory, | |
|
40 | IMapper | |
|
41 | ) | |
|
42 | from IPython.kernel.parallelfunction import ( | |
|
43 | ParallelFunction, | |
|
44 | ITaskParallelDecorator | |
|
45 | ) | |
|
37 | 46 | |
|
38 | 47 | #------------------------------------------------------------------------------- |
|
39 | 48 | # The Controller side of things |
@@ -43,32 +52,38 b' from IPython.kernel.clientinterfaces import (' | |||
|
43 | 52 | class IFCTaskController(Interface): |
|
44 | 53 | """Foolscap interface to task controller. |
|
45 | 54 | |
|
46 |
See the documentation of ITaskController |
|
|
55 | See the documentation of `ITaskController` for more information. | |
|
47 | 56 | """ |
|
48 |
def remote_run( |
|
|
57 | def remote_run(binTask): | |
|
49 | 58 | """""" |
|
50 | 59 | |
|
51 |
def remote_abort( |
|
|
60 | def remote_abort(taskid): | |
|
52 | 61 | """""" |
|
53 | 62 | |
|
54 |
def remote_get_task_result( |
|
|
63 | def remote_get_task_result(taskid, block=False): | |
|
55 | 64 | """""" |
|
56 | 65 | |
|
57 |
def remote_barrier( |
|
|
66 | def remote_barrier(taskids): | |
|
58 | 67 | """""" |
|
59 | 68 | |
|
60 |
def remote_spin( |
|
|
69 | def remote_spin(): | |
|
61 | 70 | """""" |
|
62 | 71 | |
|
63 |
def remote_queue_status( |
|
|
72 | def remote_queue_status(verbose): | |
|
73 | """""" | |
|
74 | ||
|
75 | def remote_clear(): | |
|
64 | 76 | """""" |
|
65 | 77 | |
|
66 | 78 | |
|
67 | 79 | class FCTaskControllerFromTaskController(Referenceable): |
|
68 | """XML-RPC attachmeot for controller. | |
|
80 | """ | |
|
81 | Adapt a `TaskController` to an `IFCTaskController` | |
|
69 | 82 |
|
|
70 | See IXMLRPCTaskController and ITaskController (and its children) for documentation. | |
|
83 | This class is used to expose a `TaskController` over the wire using | |
|
84 | the Foolscap network protocol. | |
|
71 | 85 | """ |
|
86 | ||
|
72 | 87 | implements(IFCTaskController, IFCClientInterfaceProvider) |
|
73 | 88 | |
|
74 | 89 | def __init__(self, taskController): |
@@ -92,8 +107,8 b' class FCTaskControllerFromTaskController(Referenceable):' | |||
|
92 | 107 | |
|
93 | 108 | def remote_run(self, ptask): |
|
94 | 109 | try: |
|
95 |
|
|
|
96 |
task |
|
|
110 | task = pickle.loads(ptask) | |
|
111 | task.uncan_task() | |
|
97 | 112 | except: |
|
98 | 113 | d = defer.fail(pickle.UnpickleableError("Could not unmarshal task")) |
|
99 | 114 | else: |
@@ -132,6 +147,9 b' class FCTaskControllerFromTaskController(Referenceable):' | |||
|
132 | 147 | d.addErrback(self.packageFailure) |
|
133 | 148 | return d |
|
134 | 149 | |
|
150 | def remote_clear(self): | |
|
151 | return self.taskController.clear() | |
|
152 | ||
|
135 | 153 | def remote_get_client_name(self): |
|
136 | 154 | return 'IPython.kernel.taskfc.FCTaskClient' |
|
137 | 155 | |
@@ -144,13 +162,23 b' components.registerAdapter(FCTaskControllerFromTaskController,' | |||
|
144 | 162 | #------------------------------------------------------------------------------- |
|
145 | 163 | |
|
146 | 164 | class FCTaskClient(object): |
|
147 | """XML-RPC based TaskController client that implements ITaskController. | |
|
165 | """ | |
|
166 | Client class for Foolscap exposed `TaskController`. | |
|
148 | 167 |
|
|
149 | :Parameters: | |
|
150 | addr : (ip, port) | |
|
151 | The ip (str) and port (int) tuple of the `TaskController`. | |
|
168 | This class is an adapter that makes a `RemoteReference` to a | |
|
169 | `TaskController` look like an actual `ITaskController` on the client side. | |
|
170 | ||
|
171 | This class also implements `IBlockingClientAdaptor` so that clients can | |
|
172 | automatically get a blocking version of this class. | |
|
152 | 173 | """ |
|
153 | implements(taskmodule.ITaskController, IBlockingClientAdaptor) | |
|
174 | ||
|
175 | implements( | |
|
176 | taskmodule.ITaskController, | |
|
177 | IBlockingClientAdaptor, | |
|
178 | ITaskMapperFactory, | |
|
179 | IMapper, | |
|
180 | ITaskParallelDecorator | |
|
181 | ) | |
|
154 | 182 | |
|
155 | 183 | def __init__(self, remote_reference): |
|
156 | 184 | self.remote_reference = remote_reference |
@@ -168,48 +196,26 b' class FCTaskClient(object):' | |||
|
168 | 196 | def run(self, task): |
|
169 | 197 | """Run a task on the `TaskController`. |
|
170 | 198 | |
|
199 | See the documentation of the `MapTask` and `StringTask` classes for | |
|
200 | details on how to build a task of different types. | |
|
201 | ||
|
171 | 202 | :Parameters: |
|
172 |
task : a `Task` |
|
|
173 | ||
|
174 | The Task object is created using the following signature: | |
|
175 | ||
|
176 | Task(expression, pull=None, push={}, clear_before=False, | |
|
177 | clear_after=False, retries=0, **options):) | |
|
178 | ||
|
179 | The meaning of the arguments is as follows: | |
|
180 | ||
|
181 | :Task Parameters: | |
|
182 | expression : str | |
|
183 | A str that is valid python code that is the task. | |
|
184 | pull : str or list of str | |
|
185 | The names of objects to be pulled as results. | |
|
186 | push : dict | |
|
187 | A dict of objects to be pushed into the engines namespace before | |
|
188 | execution of the expression. | |
|
189 | clear_before : boolean | |
|
190 | Should the engine's namespace be cleared before the task is run. | |
|
191 | Default=False. | |
|
192 | clear_after : boolean | |
|
193 | Should the engine's namespace be cleared after the task is run. | |
|
194 | Default=False. | |
|
195 | retries : int | |
|
196 | The number of times to resumbit the task if it fails. Default=0. | |
|
197 | options : dict | |
|
198 | Any other keyword options for more elaborate uses of tasks | |
|
203 | task : an `ITask` implementer | |
|
199 | 204 |
|
|
200 | 205 | :Returns: The int taskid of the submitted task. Pass this to |
|
201 | 206 | `get_task_result` to get the `TaskResult` object. |
|
202 | 207 | """ |
|
203 | assert isinstance(task, taskmodule.Task), "task must be a Task object!" | |
|
204 | ctask = taskmodule.canTask(task) # handles arbitrary function in .depend | |
|
205 | # as well as arbitrary recovery_task chains | |
|
206 | ptask = pickle.dumps(ctask, 2) | |
|
208 | assert isinstance(task, taskmodule.BaseTask), "task must be a Task object!" | |
|
209 | task.can_task() | |
|
210 | ptask = pickle.dumps(task, 2) | |
|
211 | task.uncan_task() | |
|
207 | 212 | d = self.remote_reference.callRemote('run', ptask) |
|
208 | 213 | d.addCallback(self.unpackage) |
|
209 | 214 | return d |
|
210 | 215 | |
|
211 | 216 | def get_task_result(self, taskid, block=False): |
|
212 | """The task result by taskid. | |
|
217 | """ | |
|
218 | Get a task result by taskid. | |
|
213 | 219 | |
|
214 | 220 | :Parameters: |
|
215 | 221 | taskid : int |
@@ -224,20 +230,19 b' class FCTaskClient(object):' | |||
|
224 | 230 | return d |
|
225 | 231 | |
|
226 | 232 | def abort(self, taskid): |
|
227 | """Abort a task by taskid. | |
|
233 | """ | |
|
234 | Abort a task by taskid. | |
|
228 | 235 | |
|
229 | 236 | :Parameters: |
|
230 | 237 | taskid : int |
|
231 | 238 | The taskid of the task to be aborted. |
|
232 | block : boolean | |
|
233 | Should I block until the task is aborted. | |
|
234 | 239 | """ |
|
235 | 240 | d = self.remote_reference.callRemote('abort', taskid) |
|
236 | 241 | d.addCallback(self.unpackage) |
|
237 | 242 | return d |
|
238 | 243 | |
|
239 | 244 | def barrier(self, taskids): |
|
240 |
"""Block until a |
|
|
245 | """Block until a set of tasks are completed. | |
|
241 | 246 | |
|
242 | 247 | :Parameters: |
|
243 | 248 | taskids : list, tuple |
@@ -248,20 +253,77 b' class FCTaskClient(object):' | |||
|
248 | 253 | return d |
|
249 | 254 | |
|
250 | 255 | def spin(self): |
|
251 | """touch the scheduler, to resume scheduling without submitting | |
|
252 | a task. | |
|
256 | """ | |
|
257 | Touch the scheduler, to resume scheduling without submitting a task. | |
|
258 | ||
|
259 | This method only needs to be called in unusual situations where the | |
|
260 | scheduler is idle for some reason. | |
|
253 | 261 | """ |
|
254 | 262 | d = self.remote_reference.callRemote('spin') |
|
255 | 263 | d.addCallback(self.unpackage) |
|
256 | 264 | return d |
|
257 | 265 | |
|
258 | 266 | def queue_status(self, verbose=False): |
|
259 | """Return a dict with the status of the task queue.""" | |
|
267 | """ | |
|
268 | Get a dictionary with the current state of the task queue. | |
|
269 | ||
|
270 | :Parameters: | |
|
271 | verbose : boolean | |
|
272 | If True, return a list of taskids. If False, simply give | |
|
273 | the number of tasks with each status. | |
|
274 | ||
|
275 | :Returns: | |
|
276 | A dict with the queue status. | |
|
277 | """ | |
|
260 | 278 | d = self.remote_reference.callRemote('queue_status', verbose) |
|
261 | 279 | d.addCallback(self.unpackage) |
|
262 | 280 | return d |
|
263 | 281 | |
|
282 | def clear(self): | |
|
283 | """ | |
|
284 | Clear all previously run tasks from the task controller. | |
|
285 | ||
|
286 | This is needed because the task controller keep all task results | |
|
287 | in memory. This can be a problem is there are many completed | |
|
288 | tasks. Users should call this periodically to clean out these | |
|
289 | cached task results. | |
|
290 | """ | |
|
291 | d = self.remote_reference.callRemote('clear') | |
|
292 | return d | |
|
293 | ||
|
264 | 294 | def adapt_to_blocking_client(self): |
|
295 | """ | |
|
296 | Wrap self in a blocking version that implements `IBlockingTaskClient. | |
|
297 | """ | |
|
265 | 298 | from IPython.kernel.taskclient import IBlockingTaskClient |
|
266 | 299 | return IBlockingTaskClient(self) |
|
267 | 300 | |
|
301 | def map(self, func, *sequences): | |
|
302 | """ | |
|
303 | Apply func to *sequences elementwise. Like Python's builtin map. | |
|
304 | ||
|
305 | This version is load balanced. | |
|
306 | """ | |
|
307 | return self.mapper().map(func, *sequences) | |
|
308 | ||
|
309 | def mapper(self, clear_before=False, clear_after=False, retries=0, | |
|
310 | recovery_task=None, depend=None, block=True): | |
|
311 | """ | |
|
312 | Create an `IMapper` implementer with a given set of arguments. | |
|
313 | ||
|
314 | The `IMapper` created using a task controller is load balanced. | |
|
315 | ||
|
316 | See the documentation for `IPython.kernel.task.BaseTask` for | |
|
317 | documentation on the arguments to this method. | |
|
318 | """ | |
|
319 | return TaskMapper(self, clear_before=clear_before, | |
|
320 | clear_after=clear_after, retries=retries, | |
|
321 | recovery_task=recovery_task, depend=depend, block=block) | |
|
322 | ||
|
323 | def parallel(self, clear_before=False, clear_after=False, retries=0, | |
|
324 | recovery_task=None, depend=None, block=True): | |
|
325 | mapper = self.mapper(clear_before, clear_after, retries, | |
|
326 | recovery_task, depend, block) | |
|
327 | pf = ParallelFunction(mapper) | |
|
328 | return pf | |
|
329 |
@@ -163,7 +163,6 b' class IEngineCoreTestCase(object):' | |||
|
163 | 163 | try: |
|
164 | 164 | import numpy |
|
165 | 165 | except: |
|
166 | print 'no numpy, ', | |
|
167 | 166 | return |
|
168 | 167 | a = numpy.random.random(1000) |
|
169 | 168 | d = self.engine.push(dict(a=a)) |
@@ -750,16 +750,6 b' class ISynchronousMultiEngineCoordinatorTestCase(IMultiEngineCoordinatorTestCase' | |||
|
750 | 750 | d.addCallback(lambda r: assert_array_equal(r, a)) |
|
751 | 751 | return d |
|
752 | 752 | |
|
753 | def testMapNonblocking(self): | |
|
754 | self.addEngine(4) | |
|
755 | def f(x): | |
|
756 | return x**2 | |
|
757 | data = range(16) | |
|
758 | d= self.multiengine.map(f, data, block=False) | |
|
759 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
|
760 | d.addCallback(lambda r: self.assertEquals(r,[f(x) for x in data])) | |
|
761 | return d | |
|
762 | ||
|
763 | 753 | def test_clear_pending_deferreds(self): |
|
764 | 754 | self.addEngine(4) |
|
765 | 755 | did_list = [] |
@@ -43,23 +43,23 b' class TaskTestBase(object):' | |||
|
43 | 43 | |
|
44 | 44 | class ITaskControllerTestCase(TaskTestBase): |
|
45 | 45 | |
|
46 |
def test |
|
|
46 | def test_task_ids(self): | |
|
47 | 47 | self.addEngine(1) |
|
48 | d = self.tc.run(task.Task('a=5')) | |
|
48 | d = self.tc.run(task.StringTask('a=5')) | |
|
49 | 49 | d.addCallback(lambda r: self.assertEquals(r, 0)) |
|
50 | d.addCallback(lambda r: self.tc.run(task.Task('a=5'))) | |
|
50 | d.addCallback(lambda r: self.tc.run(task.StringTask('a=5'))) | |
|
51 | 51 | d.addCallback(lambda r: self.assertEquals(r, 1)) |
|
52 | d.addCallback(lambda r: self.tc.run(task.Task('a=5'))) | |
|
52 | d.addCallback(lambda r: self.tc.run(task.StringTask('a=5'))) | |
|
53 | 53 | d.addCallback(lambda r: self.assertEquals(r, 2)) |
|
54 | d.addCallback(lambda r: self.tc.run(task.Task('a=5'))) | |
|
54 | d.addCallback(lambda r: self.tc.run(task.StringTask('a=5'))) | |
|
55 | 55 | d.addCallback(lambda r: self.assertEquals(r, 3)) |
|
56 | 56 | return d |
|
57 | 57 | |
|
58 |
def test |
|
|
58 | def test_abort(self): | |
|
59 | 59 | """Cannot do a proper abort test, because blocking execution prevents |
|
60 | 60 | abort from being called before task completes""" |
|
61 | 61 | self.addEngine(1) |
|
62 | t = task.Task('a=5') | |
|
62 | t = task.StringTask('a=5') | |
|
63 | 63 | d = self.tc.abort(0) |
|
64 | 64 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) |
|
65 | 65 | d.addCallback(lambda _:self.tc.run(t)) |
@@ -67,15 +67,15 b' class ITaskControllerTestCase(TaskTestBase):' | |||
|
67 | 67 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) |
|
68 | 68 | return d |
|
69 | 69 | |
|
70 |
def test |
|
|
70 | def test_abort_type(self): | |
|
71 | 71 | self.addEngine(1) |
|
72 | 72 | d = self.tc.abort('asdfadsf') |
|
73 | 73 | d.addErrback(lambda f: self.assertRaises(TypeError, f.raiseException)) |
|
74 | 74 | return d |
|
75 | 75 | |
|
76 |
def test |
|
|
76 | def test_clear_before_and_after(self): | |
|
77 | 77 | self.addEngine(1) |
|
78 | t = task.Task('a=1', clear_before=True, pull='b', clear_after=True) | |
|
78 | t = task.StringTask('a=1', clear_before=True, pull='b', clear_after=True) | |
|
79 | 79 | d = self.multiengine.execute('b=1', targets=0) |
|
80 | 80 | d.addCallback(lambda _: self.tc.run(t)) |
|
81 | 81 | d.addCallback(lambda tid: self.tc.get_task_result(tid,block=True)) |
@@ -85,10 +85,10 b' class ITaskControllerTestCase(TaskTestBase):' | |||
|
85 | 85 | d.addErrback(lambda f: self.assertRaises(NameError, _raise_it, f)) |
|
86 | 86 | return d |
|
87 | 87 | |
|
88 |
def test |
|
|
88 | def test_simple_retries(self): | |
|
89 | 89 | self.addEngine(1) |
|
90 | t = task.Task("i += 1\nassert i == 16", pull='i',retries=10) | |
|
91 | t2 = task.Task("i += 1\nassert i == 16", pull='i',retries=10) | |
|
90 | t = task.StringTask("i += 1\nassert i == 16", pull='i',retries=10) | |
|
91 | t2 = task.StringTask("i += 1\nassert i == 16", pull='i',retries=10) | |
|
92 | 92 | d = self.multiengine.execute('i=0', targets=0) |
|
93 | 93 | d.addCallback(lambda r: self.tc.run(t)) |
|
94 | 94 | d.addCallback(self.tc.get_task_result, block=True) |
@@ -101,10 +101,10 b' class ITaskControllerTestCase(TaskTestBase):' | |||
|
101 | 101 | d.addCallback(lambda r: self.assertEquals(r, 16)) |
|
102 | 102 | return d |
|
103 | 103 | |
|
104 |
def test |
|
|
104 | def test_recovery_tasks(self): | |
|
105 | 105 | self.addEngine(1) |
|
106 | t = task.Task("i=16", pull='i') | |
|
107 | t2 = task.Task("raise Exception", recovery_task=t, retries = 2) | |
|
106 | t = task.StringTask("i=16", pull='i') | |
|
107 | t2 = task.StringTask("raise Exception", recovery_task=t, retries = 2) | |
|
108 | 108 | |
|
109 | 109 | d = self.tc.run(t2) |
|
110 | 110 | d.addCallback(self.tc.get_task_result, block=True) |
@@ -112,47 +112,76 b' class ITaskControllerTestCase(TaskTestBase):' | |||
|
112 | 112 | d.addCallback(lambda r: self.assertEquals(r, 16)) |
|
113 | 113 | return d |
|
114 | 114 | |
|
115 | # def testInfiniteRecoveryLoop(self): | |
|
116 | # self.addEngine(1) | |
|
117 | # t = task.Task("raise Exception", retries = 5) | |
|
118 | # t2 = task.Task("assert True", retries = 2, recovery_task = t) | |
|
119 | # t.recovery_task = t2 | |
|
120 | # | |
|
121 | # d = self.tc.run(t) | |
|
122 | # d.addCallback(self.tc.get_task_result, block=True) | |
|
123 | # d.addCallback(lambda tr: tr.ns.i) | |
|
124 | # d.addBoth(printer) | |
|
125 | # d.addErrback(lambda f: self.assertRaises(AssertionError, f.raiseException)) | |
|
126 | # return d | |
|
127 | # | |
|
128 | def testSetupNS(self): | |
|
115 | def test_setup_ns(self): | |
|
129 | 116 | self.addEngine(1) |
|
130 | 117 | d = self.multiengine.execute('a=0', targets=0) |
|
131 | 118 | ns = dict(a=1, b=0) |
|
132 | t = task.Task("", push=ns, pull=['a','b']) | |
|
119 | t = task.StringTask("", push=ns, pull=['a','b']) | |
|
133 | 120 | d.addCallback(lambda r: self.tc.run(t)) |
|
134 | 121 | d.addCallback(self.tc.get_task_result, block=True) |
|
135 | 122 | d.addCallback(lambda tr: {'a':tr.ns.a, 'b':tr['b']}) |
|
136 | 123 | d.addCallback(lambda r: self.assertEquals(r, ns)) |
|
137 | 124 | return d |
|
138 | 125 | |
|
139 |
def test |
|
|
126 | def test_string_task_results(self): | |
|
140 | 127 | self.addEngine(1) |
|
141 | t1 = task.Task('a=5', pull='a') | |
|
128 | t1 = task.StringTask('a=5', pull='a') | |
|
142 | 129 | d = self.tc.run(t1) |
|
143 | 130 | d.addCallback(self.tc.get_task_result, block=True) |
|
144 |
d.addCallback(lambda tr: (tr.ns.a,tr['a'],tr.failure, tr.raise |
|
|
131 | d.addCallback(lambda tr: (tr.ns.a,tr['a'],tr.failure, tr.raise_exception())) | |
|
145 | 132 | d.addCallback(lambda r: self.assertEquals(r, (5,5,None,None))) |
|
146 | 133 | |
|
147 | t2 = task.Task('7=5') | |
|
134 | t2 = task.StringTask('7=5') | |
|
148 | 135 | d.addCallback(lambda r: self.tc.run(t2)) |
|
149 | 136 | d.addCallback(self.tc.get_task_result, block=True) |
|
150 | 137 | d.addCallback(lambda tr: tr.ns) |
|
151 | 138 | d.addErrback(lambda f: self.assertRaises(SyntaxError, f.raiseException)) |
|
152 | 139 | |
|
153 | t3 = task.Task('', pull='b') | |
|
140 | t3 = task.StringTask('', pull='b') | |
|
154 | 141 | d.addCallback(lambda r: self.tc.run(t3)) |
|
155 | 142 | d.addCallback(self.tc.get_task_result, block=True) |
|
156 | 143 | d.addCallback(lambda tr: tr.ns) |
|
157 | 144 | d.addErrback(lambda f: self.assertRaises(NameError, f.raiseException)) |
|
158 | 145 | return d |
|
146 | ||
|
147 | def test_map_task(self): | |
|
148 | self.addEngine(1) | |
|
149 | t1 = task.MapTask(lambda x: 2*x,(10,)) | |
|
150 | d = self.tc.run(t1) | |
|
151 | d.addCallback(self.tc.get_task_result, block=True) | |
|
152 | d.addCallback(lambda r: self.assertEquals(r,20)) | |
|
153 | ||
|
154 | t2 = task.MapTask(lambda : 20) | |
|
155 | d.addCallback(lambda _: self.tc.run(t2)) | |
|
156 | d.addCallback(self.tc.get_task_result, block=True) | |
|
157 | d.addCallback(lambda r: self.assertEquals(r,20)) | |
|
158 | ||
|
159 | t3 = task.MapTask(lambda x: x,(),{'x':20}) | |
|
160 | d.addCallback(lambda _: self.tc.run(t3)) | |
|
161 | d.addCallback(self.tc.get_task_result, block=True) | |
|
162 | d.addCallback(lambda r: self.assertEquals(r,20)) | |
|
163 | return d | |
|
164 | ||
|
165 | def test_map_task_failure(self): | |
|
166 | self.addEngine(1) | |
|
167 | t1 = task.MapTask(lambda x: 1/0,(10,)) | |
|
168 | d = self.tc.run(t1) | |
|
169 | d.addCallback(self.tc.get_task_result, block=True) | |
|
170 | d.addErrback(lambda f: self.assertRaises(ZeroDivisionError, f.raiseException)) | |
|
171 | return d | |
|
172 | ||
|
173 | def test_map_task_args(self): | |
|
174 | self.assertRaises(TypeError, task.MapTask, 'asdfasdf') | |
|
175 | self.assertRaises(TypeError, task.MapTask, lambda x: x, 10) | |
|
176 | self.assertRaises(TypeError, task.MapTask, lambda x: x, (10,),30) | |
|
177 | ||
|
178 | def test_clear(self): | |
|
179 | self.addEngine(1) | |
|
180 | t1 = task.MapTask(lambda x: 2*x,(10,)) | |
|
181 | d = self.tc.run(t1) | |
|
182 | d.addCallback(lambda _: self.tc.get_task_result(0, block=True)) | |
|
183 | d.addCallback(lambda r: self.assertEquals(r,20)) | |
|
184 | d.addCallback(lambda _: self.tc.clear()) | |
|
185 | d.addCallback(lambda _: self.tc.get_task_result(0, block=True)) | |
|
186 | d.addErrback(lambda f: self.assertRaises(IndexError, f.raiseException)) | |
|
187 | return d |
@@ -38,7 +38,7 b' try:' | |||
|
38 | 38 | IEngineQueuedTestCase |
|
39 | 39 | except ImportError: |
|
40 | 40 | print "we got an error!!!" |
|
41 |
|
|
|
41 | raise | |
|
42 | 42 | else: |
|
43 | 43 | class EngineFCTest(DeferredTestCase, |
|
44 | 44 | IEngineCoreTestCase, |
@@ -26,9 +26,20 b' try:' | |||
|
26 | 26 | from IPython.kernel.multienginefc import IFCSynchronousMultiEngine |
|
27 | 27 | from IPython.kernel import multiengine as me |
|
28 | 28 | from IPython.kernel.clientconnector import ClientConnector |
|
29 | from IPython.kernel.parallelfunction import ParallelFunction | |
|
30 | from IPython.kernel.error import CompositeError | |
|
31 | from IPython.kernel.util import printer | |
|
29 | 32 | except ImportError: |
|
30 | 33 | pass |
|
31 | 34 | else: |
|
35 | ||
|
36 | def _raise_it(f): | |
|
37 | try: | |
|
38 | f.raiseException() | |
|
39 | except CompositeError, e: | |
|
40 | e.raise_exception() | |
|
41 | ||
|
42 | ||
|
32 | 43 | class FullSynchronousMultiEngineTestCase(DeferredTestCase, IFullSynchronousMultiEngineTestCase): |
|
33 | 44 | |
|
34 | 45 | def setUp(self): |
@@ -68,3 +79,66 b' else:' | |||
|
68 | 79 | d.addBoth(lambda _: self.controller.stopService()) |
|
69 | 80 | dlist.append(d) |
|
70 | 81 | return defer.DeferredList(dlist) |
|
82 | ||
|
83 | def test_mapper(self): | |
|
84 | self.addEngine(4) | |
|
85 | m = self.multiengine.mapper() | |
|
86 | self.assertEquals(m.multiengine,self.multiengine) | |
|
87 | self.assertEquals(m.dist,'b') | |
|
88 | self.assertEquals(m.targets,'all') | |
|
89 | self.assertEquals(m.block,True) | |
|
90 | ||
|
91 | def test_map_default(self): | |
|
92 | self.addEngine(4) | |
|
93 | m = self.multiengine.mapper() | |
|
94 | d = m.map(lambda x: 2*x, range(10)) | |
|
95 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
96 | d.addCallback(lambda _: self.multiengine.map(lambda x: 2*x, range(10))) | |
|
97 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
98 | return d | |
|
99 | ||
|
100 | def test_map_noblock(self): | |
|
101 | self.addEngine(4) | |
|
102 | m = self.multiengine.mapper(block=False) | |
|
103 | d = m.map(lambda x: 2*x, range(10)) | |
|
104 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
|
105 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
106 | return d | |
|
107 | ||
|
108 | def test_mapper_fail(self): | |
|
109 | self.addEngine(4) | |
|
110 | m = self.multiengine.mapper() | |
|
111 | d = m.map(lambda x: 1/0, range(10)) | |
|
112 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |
|
113 | return d | |
|
114 | ||
|
115 | def test_parallel(self): | |
|
116 | self.addEngine(4) | |
|
117 | p = self.multiengine.parallel() | |
|
118 | self.assert_(isinstance(p, ParallelFunction)) | |
|
119 | @p | |
|
120 | def f(x): return 2*x | |
|
121 | d = f(range(10)) | |
|
122 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
123 | return d | |
|
124 | ||
|
125 | def test_parallel_noblock(self): | |
|
126 | self.addEngine(1) | |
|
127 | p = self.multiengine.parallel(block=False) | |
|
128 | self.assert_(isinstance(p, ParallelFunction)) | |
|
129 | @p | |
|
130 | def f(x): return 2*x | |
|
131 | d = f(range(10)) | |
|
132 | d.addCallback(lambda did: self.multiengine.get_pending_deferred(did, True)) | |
|
133 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
134 | return d | |
|
135 | ||
|
136 | def test_parallel_fail(self): | |
|
137 | self.addEngine(4) | |
|
138 | p = self.multiengine.parallel() | |
|
139 | self.assert_(isinstance(p, ParallelFunction)) | |
|
140 | @p | |
|
141 | def f(x): return 1/0 | |
|
142 | d = f(range(10)) | |
|
143 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |
|
144 | return d No newline at end of file |
@@ -20,8 +20,6 b' try:' | |||
|
20 | 20 | from twisted.internet import defer |
|
21 | 21 | from twisted.python import failure |
|
22 | 22 | |
|
23 | from IPython.testing import tcommon | |
|
24 | from IPython.testing.tcommon import * | |
|
25 | 23 | from IPython.testing.util import DeferredTestCase |
|
26 | 24 | import IPython.kernel.pendingdeferred as pd |
|
27 | 25 | from IPython.kernel import error |
@@ -30,25 +28,6 b' except ImportError:' | |||
|
30 | 28 | pass |
|
31 | 29 | else: |
|
32 | 30 | |
|
33 | #------------------------------------------------------------------------------- | |
|
34 | # Setup for inline and standalone doctests | |
|
35 | #------------------------------------------------------------------------------- | |
|
36 | ||
|
37 | ||
|
38 | # If you have standalone doctests in a separate file, set their names in the | |
|
39 | # dt_files variable (as a single string or a list thereof): | |
|
40 | dt_files = [] | |
|
41 | ||
|
42 | # If you have any modules whose docstrings should be scanned for embedded tests | |
|
43 | # as examples accorging to standard doctest practice, set them here (as a | |
|
44 | # single string or a list thereof): | |
|
45 | dt_modules = [] | |
|
46 | ||
|
47 | #------------------------------------------------------------------------------- | |
|
48 | # Regular Unittests | |
|
49 | #------------------------------------------------------------------------------- | |
|
50 | ||
|
51 | ||
|
52 | 31 | class Foo(object): |
|
53 | 32 | |
|
54 | 33 | def bar(self, bahz): |
@@ -205,14 +184,3 b' else:' | |||
|
205 | 184 | d3 = self.pdm.get_pending_deferred(did,False) |
|
206 | 185 | d3.addCallback(lambda r: self.assertEquals(r,'bar')) |
|
207 | 186 | |
|
208 | #------------------------------------------------------------------------------- | |
|
209 | # Regular Unittests | |
|
210 | #------------------------------------------------------------------------------- | |
|
211 | ||
|
212 | # This ensures that the code will run either standalone as a script, or that it | |
|
213 | # can be picked up by Twisted's `trial` test wrapper to run all the tests. | |
|
214 | if tcommon.pexpect is not None: | |
|
215 | if __name__ == '__main__': | |
|
216 | unittest.main(testLoader=IPDocTestLoader(dt_files,dt_modules)) | |
|
217 | else: | |
|
218 | testSuite = lambda : makeTestSuite(__name__,dt_files,dt_modules) |
@@ -30,6 +30,8 b' try:' | |||
|
30 | 30 | from IPython.kernel.util import printer |
|
31 | 31 | from IPython.kernel.tests.tasktest import ITaskControllerTestCase |
|
32 | 32 | from IPython.kernel.clientconnector import ClientConnector |
|
33 | from IPython.kernel.error import CompositeError | |
|
34 | from IPython.kernel.parallelfunction import ParallelFunction | |
|
33 | 35 | except ImportError: |
|
34 | 36 | pass |
|
35 | 37 | else: |
@@ -38,6 +40,12 b' else:' | |||
|
38 | 40 | # Tests |
|
39 | 41 | #------------------------------------------------------------------------------- |
|
40 | 42 | |
|
43 | def _raise_it(f): | |
|
44 | try: | |
|
45 | f.raiseException() | |
|
46 | except CompositeError, e: | |
|
47 | e.raise_exception() | |
|
48 | ||
|
41 | 49 | class TaskTest(DeferredTestCase, ITaskControllerTestCase): |
|
42 | 50 | |
|
43 | 51 | def setUp(self): |
@@ -88,3 +96,66 b' else:' | |||
|
88 | 96 | dlist.append(d) |
|
89 | 97 | return defer.DeferredList(dlist) |
|
90 | 98 | |
|
99 | def test_mapper(self): | |
|
100 | self.addEngine(1) | |
|
101 | m = self.tc.mapper() | |
|
102 | self.assertEquals(m.task_controller,self.tc) | |
|
103 | self.assertEquals(m.clear_before,False) | |
|
104 | self.assertEquals(m.clear_after,False) | |
|
105 | self.assertEquals(m.retries,0) | |
|
106 | self.assertEquals(m.recovery_task,None) | |
|
107 | self.assertEquals(m.depend,None) | |
|
108 | self.assertEquals(m.block,True) | |
|
109 | ||
|
110 | def test_map_default(self): | |
|
111 | self.addEngine(1) | |
|
112 | m = self.tc.mapper() | |
|
113 | d = m.map(lambda x: 2*x, range(10)) | |
|
114 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
115 | d.addCallback(lambda _: self.tc.map(lambda x: 2*x, range(10))) | |
|
116 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
117 | return d | |
|
118 | ||
|
119 | def test_map_noblock(self): | |
|
120 | self.addEngine(1) | |
|
121 | m = self.tc.mapper(block=False) | |
|
122 | d = m.map(lambda x: 2*x, range(10)) | |
|
123 | d.addCallback(lambda r: self.assertEquals(r,[x for x in range(10)])) | |
|
124 | return d | |
|
125 | ||
|
126 | def test_mapper_fail(self): | |
|
127 | self.addEngine(1) | |
|
128 | m = self.tc.mapper() | |
|
129 | d = m.map(lambda x: 1/0, range(10)) | |
|
130 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |
|
131 | return d | |
|
132 | ||
|
133 | def test_parallel(self): | |
|
134 | self.addEngine(1) | |
|
135 | p = self.tc.parallel() | |
|
136 | self.assert_(isinstance(p, ParallelFunction)) | |
|
137 | @p | |
|
138 | def f(x): return 2*x | |
|
139 | d = f(range(10)) | |
|
140 | d.addCallback(lambda r: self.assertEquals(r,[2*x for x in range(10)])) | |
|
141 | return d | |
|
142 | ||
|
143 | def test_parallel_noblock(self): | |
|
144 | self.addEngine(1) | |
|
145 | p = self.tc.parallel(block=False) | |
|
146 | self.assert_(isinstance(p, ParallelFunction)) | |
|
147 | @p | |
|
148 | def f(x): return 2*x | |
|
149 | d = f(range(10)) | |
|
150 | d.addCallback(lambda r: self.assertEquals(r,[x for x in range(10)])) | |
|
151 | return d | |
|
152 | ||
|
153 | def test_parallel_fail(self): | |
|
154 | self.addEngine(1) | |
|
155 | p = self.tc.parallel() | |
|
156 | self.assert_(isinstance(p, ParallelFunction)) | |
|
157 | @p | |
|
158 | def f(x): return 1/0 | |
|
159 | d = f(range(10)) | |
|
160 | d.addBoth(lambda f: self.assertRaises(ZeroDivisionError, _raise_it, f)) | |
|
161 | return d No newline at end of file |
@@ -1,13 +1,32 b'' | |||
|
1 | """String dispatch class to match regexps and dispatch commands. | |
|
2 | """ | |
|
3 | ||
|
4 | # Stdlib imports | |
|
5 | import re | |
|
6 | ||
|
7 | # Our own modules | |
|
1 | 8 | from IPython.hooks import CommandChainDispatcher |
|
2 | 9 | import IPython.hooks |
|
3 | 10 | |
|
4 | import re | |
|
5 | 11 | |
|
12 | # Code begins | |
|
6 | 13 | class StrDispatch(object): |
|
7 |
""" |
|
|
14 | """Dispatch (lookup) a set of strings / regexps for match. | |
|
15 | ||
|
16 | Example: | |
|
17 | ||
|
18 | >>> dis = StrDispatch() | |
|
19 | >>> dis.add_s('hei',34, priority = 4) | |
|
20 | >>> dis.add_s('hei',123, priority = 2) | |
|
21 | >>> dis.add_re('h.i', 686) | |
|
22 | >>> print list(dis.flat_matches('hei')) | |
|
23 | [123, 34, 686] | |
|
24 | """ | |
|
25 | ||
|
8 | 26 | def __init__(self): |
|
9 | 27 | self.strs = {} |
|
10 | 28 | self.regexs = {} |
|
29 | ||
|
11 | 30 | def add_s(self, s, obj, priority= 0 ): |
|
12 | 31 | """ Adds a target 'string' for dispatching """ |
|
13 | 32 | |
@@ -31,10 +50,9 b' class StrDispatch(object):' | |||
|
31 | 50 | if re.match(r, key): |
|
32 | 51 | yield obj |
|
33 | 52 | else: |
|
34 | #print "nomatch",key | |
|
53 | #print "nomatch",key # dbg | |
|
35 | 54 | pass |
|
36 | 55 | |
|
37 | ||
|
38 | 56 | def __repr__(self): |
|
39 | 57 | return "<Strdispatch %s, %s>" % (self.strs, self.regexs) |
|
40 | 58 | |
@@ -44,22 +62,9 b' class StrDispatch(object):' | |||
|
44 | 62 | for el in self.strs[key]: |
|
45 | 63 | yield el[1] |
|
46 | 64 | |
|
47 | ||
|
48 | 65 | def flat_matches(self, key): |
|
49 | 66 | """ Yield all 'value' targets, without priority """ |
|
50 | 67 | for val in self.dispatch(key): |
|
51 | 68 | for el in val: |
|
52 | 69 | yield el[1] # only value, no priority |
|
53 | 70 | return |
|
54 | ||
|
55 | ||
|
56 | def test(): | |
|
57 | d = StrDispatch() | |
|
58 | d.add_s('hei',34, priority = 4) | |
|
59 | d.add_s('hei',123, priority = 2) | |
|
60 | print list(d.dispatch('hei')) | |
|
61 | d.add_re('h.i', 686) | |
|
62 | print list(d.flat_matches('hei')) | |
|
63 | ||
|
64 | if __name__ == '__main__': | |
|
65 | test() No newline at end of file |
|
1 | NO CONTENT: file renamed from IPython/testing/attic/parametric.py to IPython/testing/parametric.py |
@@ -2,17 +2,51 b'' | |||
|
2 | 2 | PREFIX=~/usr/local |
|
3 | 3 | PREFIX=~/tmp/local |
|
4 | 4 | |
|
5 | NOSE0=nosetests -vs --with-doctest --doctest-tests | |
|
6 | NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt | |
|
7 | ||
|
8 | #--with-color | |
|
9 | ||
|
10 | SRC=ipdoctest.py setup.py ../decorators.py | |
|
11 | ||
|
5 | 12 | plugin: IPython_doctest_plugin.egg-info |
|
6 | 13 | |
|
14 | dtest: plugin dtexample.py | |
|
15 | $(NOSE) dtexample.py | |
|
16 | ||
|
17 | # Note: this test is double counting!!! | |
|
18 | rtest: plugin dtexample.py | |
|
19 | $(NOSE) test_refs.py | |
|
20 | ||
|
21 | std: plugin | |
|
22 | nosetests -vs --with-doctest --doctest-tests IPython.strdispatch | |
|
23 | $(NOSE) IPython.strdispatch | |
|
24 | ||
|
7 | 25 | test: plugin dtexample.py |
|
8 | nosetests -s --with-ipdoctest --doctest-tests --doctest-extension=txt \ | |
|
9 | dtexample.py test*.txt | |
|
26 | $(NOSE) dtexample.py test*.py test*.txt | |
|
10 | 27 | |
|
11 | 28 | deb: plugin dtexample.py |
|
12 | nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \ | |
|
13 | test_combo.txt | |
|
29 | $(NOSE) test_combo.txt | |
|
30 | ||
|
31 | iptest: plugin | |
|
32 | $(NOSE) IPython | |
|
33 | ||
|
34 | deco: | |
|
35 | $(NOSE0) IPython.testing.decorators | |
|
36 | ||
|
37 | mtest: plugin | |
|
38 | $(NOSE) -x IPython.Magic | |
|
39 | ||
|
40 | ipipe: plugin | |
|
41 | $(NOSE) -x IPython.Extensions.ipipe | |
|
42 | ||
|
43 | sr: rtest std | |
|
44 | ||
|
45 | base: dtest rtest test std deco | |
|
46 | ||
|
47 | all: base iptest | |
|
14 | 48 | |
|
15 |
IPython_doctest_plugin.egg-info: |
|
|
49 | IPython_doctest_plugin.egg-info: $(SRC) | |
|
16 | 50 | python setup.py install --prefix=$(PREFIX) |
|
17 | 51 | touch $@ |
|
18 | 52 |
@@ -21,9 +21,9 b' def pyfunc():' | |||
|
21 | 21 | ... |
|
22 | 22 | 0 1 1 2 2 3 |
|
23 | 23 | """ |
|
24 | ||
|
25 | 24 | return 'pyfunc' |
|
26 | 25 | |
|
26 | ||
|
27 | 27 | def ipfunc(): |
|
28 | 28 | """Some ipython tests... |
|
29 | 29 | |
@@ -67,6 +67,93 b' def ipfunc():' | |||
|
67 | 67 | In [9]: ipfunc() |
|
68 | 68 | Out[9]: 'ipfunc' |
|
69 | 69 | """ |
|
70 | ||
|
71 | 70 | return 'ipfunc' |
|
72 | 71 | |
|
72 | ||
|
73 | def ranfunc(): | |
|
74 | """A function with some random output. | |
|
75 | ||
|
76 | Normal examples are verified as usual: | |
|
77 | >>> 1+3 | |
|
78 | 4 | |
|
79 | ||
|
80 | But if you put '# random' in the output, it is ignored: | |
|
81 | >>> 1+3 | |
|
82 | junk goes here... # random | |
|
83 | ||
|
84 | >>> 1+2 | |
|
85 | again, anything goes #random | |
|
86 | if multiline, the random mark is only needed once. | |
|
87 | ||
|
88 | >>> 1+2 | |
|
89 | You can also put the random marker at the end: | |
|
90 | # random | |
|
91 | ||
|
92 | >>> 1+2 | |
|
93 | # random | |
|
94 | .. or at the beginning. | |
|
95 | ||
|
96 | More correct input is properly verified: | |
|
97 | >>> ranfunc() | |
|
98 | 'ranfunc' | |
|
99 | """ | |
|
100 | return 'ranfunc' | |
|
101 | ||
|
102 | ||
|
103 | def random_all(): | |
|
104 | """A function where we ignore the output of ALL examples. | |
|
105 | ||
|
106 | Examples: | |
|
107 | ||
|
108 | # all-random | |
|
109 | ||
|
110 | This mark tells the testing machinery that all subsequent examples should | |
|
111 | be treated as random (ignoring their output). They are still executed, | |
|
112 | so if a they raise an error, it will be detected as such, but their | |
|
113 | output is completely ignored. | |
|
114 | ||
|
115 | >>> 1+3 | |
|
116 | junk goes here... | |
|
117 | ||
|
118 | >>> 1+3 | |
|
119 | klasdfj; | |
|
120 | ||
|
121 | >>> 1+2 | |
|
122 | again, anything goes | |
|
123 | blah... | |
|
124 | """ | |
|
125 | pass | |
|
126 | ||
|
127 | ||
|
128 | def iprand(): | |
|
129 | """Some ipython tests with random output. | |
|
130 | ||
|
131 | In [7]: 3+4 | |
|
132 | Out[7]: 7 | |
|
133 | ||
|
134 | In [8]: print 'hello' | |
|
135 | world # random | |
|
136 | ||
|
137 | In [9]: iprand() | |
|
138 | Out[9]: 'iprand' | |
|
139 | """ | |
|
140 | return 'iprand' | |
|
141 | ||
|
142 | ||
|
143 | def iprand_all(): | |
|
144 | """Some ipython tests with fully random output. | |
|
145 | ||
|
146 | # all-random | |
|
147 | ||
|
148 | In [7]: 1 | |
|
149 | Out[7]: 99 | |
|
150 | ||
|
151 | In [8]: print 'hello' | |
|
152 | world | |
|
153 | ||
|
154 | In [9]: iprand_all() | |
|
155 | Out[9]: 'junk' | |
|
156 | """ | |
|
157 | return 'iprand_all' | |
|
158 | ||
|
159 |
@@ -43,9 +43,19 b' import logging' | |||
|
43 | 43 | import os |
|
44 | 44 | import re |
|
45 | 45 | import sys |
|
46 | import traceback | |
|
46 | 47 | import unittest |
|
47 | 48 | |
|
48 | 49 | from inspect import getmodule |
|
50 | from StringIO import StringIO | |
|
51 | ||
|
52 | # We are overriding the default doctest runner, so we need to import a few | |
|
53 | # things from doctest directly | |
|
54 | from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE, | |
|
55 | _unittest_reportflags, DocTestRunner, | |
|
56 | _extract_future_flags, pdb, _OutputRedirectingPdb, | |
|
57 | _exception_traceback, | |
|
58 | linecache) | |
|
49 | 59 | |
|
50 | 60 | # Third-party modules |
|
51 | 61 | import nose.core |
@@ -68,9 +78,27 b' log = logging.getLogger(__name__)' | |||
|
68 | 78 | # machinery into a fit. This code should be considered a gross hack, but it |
|
69 | 79 | # gets the job done. |
|
70 | 80 | |
|
81 | ||
|
82 | # XXX - Hack to modify the %run command so we can sync the user's namespace | |
|
83 | # with the test globals. Once we move over to a clean magic system, this will | |
|
84 | # be done with much less ugliness. | |
|
85 | ||
|
86 | def _run_ns_sync(self,arg_s,runner=None): | |
|
87 | """Modified version of %run that syncs testing namespaces. | |
|
88 | ||
|
89 | This is strictly needed for running doctests that call %run. | |
|
90 | """ | |
|
91 | ||
|
92 | out = _ip.IP.magic_run_ori(arg_s,runner) | |
|
93 | _run_ns_sync.test_globs.update(_ip.user_ns) | |
|
94 | return out | |
|
95 | ||
|
96 | ||
|
71 | 97 | def start_ipython(): |
|
72 | 98 | """Start a global IPython shell, which we need for IPython-specific syntax. |
|
73 | 99 | """ |
|
100 | import new | |
|
101 | ||
|
74 | 102 | import IPython |
|
75 | 103 | |
|
76 | 104 | def xsys(cmd): |
@@ -88,7 +116,7 b' def start_ipython():' | |||
|
88 | 116 | _excepthook = sys.excepthook |
|
89 | 117 | _main = sys.modules.get('__main__') |
|
90 | 118 | |
|
91 | # Start IPython instance | |
|
119 | # Start IPython instance. We customize it to start with minimal frills. | |
|
92 | 120 | IPython.Shell.IPShell(['--classic','--noterm_title']) |
|
93 | 121 | |
|
94 | 122 | # Deactivate the various python system hooks added by ipython for |
@@ -107,6 +135,11 b' def start_ipython():' | |||
|
107 | 135 | # doctest machinery would miss them. |
|
108 | 136 | _ip.system = xsys |
|
109 | 137 | |
|
138 | # Also patch our %run function in. | |
|
139 | im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__) | |
|
140 | _ip.IP.magic_run_ori = _ip.IP.magic_run | |
|
141 | _ip.IP.magic_run = im | |
|
142 | ||
|
110 | 143 | # The start call MUST be made here. I'm not sure yet why it doesn't work if |
|
111 | 144 | # it is made later, at plugin initialization time, but in all my tests, that's |
|
112 | 145 | # the case. |
@@ -115,7 +148,26 b' start_ipython()' | |||
|
115 | 148 | # *** END HACK *** |
|
116 | 149 | ########################################################################### |
|
117 | 150 | |
|
118 | #----------------------------------------------------------------------------- | |
|
151 | # Classes and functions | |
|
152 | ||
|
153 | def is_extension_module(filename): | |
|
154 | """Return whether the given filename is an extension module. | |
|
155 | ||
|
156 | This simply checks that the extension is either .so or .pyd. | |
|
157 | """ | |
|
158 | return os.path.splitext(filename)[1].lower() in ('.so','.pyd') | |
|
159 | ||
|
160 | ||
|
161 | class nodoc(object): | |
|
162 | def __init__(self,obj): | |
|
163 | self.obj = obj | |
|
164 | ||
|
165 | def __getattribute__(self,key): | |
|
166 | if key == '__doc__': | |
|
167 | return None | |
|
168 | else: | |
|
169 | return getattr(object.__getattribute__(self,'obj'),key) | |
|
170 | ||
|
119 | 171 | # Modified version of the one in the stdlib, that fixes a python bug (doctests |
|
120 | 172 | # not found in extension modules, http://bugs.python.org/issue3158) |
|
121 | 173 | class DocTestFinder(doctest.DocTestFinder): |
@@ -126,45 +178,38 b' class DocTestFinder(doctest.DocTestFinder):' | |||
|
126 | 178 | module. |
|
127 | 179 | """ |
|
128 | 180 | if module is None: |
|
129 | #print '_fm C1' # dbg | |
|
130 | 181 | return True |
|
131 | 182 | elif inspect.isfunction(object): |
|
132 | #print '_fm C2' # dbg | |
|
133 | 183 | return module.__dict__ is object.func_globals |
|
134 | 184 | elif inspect.isbuiltin(object): |
|
135 | #print '_fm C2-1' # dbg | |
|
136 | 185 | return module.__name__ == object.__module__ |
|
137 | 186 | elif inspect.isclass(object): |
|
138 | #print '_fm C3' # dbg | |
|
139 | 187 | return module.__name__ == object.__module__ |
|
140 | 188 | elif inspect.ismethod(object): |
|
141 | 189 | # This one may be a bug in cython that fails to correctly set the |
|
142 | 190 | # __module__ attribute of methods, but since the same error is easy |
|
143 | 191 | # to make by extension code writers, having this safety in place |
|
144 | 192 | # isn't such a bad idea |
|
145 | #print '_fm C3-1' # dbg | |
|
146 | 193 | return module.__name__ == object.im_class.__module__ |
|
147 | 194 | elif inspect.getmodule(object) is not None: |
|
148 | #print '_fm C4' # dbg | |
|
149 | #print 'C4 mod',module,'obj',object # dbg | |
|
150 | 195 | return module is inspect.getmodule(object) |
|
151 | 196 | elif hasattr(object, '__module__'): |
|
152 | #print '_fm C5' # dbg | |
|
153 | 197 | return module.__name__ == object.__module__ |
|
154 | 198 | elif isinstance(object, property): |
|
155 | #print '_fm C6' # dbg | |
|
156 | 199 | return True # [XX] no way not be sure. |
|
157 | 200 | else: |
|
158 | 201 | raise ValueError("object must be a class or function") |
|
159 | 202 | |
|
160 | ||
|
161 | ||
|
162 | 203 | def _find(self, tests, obj, name, module, source_lines, globs, seen): |
|
163 | 204 | """ |
|
164 | 205 | Find tests for the given object and any contained objects, and |
|
165 | 206 | add them to `tests`. |
|
166 | 207 | """ |
|
167 | 208 | |
|
209 | if hasattr(obj,"skip_doctest"): | |
|
210 | #print 'SKIPPING DOCTEST FOR:',obj # dbg | |
|
211 | obj = nodoc(obj) | |
|
212 | ||
|
168 | 213 | doctest.DocTestFinder._find(self,tests, obj, name, module, |
|
169 | 214 | source_lines, globs, seen) |
|
170 | 215 | |
@@ -185,13 +230,10 b' class DocTestFinder(doctest.DocTestFinder):' | |||
|
185 | 230 | self._find(tests, val, valname1, module, source_lines, |
|
186 | 231 | globs, seen) |
|
187 | 232 | |
|
188 | ||
|
189 | 233 | # Look for tests in a class's contained objects. |
|
190 | 234 | if inspect.isclass(obj) and self._recurse: |
|
191 | 235 | #print 'RECURSE into class:',obj # dbg |
|
192 | 236 | for valname, val in obj.__dict__.items(): |
|
193 | #valname1 = '%s.%s' % (name, valname) # dbg | |
|
194 | #print 'N',name,'VN:',valname,'val:',str(val)[:77] # dbg | |
|
195 | 237 | # Special handling for staticmethod/classmethod. |
|
196 | 238 | if isinstance(val, staticmethod): |
|
197 | 239 | val = getattr(obj, valname) |
@@ -208,6 +250,32 b' class DocTestFinder(doctest.DocTestFinder):' | |||
|
208 | 250 | globs, seen) |
|
209 | 251 | |
|
210 | 252 | |
|
253 | class IPDoctestOutputChecker(doctest.OutputChecker): | |
|
254 | """Second-chance checker with support for random tests. | |
|
255 | ||
|
256 | If the default comparison doesn't pass, this checker looks in the expected | |
|
257 | output string for flags that tell us to ignore the output. | |
|
258 | """ | |
|
259 | ||
|
260 | random_re = re.compile(r'#\s*random') | |
|
261 | ||
|
262 | def check_output(self, want, got, optionflags): | |
|
263 | """Check output, accepting special markers embedded in the output. | |
|
264 | ||
|
265 | If the output didn't pass the default validation but the special string | |
|
266 | '#random' is included, we accept it.""" | |
|
267 | ||
|
268 | # Let the original tester verify first, in case people have valid tests | |
|
269 | # that happen to have a comment saying '#random' embedded in. | |
|
270 | ret = doctest.OutputChecker.check_output(self, want, got, | |
|
271 | optionflags) | |
|
272 | if not ret and self.random_re.search(want): | |
|
273 | #print >> sys.stderr, 'RANDOM OK:',want # dbg | |
|
274 | return True | |
|
275 | ||
|
276 | return ret | |
|
277 | ||
|
278 | ||
|
211 | 279 | class DocTestCase(doctests.DocTestCase): |
|
212 | 280 | """Proxy for DocTestCase: provides an address() method that |
|
213 | 281 | returns the correct address for the doctest case. Otherwise |
@@ -216,33 +284,70 b' class DocTestCase(doctests.DocTestCase):' | |||
|
216 | 284 | for purposes of determining the test address, if it is provided. |
|
217 | 285 | """ |
|
218 | 286 | |
|
219 | # doctests loaded via find(obj) omit the module name | |
|
220 | # so we need to override id, __repr__ and shortDescription | |
|
221 | # bonus: this will squash a 2.3 vs 2.4 incompatiblity | |
|
222 | def id(self): | |
|
223 | name = self._dt_test.name | |
|
224 | filename = self._dt_test.filename | |
|
225 | if filename is not None: | |
|
226 | pk = getpackage(filename) | |
|
227 | if pk is not None and not name.startswith(pk): | |
|
228 | name = "%s.%s" % (pk, name) | |
|
229 | return name | |
|
230 | ||
|
231 | ||
|
232 | # Classes and functions | |
|
287 | # Note: this method was taken from numpy's nosetester module. | |
|
288 | ||
|
289 | # Subclass nose.plugins.doctests.DocTestCase to work around a bug in | |
|
290 | # its constructor that blocks non-default arguments from being passed | |
|
291 | # down into doctest.DocTestCase | |
|
292 | ||
|
293 | def __init__(self, test, optionflags=0, setUp=None, tearDown=None, | |
|
294 | checker=None, obj=None, result_var='_'): | |
|
295 | self._result_var = result_var | |
|
296 | doctests.DocTestCase.__init__(self, test, | |
|
297 | optionflags=optionflags, | |
|
298 | setUp=setUp, tearDown=tearDown, | |
|
299 | checker=checker) | |
|
300 | # Now we must actually copy the original constructor from the stdlib | |
|
301 | # doctest class, because we can't call it directly and a bug in nose | |
|
302 | # means it never gets passed the right arguments. | |
|
303 | ||
|
304 | self._dt_optionflags = optionflags | |
|
305 | self._dt_checker = checker | |
|
306 | self._dt_test = test | |
|
307 | self._dt_setUp = setUp | |
|
308 | self._dt_tearDown = tearDown | |
|
309 | ||
|
310 | # Each doctest should remember what directory it was loaded from... | |
|
311 | self._ori_dir = os.getcwd() | |
|
312 | ||
|
313 | # Modified runTest from the default stdlib | |
|
314 | def runTest(self): | |
|
315 | test = self._dt_test | |
|
316 | old = sys.stdout | |
|
317 | new = StringIO() | |
|
318 | optionflags = self._dt_optionflags | |
|
319 | ||
|
320 | if not (optionflags & REPORTING_FLAGS): | |
|
321 | # The option flags don't include any reporting flags, | |
|
322 | # so add the default reporting flags | |
|
323 | optionflags |= _unittest_reportflags | |
|
324 | ||
|
325 | runner = IPDocTestRunner(optionflags=optionflags, | |
|
326 | checker=self._dt_checker, verbose=False) | |
|
233 | 327 | |
|
234 | def is_extension_module(filename): | |
|
235 | """Return whether the given filename is an extension module. | |
|
328 | try: | |
|
329 | # Save our current directory and switch out to the one where the | |
|
330 | # test was originally created, in case another doctest did a | |
|
331 | # directory change. We'll restore this in the finally clause. | |
|
332 | curdir = os.getcwd() | |
|
333 | os.chdir(self._ori_dir) | |
|
334 | ||
|
335 | runner.DIVIDER = "-"*70 | |
|
336 | failures, tries = runner.run( | |
|
337 | test, out=new.write, clear_globs=False) | |
|
338 | finally: | |
|
339 | sys.stdout = old | |
|
340 | os.chdir(curdir) | |
|
236 | 341 | |
|
237 | This simply checks that the extension is either .so or .pyd. | |
|
238 | """ | |
|
239 | return os.path.splitext(filename)[1].lower() in ('.so','.pyd') | |
|
342 | if failures: | |
|
343 | raise self.failureException(self.format_failure(new.getvalue())) | |
|
240 | 344 | |
|
241 | 345 | |
|
242 | 346 | # A simple subclassing of the original with a different class name, so we can |
|
243 | 347 | # distinguish and treat differently IPython examples from pure python ones. |
|
244 | 348 | class IPExample(doctest.Example): pass |
|
245 | 349 | |
|
350 | ||
|
246 | 351 | class IPExternalExample(doctest.Example): |
|
247 | 352 | """Doctest examples to be run in an external process.""" |
|
248 | 353 | |
@@ -254,6 +359,7 b' class IPExternalExample(doctest.Example):' | |||
|
254 | 359 | # An EXTRA newline is needed to prevent pexpect hangs |
|
255 | 360 | self.source += '\n' |
|
256 | 361 | |
|
362 | ||
|
257 | 363 | class IPDocTestParser(doctest.DocTestParser): |
|
258 | 364 | """ |
|
259 | 365 | A class used to parse strings containing doctest examples. |
@@ -294,14 +400,22 b' class IPDocTestParser(doctest.DocTestParser):' | |||
|
294 | 400 | _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP), |
|
295 | 401 | re.MULTILINE | re.VERBOSE) |
|
296 | 402 | |
|
403 | # Mark a test as being fully random. In this case, we simply append the | |
|
404 | # random marker ('#random') to each individual example's output. This way | |
|
405 | # we don't need to modify any other code. | |
|
406 | _RANDOM_TEST = re.compile(r'#\s*all-random') | |
|
407 | ||
|
408 | # Mark tests to be executed in an external process - currently unsupported. | |
|
409 | _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL') | |
|
410 | ||
|
297 | 411 | def ip2py(self,source): |
|
298 | 412 | """Convert input IPython source into valid Python.""" |
|
299 | 413 | out = [] |
|
300 | 414 | newline = out.append |
|
301 | for line in source.splitlines(): | |
|
302 |
|
|
|
303 | newline(_ip.IP.prefilter(line,True)) | |
|
415 | for lnum,line in enumerate(source.splitlines()): | |
|
416 | newline(_ip.IP.prefilter(line,lnum>0)) | |
|
304 | 417 | newline('') # ensure a closing newline, needed by doctest |
|
418 | #print "PYSRC:", '\n'.join(out) # dbg | |
|
305 | 419 | return '\n'.join(out) |
|
306 | 420 | |
|
307 | 421 | def parse(self, string, name='<string>'): |
@@ -324,6 +438,11 b' class IPDocTestParser(doctest.DocTestParser):' | |||
|
324 | 438 | output = [] |
|
325 | 439 | charno, lineno = 0, 0 |
|
326 | 440 | |
|
441 | if self._RANDOM_TEST.search(string): | |
|
442 | random_marker = '\n# random' | |
|
443 | else: | |
|
444 | random_marker = '' | |
|
445 | ||
|
327 | 446 | # Whether to convert the input from ipython to python syntax |
|
328 | 447 | ip2py = False |
|
329 | 448 | # Find all doctest examples in the string. First, try them as Python |
@@ -341,7 +460,7 b' class IPDocTestParser(doctest.DocTestParser):' | |||
|
341 | 460 | # IPExternalExamples are run out-of-process (via pexpect) so they |
|
342 | 461 | # don't need any filtering (a real ipython will be executing them). |
|
343 | 462 | terms = list(self._EXAMPLE_RE_IP.finditer(string)) |
|
344 | if re.search(r'#\s*ipdoctest:\s*EXTERNAL',string): | |
|
463 | if self._EXTERNAL_IP.search(string): | |
|
345 | 464 | #print '-'*70 # dbg |
|
346 | 465 | #print 'IPExternalExample, Source:\n',string # dbg |
|
347 | 466 | #print '-'*70 # dbg |
@@ -361,12 +480,17 b' class IPDocTestParser(doctest.DocTestParser):' | |||
|
361 | 480 | # Extract info from the regexp match. |
|
362 | 481 | (source, options, want, exc_msg) = \ |
|
363 | 482 | self._parse_example(m, name, lineno,ip2py) |
|
483 | ||
|
484 | # Append the random-output marker (it defaults to empty in most | |
|
485 | # cases, it's only non-empty for 'all-random' tests): | |
|
486 | want += random_marker | |
|
487 | ||
|
364 | 488 | if Example is IPExternalExample: |
|
365 | 489 | options[doctest.NORMALIZE_WHITESPACE] = True |
|
366 | 490 | want += '\n' |
|
491 | ||
|
367 | 492 | # Create an Example, and add it to the list. |
|
368 | 493 | if not self._IS_BLANK_OR_COMMENT(source): |
|
369 | #print 'Example source:', source # dbg | |
|
370 | 494 | output.append(Example(source, want, exc_msg, |
|
371 | 495 | lineno=lineno, |
|
372 | 496 | indent=min_indent+len(m.group('indent')), |
@@ -377,7 +501,6 b' class IPDocTestParser(doctest.DocTestParser):' | |||
|
377 | 501 | charno = m.end() |
|
378 | 502 | # Add any remaining post-example text to `output`. |
|
379 | 503 | output.append(string[charno:]) |
|
380 | ||
|
381 | 504 | return output |
|
382 | 505 | |
|
383 | 506 | def _parse_example(self, m, name, lineno,ip2py=False): |
@@ -464,9 +587,33 b' class IPDocTestParser(doctest.DocTestParser):' | |||
|
464 | 587 | (lineno+i+1, name, |
|
465 | 588 | line[indent:space_idx], line)) |
|
466 | 589 | |
|
590 | ||
|
467 | 591 | SKIP = doctest.register_optionflag('SKIP') |
|
468 | 592 | |
|
469 | ########################################################################### | |
|
593 | ||
|
594 | class IPDocTestRunner(doctest.DocTestRunner,object): | |
|
595 | """Test runner that synchronizes the IPython namespace with test globals. | |
|
596 | """ | |
|
597 | ||
|
598 | def run(self, test, compileflags=None, out=None, clear_globs=True): | |
|
599 | ||
|
600 | # Hack: ipython needs access to the execution context of the example, | |
|
601 | # so that it can propagate user variables loaded by %run into | |
|
602 | # test.globs. We put them here into our modified %run as a function | |
|
603 | # attribute. Our new %run will then only make the namespace update | |
|
604 | # when called (rather than unconconditionally updating test.globs here | |
|
605 | # for all examples, most of which won't be calling %run anyway). | |
|
606 | _run_ns_sync.test_globs = test.globs | |
|
607 | ||
|
608 | # dbg | |
|
609 | ## print >> sys.stderr, "Test:",test | |
|
610 | ## for ex in test.examples: | |
|
611 | ## print >> sys.stderr, ex.source | |
|
612 | ## print >> sys.stderr, 'Want:\n',ex.want,'\n--' | |
|
613 | ||
|
614 | return super(IPDocTestRunner,self).run(test, | |
|
615 | compileflags,out,clear_globs) | |
|
616 | ||
|
470 | 617 | |
|
471 | 618 | class DocFileCase(doctest.DocFileCase): |
|
472 | 619 | """Overrides to provide filename |
@@ -490,7 +637,8 b' class ExtensionDoctest(doctests.Doctest):' | |||
|
490 | 637 | self.extension = tolist(options.doctestExtension) |
|
491 | 638 | self.finder = DocTestFinder() |
|
492 | 639 | self.parser = doctest.DocTestParser() |
|
493 | ||
|
640 | self.globs = None | |
|
641 | self.extraglobs = None | |
|
494 | 642 | |
|
495 | 643 | def loadTestsFromExtensionModule(self,filename): |
|
496 | 644 | bpath,mod = os.path.split(filename) |
@@ -503,17 +651,48 b' class ExtensionDoctest(doctests.Doctest):' | |||
|
503 | 651 | sys.path.pop() |
|
504 | 652 | return tests |
|
505 | 653 | |
|
654 | # NOTE: the method below is almost a copy of the original one in nose, with | |
|
655 | # a few modifications to control output checking. | |
|
656 | ||
|
657 | def loadTestsFromModule(self, module): | |
|
658 | #print 'lTM',module # dbg | |
|
659 | ||
|
660 | if not self.matches(module.__name__): | |
|
661 | log.debug("Doctest doesn't want module %s", module) | |
|
662 | return | |
|
663 | ||
|
664 | tests = self.finder.find(module,globs=self.globs, | |
|
665 | extraglobs=self.extraglobs) | |
|
666 | if not tests: | |
|
667 | return | |
|
668 | ||
|
669 | tests.sort() | |
|
670 | module_file = module.__file__ | |
|
671 | if module_file[-4:] in ('.pyc', '.pyo'): | |
|
672 | module_file = module_file[:-1] | |
|
673 | for test in tests: | |
|
674 | if not test.examples: | |
|
675 | continue | |
|
676 | if not test.filename: | |
|
677 | test.filename = module_file | |
|
678 | ||
|
679 | # xxx - checker and options may be ok instantiated once outside loop | |
|
680 | # always use whitespace and ellipsis options | |
|
681 | optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS | |
|
682 | checker = IPDoctestOutputChecker() | |
|
683 | ||
|
684 | yield DocTestCase(test, | |
|
685 | optionflags=optionflags, | |
|
686 | checker=checker) | |
|
687 | ||
|
506 | 688 | def loadTestsFromFile(self, filename): |
|
689 | #print 'lTF',filename # dbg | |
|
690 | ||
|
507 | 691 | if is_extension_module(filename): |
|
508 | 692 | for t in self.loadTestsFromExtensionModule(filename): |
|
509 | 693 | yield t |
|
510 | 694 | else: |
|
511 | ## for t in list(doctests.Doctest.loadTestsFromFile(self,filename)): | |
|
512 | ## yield t | |
|
513 | pass | |
|
514 | ||
|
515 | 695 | if self.extension and anyp(filename.endswith, self.extension): |
|
516 | #print 'lTF',filename # dbg | |
|
517 | 696 | name = os.path.basename(filename) |
|
518 | 697 | dh = open(filename) |
|
519 | 698 | try: |
@@ -529,7 +708,6 b' class ExtensionDoctest(doctests.Doctest):' | |||
|
529 | 708 | else: |
|
530 | 709 | yield False # no tests to load |
|
531 | 710 | |
|
532 | ||
|
533 | 711 | def wantFile(self,filename): |
|
534 | 712 | """Return whether the given filename should be scanned for tests. |
|
535 | 713 | |
@@ -538,38 +716,25 b' class ExtensionDoctest(doctests.Doctest):' | |||
|
538 | 716 | """ |
|
539 | 717 | #print 'Filename:',filename # dbg |
|
540 | 718 | |
|
719 | # temporarily hardcoded list, will move to driver later | |
|
720 | exclude = ['IPython/external/', | |
|
721 | 'IPython/Extensions/ipy_', | |
|
722 | 'IPython/platutils_win32', | |
|
723 | 'IPython/frontend/cocoa', | |
|
724 | 'IPython_doctest_plugin', | |
|
725 | 'IPython/Gnuplot', | |
|
726 | 'IPython/Extensions/PhysicalQIn'] | |
|
727 | ||
|
728 | for fex in exclude: | |
|
729 | if fex in filename: # substring | |
|
730 | #print '###>>> SKIP:',filename # dbg | |
|
731 | return False | |
|
732 | ||
|
541 | 733 | if is_extension_module(filename): |
|
542 | 734 | return True |
|
543 | 735 | else: |
|
544 | 736 | return doctests.Doctest.wantFile(self,filename) |
|
545 | 737 | |
|
546 | # NOTE: the method below is a *copy* of the one in the nose doctests | |
|
547 | # plugin, but we have to replicate it here in order to have it resolve the | |
|
548 | # DocTestCase (last line) to our local copy, since the nose plugin doesn't | |
|
549 | # provide a public hook for what TestCase class to use. The alternative | |
|
550 | # would be to monkeypatch doctest in the stdlib, but that's ugly and | |
|
551 | # brittle, since a change in plugin load order can break it. So for now, | |
|
552 | # we just paste this in here, inelegant as this may be. | |
|
553 | ||
|
554 | def loadTestsFromModule(self, module): | |
|
555 | #print 'lTM',module # dbg | |
|
556 | ||
|
557 | if not self.matches(module.__name__): | |
|
558 | log.debug("Doctest doesn't want module %s", module) | |
|
559 | return | |
|
560 | tests = self.finder.find(module) | |
|
561 | if not tests: | |
|
562 | return | |
|
563 | tests.sort() | |
|
564 | module_file = module.__file__ | |
|
565 | if module_file[-4:] in ('.pyc', '.pyo'): | |
|
566 | module_file = module_file[:-1] | |
|
567 | for test in tests: | |
|
568 | if not test.examples: | |
|
569 | continue | |
|
570 | if not test.filename: | |
|
571 | test.filename = module_file | |
|
572 | yield DocTestCase(test) | |
|
573 | 738 | |
|
574 | 739 | class IPythonDoctest(ExtensionDoctest): |
|
575 | 740 | """Nose Plugin that supports doctests in extension modules. |
@@ -583,5 +748,6 b' class IPythonDoctest(ExtensionDoctest):' | |||
|
583 | 748 | self.doctest_tests = options.doctest_tests |
|
584 | 749 | self.extension = tolist(options.doctestExtension) |
|
585 | 750 | self.parser = IPDocTestParser() |
|
586 | #self.finder = DocTestFinder(parser=IPDocTestParser()) | |
|
587 | 751 | self.finder = DocTestFinder(parser=self.parser) |
|
752 | self.globs = None | |
|
753 | self.extraglobs = None |
@@ -53,7 +53,7 b' class DistributedSpider(object):' | |||
|
53 | 53 | self.allLinks.append(url) |
|
54 | 54 | if url.startswith(self.site): |
|
55 | 55 | print ' ', url |
|
56 | self.linksWorking[url] = self.tc.run(client.Task('links = fetchAndParse(url)', pull=['links'], push={'url': url})) | |
|
56 | self.linksWorking[url] = self.tc.run(client.StringTask('links = fetchAndParse(url)', pull=['links'], push={'url': url})) | |
|
57 | 57 | |
|
58 | 58 | def onVisitDone(self, result, url): |
|
59 | 59 | print url, ':' |
@@ -8,7 +8,7 b' tc = client.TaskClient()' | |||
|
8 | 8 | mec = client.MultiEngineClient() |
|
9 | 9 | |
|
10 | 10 | mec.execute('import time') |
|
11 | hello_taskid = tc.run(client.Task('time.sleep(3) ; word = "Hello,"', pull=('word'))) | |
|
12 | world_taskid = tc.run(client.Task('time.sleep(3) ; word = "World!"', pull=('word'))) | |
|
11 | hello_taskid = tc.run(client.StringTask('time.sleep(3) ; word = "Hello,"', pull=('word'))) | |
|
12 | world_taskid = tc.run(client.StringTask('time.sleep(3) ; word = "World!"', pull=('word'))) | |
|
13 | 13 | print "Submitted tasks:", hello_taskid, world_taskid |
|
14 | 14 | print tc.get_task_result(hello_taskid,block=True).ns.word, tc.get_task_result(world_taskid,block=True).ns.word |
@@ -31,7 +31,7 b' sigma_vals = N.linspace(0.0, 0.2,5)' | |||
|
31 | 31 | taskids = [] |
|
32 | 32 | for K in K_vals: |
|
33 | 33 | for sigma in sigma_vals: |
|
34 | t = client.Task(task_string, | |
|
34 | t = client.StringTask(task_string, | |
|
35 | 35 | push=dict(sigma=sigma,K=K), |
|
36 | 36 | pull=('vp','ap','vc','ac','sigma','K')) |
|
37 | 37 | taskids.append(tc.run(t)) |
@@ -11,8 +11,8 b' b = 10*d' | |||
|
11 | 11 | c = a*b*d |
|
12 | 12 | """ |
|
13 | 13 | |
|
14 | t1 = client.Task(cmd1, clear_before=False, clear_after=True, pull=['a','b','c']) | |
|
14 | t1 = client.StringTask(cmd1, clear_before=False, clear_after=True, pull=['a','b','c']) | |
|
15 | 15 | tid1 = tc.run(t1) |
|
16 | 16 | tr1 = tc.get_task_result(tid1,block=True) |
|
17 |
tr1.raise |
|
|
17 | tr1.raise_exception() | |
|
18 | 18 | print "a, b: ", tr1.ns.a, tr1.ns.b No newline at end of file |
@@ -10,7 +10,7 b' mec = client.MultiEngineClient()' | |||
|
10 | 10 | mec.execute('import time') |
|
11 | 11 | |
|
12 | 12 | for i in range(24): |
|
13 |
tc. |
|
|
13 | tc.run(client.StringTask('time.sleep(1)')) | |
|
14 | 14 | |
|
15 | 15 | for i in range(6): |
|
16 | 16 | time.sleep(1.0) |
@@ -18,7 +18,7 b' for i in range(6):' | |||
|
18 | 18 | print tc.queue_status() |
|
19 | 19 | |
|
20 | 20 | for i in range(24): |
|
21 |
tc. |
|
|
21 | tc.run(client.StringTask('time.sleep(1)')) | |
|
22 | 22 | |
|
23 | 23 | for i in range(6): |
|
24 | 24 | time.sleep(1.0) |
@@ -26,7 +26,7 b' for i in range(6):' | |||
|
26 | 26 | print tc.queue_status(True) |
|
27 | 27 | |
|
28 | 28 | for i in range(12): |
|
29 |
tc. |
|
|
29 | tc.run(client.StringTask('time.sleep(2)')) | |
|
30 | 30 | |
|
31 | 31 | print "Queue status (vebose=True)" |
|
32 | 32 | print tc.queue_status(True) |
@@ -55,7 +55,7 b' def main():' | |||
|
55 | 55 | |
|
56 | 56 | # the jobs should take a random time within a range |
|
57 | 57 | times = [random.random()*(opts.tmax-opts.tmin)+opts.tmin for i in range(opts.n)] |
|
58 | tasks = [client.Task("time.sleep(%f)"%t) for t in times] | |
|
58 | tasks = [client.StringTask("time.sleep(%f)"%t) for t in times] | |
|
59 | 59 | stime = sum(times) |
|
60 | 60 | |
|
61 | 61 | print "executing %i tasks, totalling %.1f secs on %i engines"%(opts.n, stime, nengines) |
@@ -12,6 +12,22 b' Release 0.9' | |||
|
12 | 12 | New features |
|
13 | 13 | ------------ |
|
14 | 14 | |
|
15 | * The notion of a task has been completely reworked. An `ITask` interface has | |
|
16 | been created. This interface defines the methods that tasks need to implement. | |
|
17 | These methods are now responsible for things like submitting tasks and processing | |
|
18 | results. There are two basic task types: :class:`IPython.kernel.task.StringTask` | |
|
19 | (this is the old `Task` object, but renamed) and the new | |
|
20 | :class:`IPython.kernel.task.MapTask`, which is based on a function. | |
|
21 | * A new interface, :class:`IPython.kernel.mapper.IMapper` has been defined to | |
|
22 | standardize the idea of a `map` method. This interface has a single | |
|
23 | `map` method that has the same syntax as the built-in `map`. We have also defined | |
|
24 | a `mapper` factory interface that creates objects that implement | |
|
25 | :class:`IPython.kernel.mapper.IMapper` for different controllers. Both | |
|
26 | the multiengine and task controller now have mapping capabilties. | |
|
27 | * The parallel function capabilities have been reworks. The major changes are that | |
|
28 | i) there is now an `@parallel` magic that creates parallel functions, ii) | |
|
29 | the syntax for mulitple variable follows that of `map`, iii) both the | |
|
30 | multiengine and task controller now have a parallel function implementation. | |
|
15 | 31 | * All of the parallel computing capabilities from `ipython1-dev` have been merged into |
|
16 | 32 | IPython proper. This resulted in the following new subpackages: |
|
17 | 33 | :mod:`IPython.kernel`, :mod:`IPython.kernel.core`, :mod:`IPython.config`, |
@@ -38,11 +54,11 b' New features' | |||
|
38 | 54 | when ipcluster is able to start things on other hosts, we will put security |
|
39 | 55 | back. |
|
40 | 56 | |
|
41 | ||
|
42 | ||
|
43 | 57 | Bug fixes |
|
44 | 58 | --------- |
|
45 | 59 | |
|
60 | * The colors escapes in the multiengine client are now turned off on win32 as they | |
|
61 | don't print correctly. | |
|
46 | 62 | * The :mod:`IPython.kernel.scripts.ipengine` script was exec'ing mpi_import_statement |
|
47 | 63 | incorrectly, which was leading the engine to crash when mpi was enabled. |
|
48 | 64 | * A few subpackages has missing `__init__.py` files. |
@@ -52,6 +68,12 b' Bug fixes' | |||
|
52 | 68 | Backwards incompatible changes |
|
53 | 69 | ------------------------------ |
|
54 | 70 | |
|
71 | * :class:`IPython.kernel.client.Task` has been renamed | |
|
72 | :class:`IPython.kernel.client.StringTask` to make way for new task types. | |
|
73 | * The keyword argument `style` has been renamed `dist` in `scatter`, `gather` | |
|
74 | and `map`. | |
|
75 | * Renamed the values that the rename `dist` keyword argument can have from | |
|
76 | `'basic'` to `'b'`. | |
|
55 | 77 | * IPython has a larger set of dependencies if you want all of its capabilities. |
|
56 | 78 | See the `setup.py` script for details. |
|
57 | 79 | * The constructors for :class:`IPython.kernel.client.MultiEngineClient` and |
@@ -1,3 +1,5 b'' | |||
|
1 | .. _install_index: | |
|
2 | ||
|
1 | 3 | ================== |
|
2 | 4 | Installation |
|
3 | 5 | ================== |
@@ -4,18 +4,6 b'' | |||
|
4 | 4 | Introduction |
|
5 | 5 | ============ |
|
6 | 6 | |
|
7 | This is the official documentation for IPython 0.x series (i.e. what | |
|
8 | we are used to refer to just as "IPython"). The original text of the | |
|
9 | manual (most of which is still in place) has been authored by Fernando | |
|
10 | Perez, but as recommended usage patterns and new features have | |
|
11 | emerged, this manual has been updated to reflect that fact. Most of | |
|
12 | the additions have been authored by Ville M. Vainio. | |
|
13 | ||
|
14 | The manual has been generated from reStructuredText source markup with | |
|
15 | Sphinx, which should make it much easier to keep it up-to-date in the | |
|
16 | future. Some reST artifacts and bugs may still be apparent in the | |
|
17 | documentation, but this should improve as the toolchain matures. | |
|
18 | ||
|
19 | 7 | Overview |
|
20 | 8 | ======== |
|
21 | 9 | |
@@ -25,8 +13,19 b' creating test files as is typical in most programming languages.' | |||
|
25 | 13 | However, the interpreter supplied with the standard Python distribution |
|
26 | 14 | is somewhat limited for extended interactive use. |
|
27 | 15 | |
|
28 | IPython is a free software project (released under the BSD license) | |
|
29 | which tries to: | |
|
16 | The goal of IPython is to create a comprehensive environment for | |
|
17 | interactive and exploratory computing. To support, this goal, IPython | |
|
18 | has two main components: | |
|
19 | ||
|
20 | * An enhanced interactive Python shell. | |
|
21 | * An architecture for interactive parallel computing. | |
|
22 | ||
|
23 | All of IPython is open source (released under the revised BSD license). | |
|
24 | ||
|
25 | Enhanced interactive Python shell | |
|
26 | ================================= | |
|
27 | ||
|
28 | IPython's interactive shell (`ipython`), has the following goals: | |
|
30 | 29 | |
|
31 | 30 | 1. Provide an interactive shell superior to Python's default. IPython |
|
32 | 31 | has many features for object introspection, system shell access, |
@@ -50,17 +49,16 b' which tries to:' | |||
|
50 | 49 | WX applications via special threading flags. The normal Python |
|
51 | 50 | shell can only do this for Tkinter applications. |
|
52 | 51 | |
|
53 | ||
|
54 | Main features | |
|
55 | ------------- | |
|
52 | Main features of the interactive shell | |
|
53 | -------------------------------------- | |
|
56 | 54 | |
|
57 | 55 | * Dynamic object introspection. One can access docstrings, function |
|
58 | 56 | definition prototypes, source code, source files and other details |
|
59 | 57 | of any object accessible to the interpreter with a single |
|
60 |
keystroke ( |
|
|
61 |
* Searching through modules and namespaces with |
|
|
62 |
when using the |
|
|
63 | * Completion in the local namespace, by typing TAB at the prompt. | |
|
58 | keystroke (:samp:`?`, and using :samp:`??` provides additional detail). | |
|
59 | * Searching through modules and namespaces with :samp:`*` wildcards, both | |
|
60 | when using the :samp:`?` system and via the :samp:`%psearch` command. | |
|
61 | * Completion in the local namespace, by typing :kbd:`TAB` at the prompt. | |
|
64 | 62 | This works for keywords, modules, methods, variables and files in the |
|
65 | 63 | current directory. This is supported via the readline library, and |
|
66 | 64 | full access to configuring readline's behavior is provided. |
@@ -70,31 +68,31 b' Main features' | |||
|
70 | 68 | across sessions and tied to each profile), full searching in this |
|
71 | 69 | history and caching of all input and output. |
|
72 | 70 | * User-extensible 'magic' commands. A set of commands prefixed with |
|
73 | % is available for controlling IPython itself and provides | |
|
71 | :samp:`%` is available for controlling IPython itself and provides | |
|
74 | 72 | directory control, namespace information and many aliases to |
|
75 | 73 | common system shell commands. |
|
76 | 74 | * Alias facility for defining your own system aliases. |
|
77 | * Complete system shell access. Lines starting with ! are passed | |
|
78 | directly to the system shell, and using !! or var = !cmd | |
|
75 | * Complete system shell access. Lines starting with :samp:`!` are passed | |
|
76 | directly to the system shell, and using :samp:`!!` or :samp:`var = !cmd` | |
|
79 | 77 | captures shell output into python variables for further use. |
|
80 | 78 | * Background execution of Python commands in a separate thread. |
|
81 | 79 | IPython has an internal job manager called jobs, and a |
|
82 | conveninence backgrounding magic function called %bg. | |
|
80 | conveninence backgrounding magic function called :samp:`%bg`. | |
|
83 | 81 | * The ability to expand python variables when calling the system |
|
84 | shell. In a shell command, any python variable prefixed with $ is | |
|
85 | expanded. A double $$ allows passing a literal $ to the shell (for | |
|
86 |
access to shell and environment variables like |
|
|
87 | * Filesystem navigation, via a magic %cd command, along with a | |
|
88 | persistent bookmark system (using %bookmark) for fast access to | |
|
82 | shell. In a shell command, any python variable prefixed with :samp:`$` is | |
|
83 | expanded. A double :samp:`$$` allows passing a literal :samp:`$` to the shell (for | |
|
84 | access to shell and environment variables like :envvar:`PATH`). | |
|
85 | * Filesystem navigation, via a magic :samp:`%cd` command, along with a | |
|
86 | persistent bookmark system (using :samp:`%bookmark`) for fast access to | |
|
89 | 87 | frequently visited directories. |
|
90 | * A lightweight persistence framework via the %store command, which | |
|
88 | * A lightweight persistence framework via the :samp:`%store` command, which | |
|
91 | 89 | allows you to save arbitrary Python variables. These get restored |
|
92 | 90 | automatically when your session restarts. |
|
93 | 91 | * Automatic indentation (optional) of code as you type (through the |
|
94 | 92 | readline library). |
|
95 | 93 | * Macro system for quickly re-executing multiple lines of previous |
|
96 | 94 | input with a single name. Macros can be stored persistently via |
|
97 | %store and edited via %edit. | |
|
95 | :samp:`%store` and edited via :samp:`%edit`. | |
|
98 | 96 | * Session logging (you can then later use these logs as code in your |
|
99 | 97 | programs). Logs can optionally timestamp all input, and also store |
|
100 | 98 | session output (marked as comments, so the log remains valid |
@@ -106,15 +104,15 b' Main features' | |||
|
106 | 104 | debugging information (basically a terminal version of the cgitb |
|
107 | 105 | module). |
|
108 | 106 | * Auto-parentheses: callable objects can be executed without |
|
109 |
parentheses: |
|
|
110 |
* Auto-quoting: using |
|
|
111 |
auto-quoting of the rest of the line: |
|
|
112 |
automatically |
|
|
113 |
becomes |
|
|
107 | parentheses: :samp:`sin 3` is automatically converted to :samp:`sin(3)`. | |
|
108 | * Auto-quoting: using :samp:`,`, or :samp:`;` as the first character forces | |
|
109 | auto-quoting of the rest of the line: :samp:`,my_function a b` becomes | |
|
110 | automatically :samp:`my_function("a","b")`, while :samp:`;my_function a b` | |
|
111 | becomes :samp:`my_function("a b")`. | |
|
114 | 112 | * Extensible input syntax. You can define filters that pre-process |
|
115 | 113 | user input to simplify input in special situations. This allows |
|
116 | 114 | for example pasting multi-line code fragments which start with |
|
117 |
|
|
|
115 | :samp:`>>>` or :samp:`...` such as those from other python sessions or the | |
|
118 | 116 | standard Python documentation. |
|
119 | 117 | * Flexible configuration system. It uses a configuration file which |
|
120 | 118 | allows permanent setting of all command-line options, module |
@@ -131,59 +129,46 b' Main features' | |||
|
131 | 129 | uncaught exception. This drops you inside the code which triggered |
|
132 | 130 | the exception with all the data live and it is possible to |
|
133 | 131 | navigate the stack to rapidly isolate the source of a bug. The |
|
134 |
%run magic command |
|
|
132 | :samp:`%run` magic command (with the :samp:`-d` option) can run any script under | |
|
135 | 133 | pdb's control, automatically setting initial breakpoints for you. |
|
136 | 134 | This version of pdb has IPython-specific improvements, including |
|
137 | 135 | tab-completion and traceback coloring support. For even easier |
|
138 | debugger access, try %debug after seeing an exception. winpdb is | |
|
136 | debugger access, try :samp:`%debug` after seeing an exception. winpdb is | |
|
139 | 137 | also supported, see ipy_winpdb extension. |
|
140 | 138 | * Profiler support. You can run single statements (similar to |
|
141 | profile.run()) or complete programs under the profiler's control. | |
|
139 | :samp:`profile.run()`) or complete programs under the profiler's control. | |
|
142 | 140 | While this is possible with standard cProfile or profile modules, |
|
143 |
IPython wraps this functionality with magic commands (see |
|
|
144 |
and |
|
|
145 | * Doctest support. The special %doctest_mode command toggles a mode | |
|
146 |
that allows you to paste existing doctests (with leading |
|
|
141 | IPython wraps this functionality with magic commands (see :samp:`%prun` | |
|
142 | and :samp:`%run -p`) convenient for rapid interactive work. | |
|
143 | * Doctest support. The special :samp:`%doctest_mode` command toggles a mode | |
|
144 | that allows you to paste existing doctests (with leading :samp:`>>>` | |
|
147 | 145 | prompts and whitespace) and uses doctest-compatible prompts and |
|
148 | 146 | output, so you can use IPython sessions as doctest code. |
|
149 | 147 | |
|
148 | Interactive parallel computing | |
|
149 | ============================== | |
|
150 | ||
|
151 | Increasingly, parallel computer hardware, such as multicore CPUs, clusters and supercomputers, is becoming ubiquitous. Over the last 3 years, we have developed an | |
|
152 | architecture within IPython that allows such hardware to be used quickly and easily | |
|
153 | from Python. Moreover, this architecture is designed to support interactive and | |
|
154 | collaborative parallel computing. | |
|
155 | ||
|
156 | For more information, see our :ref:`overview <parallel_index>` of using IPython for | |
|
157 | parallel computing. | |
|
150 | 158 | |
|
151 | 159 | Portability and Python requirements |
|
152 | 160 | ----------------------------------- |
|
153 | 161 | |
|
154 | Python requirements: IPython requires with Python version 2.3 or newer. | |
|
155 | If you are still using Python 2.2 and can not upgrade, the last version | |
|
156 | of IPython which worked with Python 2.2 was 0.6.15, so you will have to | |
|
157 | use that. | |
|
158 | ||
|
159 | IPython is developed under Linux, but it should work in any reasonable | |
|
160 | Unix-type system (tested OK under Solaris and the BSD family, for which | |
|
161 | a port exists thanks to Dryice Liu). | |
|
162 | ||
|
163 | Mac OS X: it works, apparently without any problems (thanks to Jim Boyle | |
|
164 | at Lawrence Livermore for the information). Thanks to Andrea Riciputi, | |
|
165 | Fink support is available. | |
|
166 | ||
|
167 | CygWin: it works mostly OK, though some users have reported problems | |
|
168 | with prompt coloring. No satisfactory solution to this has been found so | |
|
169 | far, you may want to disable colors permanently in the ipythonrc | |
|
170 | configuration file if you experience problems. If you have proper color | |
|
171 | support under cygwin, please post to the IPython mailing list so this | |
|
172 | issue can be resolved for all users. | |
|
173 | ||
|
174 | Windows: it works well under Windows Vista/XP/2k, and I suspect NT should | |
|
175 | behave similarly. Section "Installation under windows" describes | |
|
176 | installation details for Windows, including some additional tools needed | |
|
177 | on this platform. | |
|
178 | ||
|
179 | Windows 9x support is present, and has been reported to work fine (at | |
|
180 | least on WinME). | |
|
181 | ||
|
182 | Location | |
|
183 | -------- | |
|
184 | ||
|
185 | IPython is generously hosted at http://ipython.scipy.org by the | |
|
186 | Enthought, Inc and the SciPy project. This site offers downloads, | |
|
187 | subversion access, mailing lists and a bug tracking system. I am very | |
|
188 | grateful to Enthought (http://www.enthought.com) and all of the SciPy | |
|
189 | team for their contribution. No newline at end of file | |
|
162 | As of the 0.9 release, IPython requires Python 2.4 or greater. We have | |
|
163 | not begun to test IPython on Python 2.6 or 3.0, but we expect it will | |
|
164 | work with some minor changes. | |
|
165 | ||
|
166 | IPython is known to work on the following operating systems: | |
|
167 | ||
|
168 | * Linux | |
|
169 | * AIX | |
|
170 | * Most other Unix-like OSs (Solaris, BSD, etc.) | |
|
171 | * Mac OS X | |
|
172 | * Windows (CygWin, XP, Vista, etc.) | |
|
173 | ||
|
174 | See :ref:`here <install_index>` for instructions on how to install IPython. No newline at end of file |
@@ -1,3 +1,5 b'' | |||
|
1 | .. _parallel_index: | |
|
2 | ||
|
1 | 3 | ==================================== |
|
2 | 4 | Using IPython for Parallel computing |
|
3 | 5 | ==================================== |
@@ -24,4 +24,5 b' are trapped first by Python itself.' | |||
|
24 | 24 | """ |
|
25 | 25 | |
|
26 | 26 | import IPython.Shell |
|
27 | ||
|
27 | 28 | IPython.Shell.start().mainloop() |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now