Ϫf|dZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z mZmZmZmZmZddlmZddlmZdd lmZmZmZdd lmZmZefZd Z d Z!d Z"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,ee ddddddddZ-ia.ia/dZ0dZ1d Z2d!Z3d"Z4d8d#Z5d$Z6d%Z7Gd&d'Z8e eGd(d)Z9e eGd*d+Z:Gd,d-Z;Gd.d/Z<Gd0d1e=Z>Gd2d3Z?Gd4d5Z@e@ZAeAje?ddfd6ZCe?ddfd7ZDy)9aM S-expression-based persistence of python objects. It does something very much like L{Pickle}; however, pickle's main goal seems to be efficiency (both in space and time); jelly's main goals are security, human readability, and portability to other environments. This is how Jelly converts various objects to s-expressions. Boolean:: True --> ['boolean', 'true'] Integer:: 1 --> 1 List:: [1, 2] --> ['list', 1, 2] String:: "hello" --> "hello" Float:: 2.3 --> 2.3 Dictionary:: {'a': 1, 'b': 'c'} --> ['dictionary', ['b', 'c'], ['a', 1]] Module:: UserString --> ['module', 'UserString'] Class:: UserString.UserString --> ['class', ['module', 'UserString'], 'UserString'] Function:: string.join --> ['function', 'join', ['module', 'string']] Instance: s is an instance of UserString.UserString, with a __dict__ {'data': 'hello'}:: ["UserString.UserString", ['dictionary', ['data', 'hello']]] Class Method: UserString.UserString.center:: ['method', 'center', ['None'], ['class', ['module', 'UserString'], 'UserString']] Instance Method: s.center, where s is an instance of UserString.UserString:: ['method', 'center', ['instance', ['reference', 1, ['class', ['module', 'UserString'], 'UserString']], ['dictionary', ['data', 'd']]], ['dereference', 1]] The Python 2.x C{sets.Set} and C{sets.ImmutableSet} classes are serialized to the same thing as the builtin C{set} and C{frozenset} classes. (This is only relevant if you are communicating with a version of jelly running on an older version of Python.) @author: Glyph Lefkowitz N)reduce) implementer)Version)NotKnown _Container _Dereference_DictKeyAndValue_InstanceMethod_Tuple) nativeString)deprecatedModuleAttribute)namedAny namedObjectqual) IJellyable IUnjellyableNoneclassmodulefunctions dereferences persistents references dictionaryslistsetstuplesinstance frozensetTwistedz'instance_atom is unused within Twisted.ztwisted.spread.jelly instance_atoms unpersistablecFt|tr|j|Sy)a Given an object, if that object is a type, return a new, blank instance of that type which has not had C{__init__} called on it. If the object is not a type, return L{None}. @param cls: The type (or class) to create an instance of. @type cls: L{type} or something else that cannot be instantiated. @return: a new blank instance or L{None} if C{cls} is not a class or type. N) isinstancetype__new__)clss 6/usr/lib/python3/dist-packages/twisted/spread/jelly.py _createBlankr"s"#t{{3cRt|fd}td|}||S)z Make a new instance of a class without calling its __init__ method. @param state: A C{dict} used to update C{inst.__dict__} either directly or via C{__setstate__}, if available. @return: A new instance of C{cls}. c>t|tr |xsi_yyN)rdict__dict__)stateinstances r! defaultSetterz#_newInstance..defaultSetters eT " % H  #r# __setstate__)r"getattr)r r)r+setterr*s @r! _newInstancer/s0C H,X~} =F 5M Or#ct|t}|r t|}t|ts|j d}|S)Nutf-8)rrrbytesencode) classnamepisObjects r! _maybeClassr6s;*d+H*% j% (&&w/ r#cVt|}|t|<tj|y)at Set which local class will represent a remote type. If you have written a Copyable class that you expect your client to be receiving, write a local "copy" class to represent it, then call:: jellier.setUnjellyableForClass('module.package.Class', MyCopier). Call this at the module level immediately after its class definition. MyCopier should be a subclass of RemoteCopy. The classname may be a special tag returned by 'Copyable.getTypeToCopyFor' rather than an actual classname. This call is also for cached classes, since there will be no overlap. The rules are the same. N)r6unjellyableRegistryglobalSecurity allowTypes) classname unjellyables r!setUnjellyableForClassr=s'(I&I%0 "i(r#cVt|}|t|<tj|y)a Set the factory to construct a remote instance of a type:: jellier.setUnjellyableFactoryForClass('module.package.Class', MyFactory) Call this at the module level immediately after its class definition. C{copyFactory} should return an instance or subclass of L{RemoteCopy}. Similar to L{setUnjellyableForClass} except it uses a factory instead of creating an instance. N)r6unjellyableFactoryRegistryr9r:)r; copyFactorys r!setUnjellyableFactoryForClassrAs'I&I,7y)i(r#c| |j}|rd|z}t|D].}t||} t||}|st |||0y#t $rY=wxYw)a Set all classes in a module derived from C{baseClass} as copiers for a corresponding remote class. When you have a hierarchy of Copyable (or Cacheable) classes on one side, and a mirror structure of Copied (or RemoteCache) classes on the other, use this to setUnjellyableForClass all your Copieds for the Copyables. Each copyTag (the "classname" argument to getTypeToCopyFor, and what the Copyable's getTypeToCopyFor returns) is formed from adding a prefix to the Copied's class name. The prefix defaults to module.__name__. If you wish the copy tag to consist of solely the classname, pass the empty string ''. @param module: a module object from which to pull the Copied classes. (passing sys.modules[__name__] might be useful) @param baseClass: the base class from which all your Copied classes derive. @param prefix: the string prefixed to classnames to form the unjellyableRegistry. Nz%s.)__name__dirr- issubclassr= TypeError)module baseClassprefixnameloadedyess r!setUnjellyableForClassTreerMs}0~ F B& BVY/C&&$'8&AB  s A AAc"t|dr|j}n |j}|j|}|j t |j jd|j|g|j||S)zM Utility method to default to 'normal' state rules in serialization. __getstate__r1) hasattrrOr(prepareextendr __class__r3jellypreserve)instjellierr)sxps r!getInstanceStaterYstt^$!!#  //$ CJJT^^$++G4gmmE6JKL   D# &&r#cz|j|d}t|dr|j||S||_|S)zO Utility method to default to 'normal' state rules in unserialization. r,)unjellyrPr,r()rV unjellier jellyListr)s r!setInstanceStater_sE   il +Et^$ %  K Kr#c"eZdZdZdZdefdZy) Unpersistablezd This is an instance of a class that comes back when something couldn't be unpersisted. c||_y)zY Initialize an unpersistable object with a descriptive C{reason} string. N)reason)selfrcs r!__init__zUnpersistable.__init__&s  r#returnc2dt|jzS)NzUnpersistable(%s))reprrcrds r!__repr__zUnpersistable.__repr__,s"T$++%666r#N)rC __module__ __qualname____doc__restrrjr#r!rara s  7#7r#raceZdZdZdZdZy) Jellyablezc Inherit from me to Jelly yourself directly with the `getStateFor' convenience method. c|jSr&r()rdrWs r! getStateForzJellyable.getStateFor7s }}r#c|j|}|jt|jj d|j |j |g|j||S)zH @see: L{twisted.spread.interfaces.IJellyable.jellyFor} r1)rQrRrrSr3rTrtrU)rdrWrXs r!jellyForzJellyable.jellyFor:sfood# T^^$++G4 d..w78  c**r#N)rCrkrlrmrtrvror#r!rqrq0s  +r#rqceZdZdZdZdZy) Unjellyablezf Inherit from me to Unjelly yourself directly with the C{setStateFor} convenience method. c||_yr&rs)rdr]r)s r! setStateForzUnjellyable.setStateForOs  r#cR|j|d}|j|||S)z Perform the inverse operation of L{Jellyable.jellyFor}. @see: L{twisted.spread.interfaces.IUnjellyable.unjellyFor} r[)r\rz)rdr]r^r)s r! unjellyForzUnjellyable.unjellyForRs- !!)A,/ E* r#N)rCrkrlrmrzr|ror#r!rxrxHs r#rxcHeZdZdZdZdZdZdZdZdZ dZ d Z d d Z y ) _JellierzC (Internal) This class manages state for a call to jelly() cf||_i|_i|_i|_d|_||_||_y)z Initialize. r[N)taster preservedcookedcooker_ref_idpersistentStoreinvoker)rdrrrs r!rez_Jellier.__init__bs8    . r#c|jt|}tj|}|j}|jdz|_t||g|ddt |g|j t|<|S)a (internal) Backreference an object. Notes on this method for the hapless future maintainer: If I've already gone through the prepare/preserve cycle on the specified object (it is being referenced after the serializer is "done with" it, e.g. this reference is NOT circular), the copy-in-place of aList is relevant, since the list being modified is the actual, pre-existing jelly expression that was returned for that object. If not, it's technically superfluous, since the value in self.preserved didn't need to be set, but the invariant that self.preserved[id(object)] is a list is convenient because that means we don't have to test and create it or not create it here, creating fewer code-paths. that's why self.preserved is always set to a list. Sorry that this code is so hard to follow, but Python objects are tricky to persist correctly. -glyph r[N)ridcopyrreference_atomdereference_atomr)rdobjectaListnewListrefids r!_cookz_Jellier._cookqsk&r&z*))E" ||a' #E73a#3U"; BvJ r#cfg|jt|<||jt|<gS)a] (internal) Create a list for persisting an object to. This will allow backreferences to be made internal to the object. (circular references). The reason this needs to happen is that we don't generate an ID for every object, so we won't necessarily know which ID the object will have in the future. When it is 'cooked' ( see _cook ), it will be assigned an ID, and the temporary placeholder list created here will be modified in-place to create an expression that gives this object an ID: [reference id# [object-jelly]]. )rrr)rdrs r!rQz_Jellier.prepares/&(r&z" #) BvJ r#ct||jvr5||jt|d<|jt|}|S||jt|<|S)zQ (internal) Mark an object's persistent list for later referral. )rrr)rdrsexps r!rUz_Jellier.preserves] f: $,0DNN2f: &q )>>"V*-D *.DNN2f: & r#ct|}||jvr|j|S||jvr |j||j|Syr&)rrrr)rdobjobjIds r! _checkMutablez_Jellier._checkMutablesQ3 DKK ;;u% % DNN " JJsO;;u% % #r#c 0 t|tr&|j|}|r|S|j|St |}|j j t|jdr|tttfvr|St|tjrR|j}|j}|j }d|j"|j%||j%|gS|t&urd|jdgSt|t drdgSt|tj(rd|j*dz|j,zgSt|tj.rd|j"gS|t0ur d |xrd xsd gS|t2j2ur|j4r t7d d dj9|j:|j<|j>|j@|jB|jD|jFfDcgc] }t'|c}jdgS|t2jHur||j4r t7d ddj9|j@|jB|jD|jFfDcgc] }t'|c}jdgS|t2jJurZddj9|j:|j<|j>fDcgc] }t'|c}jdgS|t2jLurZddj9|jN|jP|jRfDcgc] }t'|c}jdgStU|trdt|jdgS|tVjXur|j[|S|j|}|r|S|j]|}|t^ur'|ja|jctd|n |tfur'|ja|jcth|n|tjvr`|jmtn|jqD]6\} } |jm|j%| |j%| g8ns|trur'|ja|jctt|nD|tvur'|ja|jctx|nt|j jd} d} |jzr|j{||} | '|jmt||jm| n|j j|j r[|jm| t|dr|j} n |j} |jm|j%| n(|jdt|j z||j||Std|d|cc}wcc}wcc}wcc}w)Nr1smethodunicodeUTF-8rr.rbooleantruefalsez2Currently can't jelly datetime objects with tzinfodatetime timedate timedeltarrOz$instance of class %s deemed insecurezType not allowed for object: )Frrqrrvrr isTypeAllowedrr3r2intfloattypes MethodType__self____func__rSrCrTrn FunctionTyperkrl ModuleTypebooldatetimetzinfoNotImplementedErrorjoinyearmonthdayhourminutesecond microsecondtimedate timedeltadaysseconds microsecondsrEdecimalDecimal jelly_decimalrQlistrR_jellyIterable list_atomtuple tuple_atom DictTypesappenddictionary_atomitemssetset_atom frozensetfrozenset_atomrpersistent_atomisClassAllowedrPrOr( unpersistablerU InsecureJelly)rdrpreRefobjTypeaSelfaFuncaClassxrXkeyval className persistentr)s r!rTz_Jellier.jellys c9 %'',F <<% %s) ;; $ $T']%9%9'%B C5#u-- C!1!12  NNJJu%JJv&  C"CJJw$788Cd,y C!3!34#S^^c%9C3GH $S]] 3 : :7 CI!%J++%)%9%9#t%D !- ?3 :.33CMMB 9-"37$'$4$4$6E$'LLE 4::e#45**B"3==12 }}S#.."?y# OP Po ,NTs$Z 2Z Z Z c#HK||D]}|j|yw)a Jelly an iterable object. @param atom: the identifier atom of the object. @type atom: C{str} @param obj: any iterable object. @type obj: C{iterable} @return: a generator of jellied data. @rtype: C{generator} N)rT)rdatomritems r!rz_Jellier._jellyIterable=s+  #D**T" " #s "cX|j\}}}td|}|r| }d||gS)z Jelly a decimal object. @param d: a decimal object to serialize. @type d: C{decimal.Decimal} @return: jelly for the decimal object. @rtype: C{list} c|dz|zS)N ro)leftrights r!z(_Jellier.jelly_decimal..Ys4"9u+<r#decimal)as_tupler)rddsigngutsexponentvalues r!rz_Jellier.jelly_decimalNs: !zz|dH !#))#.Ihhy"~.G;;..w7#gY&<[MLk*C;;--c2#$;k$IJJ''SV4 4r#cV|jt||j|S)a Unjelly a type for which no specific unjellier is registered, but which is nonetheless allowed. @param cls: the class of the instance we are unjellying. @type cls: L{type} @param state: The jellied representation of the object's state; its C{__dict__} unless it has a C{__setstate__} that takes something else. @type state: L{list} @return: the new, unjellied instance. )rr/r\)rdr r)s r!rz_Unjellier._genericUnjellys%%%l3 U8K&LMMr#cyr&rordexps r! _unjelly_Nonez_Unjellier._unjelly_Nonesr#c t|ddS)Nrr)rnrs r!_unjelly_unicodez_Unjellier._unjelly_unicodes3q67##r#c|d}|d}|dkrd}nd}tj|jd}tj|||fS)z* Unjelly decimal objects. rr[)rrr)rdrrrrrs r!_unjelly_decimalz_Unjellier._unjelly_decimalsYAq6 19DDu%..03dH566r#c$|ddvsJ|ddk(S)Nr)rrrrors r!_unjelly_booleanz_Unjellier._unjelly_booleans$1v,,,,1v  r#cdtjtt|djSNr)rmaprrrs r!_unjelly_datetimez_Unjellier._unjelly_datetimes$  #c3q6<<>":;;r#cdtjtt|dj Sr)rrrrrrs r! _unjelly_datez_Unjellier._unjelly_date"}}c#s1v||~677r#cdtjtt|dj Sr)rrrrrrs r! _unjelly_timez_Unjellier._unjelly_timerr#c|tt|dj\}}}tj|||S)Nr)rrr)rrrrr)rdrrrrs r!_unjelly_timedeltaz_Unjellier._unjelly_timedeltas4&)#s1v||~&>#g|!!tW<XXr#cv|j|}t|tr|j|||||<|Sr&)r\rr addDependant)rdrlocjelrs r! unjellyIntoz_Unjellier.unjellyIntos6 LL  a " NN3 $Cr#c|d}|jj|}||St|}||j|<|Sr)rrr)rdlstrrders r!_unjelly_dereferencez_Unjellier._unjelly_dereferencesFA OO   & =H5!!$ r#c|d}|d}|j|}|jj|}|||j|<|St|tr"|j |||j|<|SJd)Nrr[z!Multiple references with same ID!)r\rrrrresolveDependants)rdr)rrrrefs r!_unjelly_referencez_Unjellier._unjelly_referencesA!f LL oo!!%( ;%&DOOE "  X &  ! !! $%&DOOE " :9 91r#c ttt|}d}|D])}t|j ||||t s(d}+|r t |St|S)Nr[r)rrangelenrr'rrr )rdr)lfinishedelems r!_unjelly_tuplez_Unjellier._unjelly_tuplesb s3x ! D$**1dCI>I  8O!9 r#czttt|}|D]}|j|||||Sr&)rr1r2r')rdr)r3r5s r! _unjelly_listz_Unjellier._unjelly_lists> s3x ! 1D   Qc$i 0 1r#cttt|}d}|D]+}|j||||}t |t s*d}-|s t ||S||S)z Helper method to unjelly set or frozenset. @param lst: the content of the set. @type lst: C{list} @param containerType: the type of C{set} to use. TF)rr1r2r'rrr)rdr) containerTyper3r4r5datas r!_unjellySetOrFrozensetz!_Unjellier._unjellySetOrFrozenset sn s3x ! !D##AtSY7D$)  !a/ / # #r#c.|j|tS)z7 Unjelly set using the C{set} builtin. )r<rrdr)s r! _unjelly_setz_Unjellier._unjelly_sets**344r#c.|j|tS)zC Unjelly frozenset using the C{frozenset} builtin. )r<rr>s r!_unjelly_frozensetz_Unjellier._unjelly_frozenset#s**3 ::r#ci}|D]6\}}t|}|j|d||j|d|8|S)Nrr[)r r')rdr)rkvkvds r!_unjelly_dictionaryz_Unjellier._unjelly_dictionary)sO  (DAq"1%C   S!Q '   S!Q ' (r#ct|d}t|tk7r td|jj |std|t |iid}|S)Nrz5Attempted to unjelly a module with a non-string name.z"Attempted to unjelly module named r)r rrnrrr __import__)rdrest moduleNamemods r!_unjelly_modulez_Unjellier._unjelly_module1sc!$q'*  s " WX X{{**:6"DZN ST TRS1 r#ct|d}|jtd}tdj|dd}|jj |st d|zt |}t|}|turt d|d||jj|st dt|z|S)Nrrrzmodule %s not allowedzclass z, unjellied to something that isn't a class: zclass not allowed: %s) r rrrrrrrrr)rdrIcnameclistr klausrs r!_unjelly_classz_Unjellier._unjelly_class:sT!W% L-.s#((s4{{**73 7' AB BE"u+ $ %! {{))%0 7$u+ EF F r#ct|d}|jtd}tdj|dd}|jj |st d|zt |}|S)NrrrzModule not allowed: %s)r rrrrrr)rdrIfnamemodSplitr functions r!_unjelly_functionz_Unjellier._unjelly_functionKsoT!W%;;|C01s#((#27{{**73 87 BC CE?r#c^|jr|j|d|}|StdS)NrzPersistent callback not found)rra)rdrIploads r!_unjelly_persistentz_Unjellier._unjelly_persistentUs2   ''Q6EL !@A Ar#ctjdtdd|j|d}|j ||dS)z (internal) Unjelly an instance. Called to handle the deprecated I{instance} token. @param rest: The s-expression representing the instance. @return: The unjellied instance. ztUnjelly support for the instance atom is deprecated since Twisted 15.0.0. Upgrade peer for modern instance support.r)categoryfilenamelinenor[)warnings warn_explicitDeprecationWarningr\r)rdrIr s r!_unjelly_instancez_Unjellier._unjelly_instance\sL  I'  ll47###Ca11r#c$td|dS)NzUnpersistable data: r)ra)rdrIs r!_unjelly_unpersistablez!_Unjellier._unjelly_unpersistableqs3DG9=>>r#cv|d}|j|d}|j|d}t|ts td||jvrY|t ||}|St|t rt|||}|Stj|j||g|gdz}|Std)z. (internal) Unjelly a method. rr[rz"Method found with non-class class.Fzinstance method changed) r\rrrr(r-rr rrrF)rdrIim_nameim_selfim_classims r!_unjelly_methodz_Unjellier._unjelly_methodtsq',,tAw'<<Q((D) DE E h'' 'Xw/ GX.$Wgx@ %%%%g. insecure security options Dummy security options -- this class will allow anything. cy)z DummySecurityOptions.isModuleAllowed(moduleName) -> boolean returns 1 if a module by that name is allowed, 0 otherwise r[rordrJs r!rz$DummySecurityOptions.isModuleAllowed r#cy)z DummySecurityOptions.isClassAllowed(class) -> boolean Assumes the module has already been allowed. Returns 1 if the given class is allowed, 0 otherwise. r[rordklasss r!rz#DummySecurityOptions.isClassAlloweds r#cy)z DummySecurityOptions.isTypeAllowed(typeName) -> boolean Returns 1 if the given type is allowed, 0 otherwise. r[rordtypeNames r!rz"DummySecurityOptions.isTypeAllowedrpr#N)rCrkrlrmrrrror#r!rmrms r#rmcHeZdZdZgdZdZdZdZdZdZ dZ d Z d Z y ) SecurityOptionszF This will by default disallow everything, except for 'none'. ) dictionaryrr reference dereferencerrlong_intlongr'ciddddddddddddddd dd dd dd dd ddddddddd|_i|_i|_y)z/ SecurityOptions() initialize. rr[sboolrsstringsstrsintsfloatrrrrsNoneTyperrrrN) allowedTypesallowedModulesallowedClassesris r!rezSecurityOptions.__init__s  Q Q    q  A  A   a    Q  Q  !        A !! $! r#c6|j|jy)zz Allow all `basic' types. (Dictionary and list. Int, string, and float are implicitly allowed.) N)r: basicTypesris r!allowBasicTypeszSecurityOptions.allowBasicTypess )r#c|D]M}t|tr|jd}t|ts t |}d|j |<Oy)zg SecurityOptions.allowTypes(typeString): Allow a particular type, by its name. r1r[N)rrnr3r2rr)rdrtyps r!r:zSecurityOptions.allowTypessN  'C#s#jj)c5)3i%&D  c "  'r#c|j|jdddd|D]F}|jt||j|jd|j |<Hy)a SecurityOptions.allowInstances(klass, klass, ...): allow instances of the specified classes This will also allow the 'instance', 'class' (renamed 'classobj' in Python 2.3), and 'module' types, as well as basic types. r*classclassobjrGr[N)rr:r allowModulesrkr)rdclassesrss r!allowInstancesOfz SecurityOptions.allowInstancesOfse   GZB +E OODK (   e.. /)*D   & +r#c|D]Z}t|tjk(r |j}t |t s|j d}d|j|<\y)z SecurityOptions.allowModules(module, module, ...): allow modules by name. This will also allow the 'module' type. r1r[N)rrrrCrr2r3r)rdmodulesrGs r!rzSecurityOptions.allowModulessV  ,FF|u///fe,w/*+D   ' ,r#c`t|ts|jd}||jvS)z SecurityOptions.isModuleAllowed(moduleName) -> boolean returns 1 if a module by that name is allowed, 0 otherwise r1)rr2r3rros r!rzSecurityOptions.isModuleAlloweds/ *e,#**73JT0000r#c||jvS)z SecurityOptions.isClassAllowed(class) -> boolean Assumes the module has already been allowed. Returns 1 if the given class is allowed, 0 otherwise. )rrrs r!rzSecurityOptions.isClassAlloweds ++++r#clt|ts|jd}||jvxsd|vS)z SecurityOptions.isTypeAllowed(typeName) -> boolean Returns 1 if the given type is allowed, 0 otherwise. r1.)rr2r3rrus r!rzSecurityOptions.isTypeAllowed!s7 (E*w/H4,,,@0@@r#N) rCrkrlrmrrerr:rrrrrror#r!rxrxs7 J!6* ' + ,1,Ar#rxc:t|||j|S)z Serialize to s-expression. Returns a list which is the serialized representation of an object. An optional 'taster' argument takes a SecurityOptions and will mark any insecure objects as unpersistable rather than serializing them. )r~rT)rrrrs r!rTrT0s FOW 5 ; ;F CCr#c:t|||j|S)aT Unserialize from s-expression. Takes a list that was the result from a call to jelly() and unserializes an arbitrary object from it. The optional 'taster' argument, an instance of SecurityOptions, will cause an InsecureJelly exception to be raised if a disallowed type, module, or class attempted to unserialize. )rr)rrrrs r!r\r\;s fng 6 B B4 HHr#r&)Ermrrrrr_ functoolsrzope.interfacer incrementalrtwisted.persisted.crefutilrrrr r r twisted.python.compatr twisted.python.deprecater twisted.python.reflectrrrtwisted.spread.interfacesrrr'r None_atom class_atom module_atom function_atomrrrrrrrrrrr8r?r"r/r6r=rArMrYr_rarqrxr~r Exceptionrrmrxr9rrTr\ror#r!rs 8t  &/>>>> G     "      Ir1a - &  ( )2)(&BR '  7 7  Z+++. \(LL^\\D I:wAwAt!" ./tD./d Ir#