From jim at zope.com Tue Jun 4 16:05:49 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - Contact.py:1.2.2.1 Contact.zcml:1.7.2.1 ContactEditView.py:1.1.2.1 IContact.py:1.2.2.1 IContactEdit.py:1.1.2.1 IContactInfo.py:1.1.2.1 __init__.py:1.3.2.1 edit.pt:1.5.2.1 stubpostal.py:1.5.2.1 ContactInfoView.py:NONE ContactViewPresentation.py:NONE Message-ID: <200206042005.g54K5nG29208@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv29193 Modified Files: Tag: Zope3InWonderland-branch Contact.py Contact.zcml ContactEditView.py IContact.py IContactEdit.py IContactInfo.py __init__.py edit.pt stubpostal.py Removed Files: Tag: Zope3InWonderland-branch ContactInfoView.py ContactViewPresentation.py Log Message: Contact step 5 now works with the Zope3InWonderland-branch! (and the Zope3InWonderland-branch works with it ;) === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/Contact.py 1.2 => 1.2.2.1 === import Persistence +from IContact import IContact class Contact (Persistence.Persistent): - """Contacts keep track of personal data, such as name, email - and postal address. All methods are protected.""" + """Personal contact information + + Contacts keep track of personal data, such as name, email + and postal address. All methods are protected. + """ + + __implements__ = IContact def __init__(self, first='', last='', email='', address='', pc=''): self.update(first, last, email, address, pc) === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/Contact.zcml 1.7 => 1.7.2.1 === - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + - - + factory=".stubpostal.Lookup" + provides=".IPostal.IPostalLookup" + permission="Zope.Public" /> - + factory=".ContactCityState." + provides=".IPostal.IPostalInfo" + for=".IContact.IContactInfo" + permission="Zope.Public" + /> === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactEditView.py 1.1 => 1.1.2.1 === -from Zope.PageTemplate import PageTemplateFile -from IContactEdit import IContactEdit - -class ContactEditView(AttributePublisher): - """Provide an interface for editing a contact - """ - - # Boiler plate - def __init__(self, context): - self._context=context - - def getContext(self): - return self._context - - # Assert that we can only be applied to IContactEdit - __used_for__=IContactEdit +from Zope.App.PageTemplate import ViewPageTemplateFile +from Zope.Publisher.Browser.BrowserView import BrowserView +from IContact import IContact + +class ContactEditView(BrowserView): + "Provide a user interface for editing a contact" + + # Assert that we can only be applied to IContact + __used_for__ = IContact # Input form - index = PageTemplateFile('edit.pt', globals()) + editForm = ViewPageTemplateFile('edit.pt') # action method - def action(self, first, last, email, address, pc, REQUEST): + def edit(self, first, last, email, address, pc): "Edit a contact" - self.getContext().update(first, last, email, address, pc) - return self.index(REQUEST) + self.context.update(first, last, email, address, pc) + return self.editForm() === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContact.py 1.2 => 1.2.2.1 === +from Interface import Interface -# Local Package imports -from Contact import Contact +class IContactInfo(Interface): + "Provides access to basic contact information." -class IContact(Interface): - "Marker for objects that provide specific behavior" + def first(): "Get the first name" + def last(): "Get the last name" + def email(): "Get the electronic mail address" + def address(): "Get the postal address" + def postal_code(): "Get the postal code" -implements(Contact, IContact) + def name(): + """Gets the contact name. + + The contact name is the first and last name""" + +class IContact(IContactInfo): + "Provides the ability to change contact information." + + def update(first, last, email, address, pc): + """Modifies contact data + + 'None' values are ignored. + """ === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContactEdit.py 1.1 => 1.1.2.1 === from Contact import Contact -from Interface import implements +from Interface.Implements import implements class IContactEdit(IContactInfo): "Provides the ability to change basic contact information." === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContactInfo.py 1.1 => 1.1.2.1 === +from Interface import Interface +from Interface.Implements import implements # Local Package imports from Contact import Contact === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/__init__.py 1.3 => 1.3.2.1 === === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/edit.pt 1.5 => 1.5.2.1 ===
Enter the information about the contact. -
+
First name 1.5.2.1 === if data is not None: data = Info(*data) return data - -lookup=Lookup() === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactInfoView.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactViewPresentation.py === From jim at zope.com Fri Jun 7 11:17:41 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sdd.gz:1.4 Message-ID: <200206071517.g57FHfS26137@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv26130 Modified Files: slides.sdd.gz Log Message: Updated to reflect "Wonderland" changes. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sdd.gz 1.3 => 1.4 === From jim at zope.com Mon Jun 10 08:07:46 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - Contact.py:1.3 Contact.zcml:1.8 ContactEditView.py:1.2 IContact.py:1.3 IContactEdit.py:1.2 IContactInfo.py:1.2 __init__.py:1.4 edit.pt:1.6 stubpostal.py:1.6 ContactInfoView.py:NONE ContactViewPresentation.py:NONE Message-ID: <200206101207.g5AC7kf12885@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv12870 Modified Files: Contact.py Contact.zcml ContactEditView.py IContact.py IContactEdit.py IContactInfo.py __init__.py edit.pt stubpostal.py Removed Files: ContactInfoView.py ContactViewPresentation.py Log Message: Merged in changes from Wonderland branch === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/Contact.py 1.2 => 1.3 === import Persistence +from IContact import IContact class Contact (Persistence.Persistent): - """Contacts keep track of personal data, such as name, email - and postal address. All methods are protected.""" + """Personal contact information + + Contacts keep track of personal data, such as name, email + and postal address. All methods are protected. + """ + + __implements__ = IContact def __init__(self, first='', last='', email='', address='', pc=''): self.update(first, last, email, address, pc) === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/Contact.zcml 1.7 => 1.8 === - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + - - + factory=".stubpostal.Lookup" + provides=".IPostal.IPostalLookup" + permission="Zope.Public" /> - + factory=".ContactCityState." + provides=".IPostal.IPostalInfo" + for=".IContact.IContactInfo" + permission="Zope.Public" + /> === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactEditView.py 1.1 => 1.2 === -from Zope.PageTemplate import PageTemplateFile -from IContactEdit import IContactEdit - -class ContactEditView(AttributePublisher): - """Provide an interface for editing a contact - """ - - # Boiler plate - def __init__(self, context): - self._context=context - - def getContext(self): - return self._context - - # Assert that we can only be applied to IContactEdit - __used_for__=IContactEdit +from Zope.App.PageTemplate import ViewPageTemplateFile +from Zope.Publisher.Browser.BrowserView import BrowserView +from IContact import IContact + +class ContactEditView(BrowserView): + "Provide a user interface for editing a contact" + + # Assert that we can only be applied to IContact + __used_for__ = IContact # Input form - index = PageTemplateFile('edit.pt', globals()) + editForm = ViewPageTemplateFile('edit.pt') # action method - def action(self, first, last, email, address, pc, REQUEST): + def edit(self, first, last, email, address, pc): "Edit a contact" - self.getContext().update(first, last, email, address, pc) - return self.index(REQUEST) + self.context.update(first, last, email, address, pc) + return self.editForm() === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContact.py 1.2 => 1.3 === +from Interface import Interface -# Local Package imports -from Contact import Contact +class IContactInfo(Interface): + "Provides access to basic contact information." -class IContact(Interface): - "Marker for objects that provide specific behavior" + def first(): "Get the first name" + def last(): "Get the last name" + def email(): "Get the electronic mail address" + def address(): "Get the postal address" + def postal_code(): "Get the postal code" -implements(Contact, IContact) + def name(): + """Gets the contact name. + + The contact name is the first and last name""" + +class IContact(IContactInfo): + "Provides the ability to change contact information." + + def update(first, last, email, address, pc): + """Modifies contact data + + 'None' values are ignored. + """ === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContactEdit.py 1.1 => 1.2 === from Contact import Contact -from Interface import implements +from Interface.Implements import implements class IContactEdit(IContactInfo): "Provides the ability to change basic contact information." === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContactInfo.py 1.1 => 1.2 === +from Interface import Interface +from Interface.Implements import implements # Local Package imports from Contact import Contact === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/__init__.py 1.3 => 1.4 === === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/edit.pt 1.5 => 1.6 ===
Enter the information about the contact. - +
First name 1.6 === if data is not None: data = Info(*data) return data - -lookup=Lookup() === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactInfoView.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactViewPresentation.py === From steve at cat-box.net Mon Jun 10 09:02:55 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6 - Contact.zcml:1.3 Message-ID: <200206101302.g5AD2ti32666@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6 In directory cvs.zope.org:/tmp/cvs-serv32530/Step6 Modified Files: Contact.zcml Log Message: added OpenOffice 1.0 version of the slides. This will be the canonical version of the slides. Note: I need to find out whether the Luxi fonts are a standard part of OpenOffice, and change the fonts to standard ones otherwise. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/Contact.zcml 1.2 => 1.3 === xmlns:browser='http://namespaces.zope.org/browser'> + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - + + + + - - + provides=".IPostal.IPostalLookup" + permission="Zope.Public" /> + for=".IContactInfo." + permission="Zope.Public" /> From steve at cat-box.net Mon Jun 10 09:41:25 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides_readme.txt:1.1 slides.sxi:1.2 Message-ID: <200206101341.g5ADfPA10972@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv10770 Modified Files: slides.sxi Added Files: slides_readme.txt Log Message: formatting changes to slides.sxi added slides_readme.txt to explain about the sxi file, and the fonts used in it. === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides_readme.txt === README document for slides.sxi The slides.sxi file is in OpenOffice "Impress" slideshow format. It uses the Luxi set of fonts, which are available as standard with XFree86 4.?.x. You can get these fonts separately as part of Debian xfonts-scalable-nonfree in TTF and type1 formats. http://packages.debian.org/unstable/x11/xfonts-scalable-nonfree.html The OpenOffice slideshow format is documented on the OpenOffice website. http://xml.openoffice.org/faq.html You can get at various the various xml files and binary files such as images that comprise the presentation by unzipping the slides.sxi file. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.1 => 1.2 === From steve at cat-box.net Mon Jun 10 09:50:26 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.3 Message-ID: <200206101350.g5ADoQv14013@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv13923 Modified Files: slides.sxi Log Message: some updates to zcml. one XXX: query in red for Jim to look at later. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.2 => 1.3 === From steve at cat-box.net Mon Jun 10 12:08:32 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sdd.gz:NONE Message-ID: <200206101608.g5AG8WI18015@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv18007 Removed Files: slides.sdd.gz Log Message: removing obselete StartOffice 5.x file. === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sdd.gz === From steve at cat-box.net Mon Jun 10 14:50:16 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides_readme.txt:1.2 dev_slides.sxi:NONE Message-ID: <200206101850.g5AIoGD27632@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv27535 Modified Files: slides_readme.txt Removed Files: dev_slides.sxi Log Message: removed obselete dev_slides.sxi added note about using "font replacements" in Open Office, if you have the fonts under the older name Lucidux rather than Luxi. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides_readme.txt 1.1 => 1.2 === http://packages.debian.org/unstable/x11/xfonts-scalable-nonfree.html + +In some older OSes and older versions of XFree86, the fonts were called +Lucidux Sans and Lucidux Mono. +The easiest thing to do if you have these fonts is go into the +tools | font replacements menu of Open Office, and add the two replacements + + * replace Luxi Sans with Lucidux Sans + + * replace Luxi Mono with Lucidux Mono The OpenOffice slideshow format is documented on the OpenOffice website. === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/dev_slides.sxi === From steve at cat-box.net Mon Jun 10 16:16:37 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - contact_product_uml.txt:1.5 Message-ID: <200206102016.g5AKGb218064@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv17954 Modified Files: contact_product_uml.txt Log Message: updated ascii art uml in line with updates in the tutorial === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/contact_product_uml.txt 1.4 => 1.5 === - <> - o IContact <> - | ----------- - | | edit.pt | - ----------- ----------- <> - | Contact | | ----------- - ----------- | | info.pt | - | | ^ <> ----------- - | | --V---------------- | - | o<- - - - - - - -| ContactEditView | | - | IContactEdit ------------------- | - | | - | <> ^ - |IContactInfo ----------V-------- - o<- - - - - - - - - - - - - - - - - - -| ContactInfoView | - ^ ------------------- - : - : o IPostalInfo - : | - : <> + <> + ---------- + | Lookup | + ---------- + | + o IPostalLookup + o IPostalInfo ^ + | : + <> : + -------------------- : + | ContactCityState |- - - - + -------------------- - | ContactCityState | - -------------------- - : - : - + - - - - - ->o IPostalLookup - | - | - <> - ---------- - | Lookup | - ---------- - + : + : + : + : <> + v IContactInfo ------------------- + o<- - - - - - - - - - - - - - - - - - -| ContactInfoView | + ^ --------^---------- + : V + : | + : | <> + : <> ----------- + : ----------- | info.pt | + : | edit.pt | ----------- + : ----------- + : | + : ^ <> + : IContact --------V---------- + o<- - - - - - -| ContactEditView | + | ------------------- + | + ----------- + | Contact | + ----------- + Key: @@ -43,6 +46,11 @@ <- - - + Dependency : + + + o<- - -o Interface B specializes interface A + A B + <> Stereotype From steve at cat-box.net Mon Jun 10 16:27:13 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.4 Message-ID: <200206102027.g5AKRDK21720@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv21589 Modified Files: slides.sxi Log Message: fixed some formatting inconsistencies === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.3 => 1.4 === From steve at cat-box.net Thu Jun 13 13:38:05 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.5 Message-ID: <200206131738.g5DHc5k25329@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv24328 Modified Files: slides.sxi Log Message: highlighted the first introduction of the browser namespace into the zcml file. The caught up a learner who was studying from the tutorial slides, adding in the new highlighted sections each time. She missed adding the new namespace declaration, as it was not highlighted like the other new text. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.4 => 1.5 === From steve at cat-box.net Thu Jun 13 13:43:07 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.6 Message-ID: <200206131743.g5DHh7Q26592@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv26505 Modified Files: slides.sxi Log Message: changed "here/first" etc. in info.pt to "context/first" === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.5 => 1.6 === From steve at cat-box.net Thu Jun 13 14:27:43 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.7 Message-ID: <200206131827.g5DIRhc05364@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv5357 Modified Files: slides.sxi Log Message: corrected "PageTemplateFile" to "ViewPageTemplateFile" on slide 34. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.6 => 1.7 === From steve at cat-box.net Fri Jun 14 05:17:05 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - Contact.zcml:1.9 Message-ID: <200206140917.g5E9H5431375@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv30460 Modified Files: Contact.zcml Log Message: Corrected path to icon from Contact/contact.gif to just contact.gif === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/Contact.zcml 1.8 => 1.9 === - + From steve at cat-box.net Fri Jun 14 07:50:21 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.8 Message-ID: <200206141150.g5EBoLA05629@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv5526 Modified Files: slides.sxi Log Message: slide 39: changed Contact/contact.gif to contact.gif changed to === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.7 => 1.8 === From steve at cat-box.net Sun Jun 16 09:57:02 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.9 Message-ID: <200206161357.g5GDv2t16241@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv15379 Modified Files: slides.sxi Log Message: corrected typo on slide 49 === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.8 => 1.9 === From steve at cat-box.net Sun Jun 16 10:14:25 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.10 Message-ID: <200206161414.g5GEEPo20531@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv20520 Modified Files: slides.sxi Log Message: corrected code error on slide 49. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.9 => 1.10 === From steve at cat-box.net Sun Jun 16 10:24:32 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.11 Message-ID: <200206161424.g5GEOWw23248@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv23233 Modified Files: slides.sxi Log Message: removed superfluous qualification of classes in slide 50 === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.10 => 1.11 === From steve at cat-box.net Sun Jun 16 11:56:11 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.12 Message-ID: <200206161556.g5GFuBW14483@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv14397 Modified Files: slides.sxi Log Message: various corrections to typos in code explained queryAdapter expanded confusing abbreviation "nva" to "number_in_virginia" === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.11 => 1.12 === From jim at zope.com Tue Jun 18 11:41:31 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - ContactInfoView.py:1.3 configure.zcml:1.1 ContactEditView.py:1.3 README.txt:1.7 edit.pt:1.7 info.pt:1.3 Contact.zcml:NONE IContactEdit.py:NONE IContactInfo.py:NONE view.pt:NONE Message-ID: <200206181541.g5IFfVM22282@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv22086 Modified Files: ContactEditView.py README.txt edit.pt info.pt Added Files: ContactInfoView.py configure.zcml Removed Files: Contact.zcml IContactEdit.py IContactInfo.py view.pt Log Message: Merged Steve's step 6 into this step (5). Changed views to specify templates in zcml. Changed the config file to configure.zcml. Change the form/action naming pattern in the edit view so that the form has a nice name ('edit.html') and the action has a long name, which users should never see. Change the edit action to redirect to the default view. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactInfoView.py 1.2 => 1.3 === +from IContactInfo import IContactInfo +from IPostal import IPostalInfo + +class ContactInfoView: + """Provide an interface for viewing a contact + """ + + __used_for__ = IContactInfo + + def __init__(self, context, request): + self.context = context + self.request = request + + self.info = getAdapter(context, IPostalInfo) + + def city(self): + return self.info.city() + + def state(self): + return self.info.state() + === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/configure.zcml === === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactEditView.py 1.2 => 1.3 === from Zope.Publisher.Browser.BrowserView import BrowserView from IContact import IContact @@ -8,11 +7,8 @@ # Assert that we can only be applied to IContact __used_for__ = IContact - # Input form - editForm = ViewPageTemplateFile('edit.pt') - # action method - def edit(self, first, last, email, address, pc): + def action(self, first, last, email, address, pc): "Edit a contact" self.context.update(first, last, email, address, pc) - return self.editForm() + self.request.response.redirect('.') === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/README.txt 1.6 => 1.7 === +Step5, adding adapters and utilities In earlier steps we showed how to use simple classes to create content objects that can be used in Zope. We also showed how to create @@ -20,7 +20,7 @@ services and services are more prominent within the component-management facilities. A common use of services is to manage components. There are services for managing presentation - components, features, utilities and services. Services may provide + components, adapters, utilities and services. Services may provide other foundational capabilities, such as cataloging, version management, and event channels. Utilities provide functionality that may be used by a few applications or components. @@ -41,32 +41,35 @@ The 'stubpostal' module, in 'stubpostal.py', provides an implementation of the postal interfaces suitable for testing. This - module allows us to build and test our contact feature, but we don't + module allows us to build and test our contact adapter, but we don't expect it to be used in a production environment. The configuration file registers the the stub utility using the - 'utility' directive. The 'utility' directive uses two - attributes. The 'provides' attribute specifies the interface that - the component provides. The 'factory' attribute specifies the - component. The interface identifies the utility and the component - provides the implementation. In this case, we register an actual - component, which is an instance of our lookup class. This is in - contrast to the way that presentation components are registered. For - presentation components, we don't register the component directly, - but register a callable object that returns the presentation - component for a given context. + 'utility' directive. The 'utility' directive uses three + attributes. - The configuration module makes security assertions for the utility - classes, declaring the utilities and their methods to be public. + The 'provides' attribute specifies the interface that the component + provides. - The 'ContactCityState' module, in 'ContactCityState.py', defines a - feature component for getting the city and state for a contact + The 'factory' attribute specifies an object that can be called to + create the utility, typically the utility class. We could also + create the utility instance ourselves in Python and name the object + with a 'component' attribute. This would be useful if the utility + contained data that needed to be set up in Python. In this case, we + don't provide any special data, so it's easier to just specify the + class in the configuration file. + + The permission attribute specifies the id of the permission required + to use the utility. + + The 'ContactCityState' module, in 'ContactCityState.py', defines an + adapter for getting the city and state for a contact object. The constructor for the component uses the contact 'postal_code' method, defined in the 'IContactInfo' interface to get the contact postal code. It then retrieves a 'PostalLookup' utility to get a 'PostalInfo' object for the given postal code. It looks up the utility with 'Zope.ComponentArchitecture.getUtility', which - takes two arguments [2], an object and a desired interface. The + takes two arguments, an object and a desired interface. The first argument is passed to allow the utility lookup to be context dependent. Utilities can be registered in specific locations (e.g. folders) in a Zope object system. By passing an object to @@ -75,49 +78,33 @@ for later use in the 'city' and 'state' methods. The adapter is registered with the 'adapter' directive in the - configuration file. The 'adapter' directive uses three + configuration file. The 'adapter' directive uses four attributes. The 'for' attribute specifies the interface of the - objects the feature is used for. The 'factory' and 'provides' - attributes specify the component and the provided interface. The - adapter can be used with any component that provides the input - interface. In this example, we pass the class as the callable - object. Adapters are like presentation components in that they are - context-dependent and must be registered with a callable object that - creates a component for a given context. - - To use the feature, we need to look it up with the - 'Zope.ComponentArchitecture.getAdapter' method. For example, - consider a Python script that wants to find out how many contacts, - in a list of contacts live in Virginia:: - - from Zope.ComponentArchitecture import getAdapter - nva = 0 - for contact in aListOfContacts: - info = getAdapter(contact, IPostalInfo, None) - if info is not None and info.state() == 'Virginia': - nva = nva+1 - - In this example, 'getAdapter' is passed three arguments: an object, - an interface, and a default value. In this case, the object passed - specifies both a location to search for the feature and an object - that the feature will be passed when it is created (or bound). It's - worth noting that if the object passed as the first argument already - implements the interface passed as the second argument, the object - will be returned. - - This adapter can be used with any - implementation of 'IContactInfo' and 'IPostalLookup'. If there were - multiple or alternative contact implementations, this adapter would - be applicable. Similarly, the adapter works equally well with a - production-quality postal-information lookup component and with the - stub that we've provided here. - ------------------------------------------------------------------------------- - -[1] -- We allow either an interface or a name. The name is only used - in cases where defining an interface is too much - bother. Interfaces are preferred. - -[2] -- An optional third argument can provide a default. If no default - is specified, an error is raised if the lookup fails. + objects the adapter is used for. The 'factory' and 'provides' + attributes specify the component factory and the + provided interface. The adapter can be used with any component that + provides the input interface. In this example, we pass the class as + the component factory. Adapters are like presentation components in + that they are context-dependent and must be registered with a + callable object that creates a component for a given context. + + The 'permission' attribute in the adapter directive specifies the id + of the permission required to use the attribute. + + We'll update the Contact info view to use the adapter. First, we'll + create a new class, 'ContactInfoView', in 'ContactInfoView.py'. This + class provides a contructor that saves the request and response and + gets and saves the new adapter. It gets the adapter by calling + 'Zope.ComponentArchitecture.getAdapter'. It provides 'city' and + 'state' methods that call the adapter. + + The info template, 'info.pt' is updated to use these methods. Notice + that the methods are invoked on the view, not on the context. + + Finally, we need to update the configuratrion file to use the new + view class. We still have a view with one page, so we can still use + the simple form of the view directive. We simply provide an + additional attribute, 'class', that specified the new class, + 'ContactInfoView'. The class is used as a base class for the + generated view component. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/edit.pt 1.6 => 1.7 ===
Enter the information about the contact. - + - + + + + + + + +
First name 1.3 === Mailing address here
Email
Email: foo@bar.com
City:City
State:State
=== Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/Contact.zcml === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContactEdit.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/IContactInfo.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/view.pt === From steve at cat-box.net Tue Jun 18 13:45:12 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - configure.zcml:1.2 Message-ID: <200206181745.g5IHjC921561@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv21476 Modified Files: configure.zcml Log Message: changed formatting to correspond with the zcml style guide. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/configure.zcml 1.1 => 1.2 === - xmlns='http://namespaces.zope.org/zope' - xmlns:security='http://namespaces.zope.org/security' - xmlns:zmi='http://namespaces.zope.org/zmi' - xmlns:browser='http://namespaces.zope.org/browser'> + xmlns='http://namespaces.zope.org/zope' + xmlns:security='http://namespaces.zope.org/security' + xmlns:zmi='http://namespaces.zope.org/zmi' + xmlns:browser='http://namespaces.zope.org/browser'> + id="ZopeProducts.Contact.ManageContacts" + title="Manage Contacts" /> - - - - - - + permission="ZopeProducts.Contact.ManageContacts" + title="Personal Contact Information" /> + + - - - - - + - - + + + + + - - + + @@ -57,10 +55,9 @@ permission="Zope.Public" /> + factory=".ContactCityState." + provides=".IPostal.IPostalInfo" + for=".IContact.IContactInfo" + permission="Zope.Public" /> From steve at cat-box.net Tue Jun 18 13:53:51 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - stubpostal.py:1.7 Message-ID: <200206181753.g5IHrpI23965@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv23958 Modified Files: stubpostal.py Log Message: simplified lookup method === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/stubpostal.py 1.6 => 1.7 === def lookup(self, postal_code): - data=self._data.get(postal_code) - if data is not None: data = Info(*data) - return data + data = self._data.get(postal_code) + if data: return Info(*data) From steve at cat-box.net Tue Jun 18 13:59:39 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - ContactCityState.py:1.5 products.zcml:1.2 Message-ID: <200206181759.g5IHxdL25302@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv25288 Modified Files: ContactCityState.py products.zcml Log Message: minor formatting changes. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactCityState.py 1.4 => 1.5 === "Provide access to city and state information for a contact" - __implements__=IPostalInfo + __implements__ = IPostalInfo - __used_for__=IContactInfo + __used_for__ = IContactInfo def __init__(self, contact): - self._contact=contact + self._contact = contact lookup = getUtility(contact, IPostalLookup) info = lookup.lookup(contact.postal_code()) if info is None: === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/products.zcml 1.1 => 1.2 === - xmlns='http://namespaces.zope.org/zope' - xmlns:security='http://namespaces.zope.org/security' - xmlns:zmi='http://namespaces.zope.org/zmi' - xmlns:browser='http://namespaces.zope.org/browser' + xmlns='http://namespaces.zope.org/zope' + xmlns:security='http://namespaces.zope.org/security' + xmlns:zmi='http://namespaces.zope.org/zmi' + xmlns:browser='http://namespaces.zope.org/browser' > From steve at cat-box.net Tue Jun 18 14:49:13 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - README.txt:1.8 Message-ID: <200206181849.g5IInDb10237@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv10148 Modified Files: README.txt Log Message: corrected typos. Rephrased certain sentences. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/README.txt 1.7 => 1.8 === separate presentation components that provide web interfaces for your objects. In this step, we'll learn about components for - providing additional functionality to your objects and - applications. + providing additional functionality to your objects and applications. Components that provide new presentation-independent logic are called "application-functionality" components. There are three standard kinds of application-functionality components. Adapters provide new functionality for other components, typically content - components. Utilities and services provide stand-alone - functionality. + components. Utilities and services provide stand-alone functionality. Utilities and services differ primarily in their role with respect to the system overall and in their management. Services are foundational. Many components and applications will depend on services and services are more prominent within the component-management facilities. A common use of services is to - manage components. There are services for managing presentation + manage components: there are services for managing presentation components, adapters, utilities and services. Services may provide other foundational capabilities, such as cataloging, version management, and event channels. Utilities provide functionality - that may be used by a few applications or components. + for particular applications or components. In this step, we'll add a simple (trivial) adapter for getting city and state information for contacts. The functionality is provided using an adapter because the computation depends on a content component, specifically a contact. The adapter will look up the - city and state for a contact using the contact postal code. Looking - up a city and state for a postal code is not unique to working with - contacts however. We'll use a separate utility for doing the + city and state for a contact using the contact's postal code. + Because looking up a city and state for a postal code is not unique + to working with contacts, we'll use a separate utility for doing the postal-code lookup. The 'IPostal' module, in 'IPostal.py', defines two interfaces needed - for postal code data lookup. The first interface defines how to get - postal-code data from postal code information objects. The second + for looking up postal code data. The first interface defines how to + get postal-code data from postal code information objects. The second interface defines postal code lookup. The 'stubpostal' module, in 'stubpostal.py', provides an implementation of the postal interfaces suitable for testing. This module allows us to build and test our contact adapter, but we don't - expect it to be used in a production environment. + expect it to be used in a production environment. - The configuration file registers the the stub utility using the + The configuration file registers the stub as a utility using the 'utility' directive. The 'utility' directive uses three attributes. @@ -60,14 +58,14 @@ class in the configuration file. The permission attribute specifies the id of the permission required - to use the utility. + in order to use the utility. The 'ContactCityState' module, in 'ContactCityState.py', defines an - adapter for getting the city and state for a contact - object. The constructor for the component uses the contact - 'postal_code' method, defined in the 'IContactInfo' interface to get - the contact postal code. It then retrieves a 'PostalLookup' utility - to get a 'PostalInfo' object for the given postal code. It looks up + adapter for getting the city and state for a contact object. The + adapter's constructor method uses the contact's 'postal_code' method, + defined in the 'IContactInfo' interface to get the contact's postal + code. The constructor then retrieves an 'IPostalLookup' utility + to get an 'IPostalInfo' object for the given postal code. It looks up the utility with 'Zope.ComponentArchitecture.getUtility', which takes two arguments, an object and a desired interface. The first argument is passed to allow the utility lookup to be context @@ -75,36 +73,39 @@ (e.g. folders) in a Zope object system. By passing an object to getUtility, we cause local utility registries, if any, to be searched. The constructor gets the city and state, which it saves - for later use in the 'city' and 'state' methods. + for later use by the 'city' and 'state' methods. - The adapter is registered with the 'adapter' directive in the - configuration file. The 'adapter' directive uses four - attributes. The 'for' attribute specifies the interface of the - objects the adapter is used for. The 'factory' and 'provides' - attributes specify the component factory and the - provided interface. The adapter can be used with any component that - provides the input interface. In this example, we pass the class as - the component factory. Adapters are like presentation components in - that they are context-dependent and must be registered with a - callable object that creates a component for a given context. + The ContactCityState adapter is registered with the 'adapter' directive + in the 'configure.zcml' configuration file. The 'adapter' directive uses + four attributes. The 'for' and 'provides' attributes specify the + interface of the objects the adapter is used for, and the interface + the adapter itself provides. The 'factory' attribute specifies the + callable object that creates particular adapters. The adapter can be + used with any component that provides the 'for' interface. In this + example, we pass the Adapter's class as the factory. Adapters are like + presentation components in that they are context-dependent and must be + registered with a callable object that creates a component for a given + context. The 'permission' attribute in the adapter directive specifies the id of the permission required to use the attribute. - We'll update the Contact info view to use the adapter. First, we'll - create a new class, 'ContactInfoView', in 'ContactInfoView.py'. This - class provides a contructor that saves the request and response and - gets and saves the new adapter. It gets the adapter by calling - 'Zope.ComponentArchitecture.getAdapter'. It provides 'city' and - 'state' methods that call the adapter. + We would like to update the Contact's info.html view to display the + contact's city and state, using the new ContactCityState adapter. + First, we'll create a new class, 'ContactInfoView', in + 'ContactInfoView.py'. This class provides a contructor that saves + the request and response, and gets and saves the new adapter. It + gets the adapter by calling 'Zope.ComponentArchitecture.getAdapter'. + It provides 'city' and 'state' methods that call the adapter. The info template, 'info.pt' is updated to use these methods. Notice - that the methods are invoked on the view, not on the context. + that the methods are invoked on the view, not on the context. For + example, 'tal:content="view/city"', as compared to + 'tal:content="context/name"'. - Finally, we need to update the configuratrion file to use the new + Finally, we need to update the configuration file to use the new view class. We still have a view with one page, so we can still use - the simple form of the view directive. We simply provide an - additional attribute, 'class', that specified the new class, + the simple form of the view directive. We just provide an + additional attribute, 'class', that specifies the new class, 'ContactInfoView'. The class is used as a base class for the - generated view component. - + generated view component. From jim at zope.com Thu Jun 20 16:24:27 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - configure.zcml:1.3 Message-ID: <200206202024.g5KKORa30276@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv30252 Modified Files: configure.zcml Log Message: Updated to use add menu. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/configure.zcml 1.2 => 1.3 === xmlns='http://namespaces.zope.org/zope' - xmlns:security='http://namespaces.zope.org/security' - xmlns:zmi='http://namespaces.zope.org/zmi' xmlns:browser='http://namespaces.zope.org/browser'> - - - - + + - - - - + + + + - + - + Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6 In directory cvs.zope.org:/tmp/cvs-serv31262 Removed Files: Contact.py Contact.zcml ContactCityState.py ContactEditView.py ContactInfoView.py IContact.py IContactEdit.py IContactInfo.py IPostal.py README.txt __init__.py contact.gif contact_product_uml.txt edit.pt info.pt products.zcml stubpostal.py Log Message: starting over with step 6 === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/Contact.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/Contact.zcml === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/ContactCityState.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/ContactEditView.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/ContactInfoView.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/IContact.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/IContactEdit.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/IContactInfo.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/IPostal.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/README.txt === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/__init__.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/contact.gif === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/contact_product_uml.txt === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/edit.pt === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/info.pt === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/products.zcml === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/stubpostal.py === From jim at zope.com Thu Jun 20 16:53:50 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 - ContactCityState.py:1.6 ContactInfoView.py:1.4 Message-ID: <200206202053.g5KKroC05989@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5 In directory cvs.zope.org:/tmp/cvs-serv5537 Modified Files: ContactCityState.py ContactInfoView.py Log Message: Fixed some import bugs that were hidden from me by old .pyc files. :( === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactCityState.py 1.5 => 1.6 === -from IContactInfo import IContactInfo +from IContact import IContactInfo from Zope.ComponentArchitecture import getUtility class ContactCityState: === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step5/ContactInfoView.py 1.3 => 1.4 === -from IContactInfo import IContactInfo +from IContact import IContactInfo from IPostal import IPostalInfo class ContactInfoView: From jim at zope.com Thu Jun 20 17:49:29 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6 - Contact.py:1.3 ContactAddView.py:1.1 ContactCityState.py:1.3 ContactEditView.py:1.3 ContactInfoView.py:1.3 IContact.py:1.4 IPostal.py:1.3 __init__.py:1.3 add.pt:1.1 configure.zcml:1.1 contact.gif:1.3 contact_product_uml.txt:1.3 edit.pt:1.4 info.pt:1.4 products.zcml:1.3 stubpostal.py:1.3 Message-ID: <200206202149.g5KLnTX20821@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6 In directory cvs.zope.org:/tmp/cvs-serv20792 Added Files: Contact.py ContactAddView.py ContactCityState.py ContactEditView.py ContactInfoView.py IContact.py IPostal.py __init__.py add.pt configure.zcml contact.gif contact_product_uml.txt edit.pt info.pt products.zcml stubpostal.py Log Message: New step 6 with a contact add interface. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/Contact.py 1.2 => 1.3 === +import Persistence +from IContact import IContact + +class Contact (Persistence.Persistent): + """Personal contact information + + Contacts keep track of personal data, such as name, email + and postal address. All methods are protected. + """ + + __implements__ = IContact + + def __init__(self, first='', last='', email='', address='', pc=''): + self.update(first, last, email, address, pc) + + def name(self): + return "%s %s" % (self._first, self._last) + + def first(self): + return self._first + + def last(self): + return self._last + + def email(self): + return self._email + + def address(self): + return self._address + + def postal_code(self): + return self._pc + + def update(self, first=None, last=None, email=None, address=None, pc=None): + if first is not None: + self._first = first + if last is not None: + self._last = last + if email is not None: + self._email = email + if address is not None: + self._address = address + if pc is not None: + self._pc = pc + === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/ContactAddView.py === from Zope.Publisher.Browser.BrowserView import BrowserView from IContact import IContact from Zope.App.OFS.Container.IAdding import IAdding from Contact import Contact class ContactAddView(BrowserView): "Provide a user interface for adding a contact" # Assert that we can only be applied to IContact __used_for__ = IAdding # action method def action(self, first, last, email, address, pc): "Add a contact" contact = Contact() contact.update(first, last, email, address, pc) self.context.add(contact) self.request.response.redirect(self.context.nextURL()) === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/ContactCityState.py 1.2 => 1.3 === +from IContact import IContactInfo +from Zope.ComponentArchitecture import getUtility + +class ContactCityState: + "Provide access to city and state information for a contact" + + __implements__ = IPostalInfo + + __used_for__ = IContactInfo + + def __init__(self, contact): + self._contact = contact + lookup = getUtility(contact, IPostalLookup) + info = lookup.lookup(contact.postal_code()) + if info is None: + self._city, self._state = '', '' + else: + self._city, self._state = info.city(), info.state() + + def city(self): return self._city + + def state(self): return self._state + === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/ContactEditView.py 1.2 => 1.3 === +from IContact import IContact + +class ContactEditView(BrowserView): + "Provide a user interface for editing a contact" + + # Assert that we can only be applied to IContact + __used_for__ = IContact + + # action method + def action(self, first, last, email, address, pc): + "Edit a contact" + self.context.update(first, last, email, address, pc) + self.request.response.redirect('.') === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/ContactInfoView.py 1.2 => 1.3 === +from IContact import IContactInfo +from IPostal import IPostalInfo + +class ContactInfoView: + """Provide an interface for viewing a contact + """ + + __used_for__ = IContactInfo + + def __init__(self, context, request): + self.context = context + self.request = request + + self.info = getAdapter(context, IPostalInfo) + + def city(self): + return self.info.city() + + def state(self): + return self.info.state() + === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/IContact.py 1.3 => 1.4 === + +class IContactInfo(Interface): + "Provides access to basic contact information." + + def first(): "Get the first name" + def last(): "Get the last name" + def email(): "Get the electronic mail address" + def address(): "Get the postal address" + def postal_code(): "Get the postal code" + + def name(): + """Gets the contact name. + + The contact name is the first and last name""" + +class IContact(IContactInfo): + "Provides the ability to change contact information." + + def update(first, last, email, address, pc): + """Modifies contact data + + 'None' values are ignored. + """ === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/IPostal.py 1.2 => 1.3 === +from Interface import Interface + +class IPostalInfo(Interface): + "Provide information for postal codes" + + def city(): + """Return the city associated with the postal code. + + An empty string is returned if the city is unknown. + """ + + def state(): + """Return the state associated with the postal code. + + An empty string is returned if the state is unknown. + """ + +class IPostalLookup(Interface): + "Provide postal code lookup" + + def lookup(postal_code): + """Lookup information for a postal code. + + An IPostalInfo is returned if the postal code is known. None is + returned otherwise. + """ + === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/__init__.py 1.2 => 1.3 === === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/add.pt === Edit contact
Enter the information about the contact.
First name
Last name
Email
Address
Postal Code
=== Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/configure.zcml === === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/contact.gif 1.2 => 1.3 === === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/contact_product_uml.txt 1.2 => 1.3 === + <> + ---------- + | Lookup | + ---------- + | + o IPostalLookup + o IPostalInfo ^ + | : + <> : + -------------------- : + | ContactCityState |- - - - + + -------------------- + : + : + : + : <> + v IContactInfo ------------------- + o<- - - - - - - - - - - - - - - - - - -| ContactInfoView | + ^ --------^---------- + : V + : | + : | <> + : <> ----------- + : ----------- | info.pt | + : | edit.pt | ----------- + : ----------- + : | + : ^ <> + : IContact --------V---------- + o<- - - - - - -| ContactEditView | + | ------------------- + | + ----------- + | Contact | + ----------- + + +Key: + + o Interface (catalysis style) + + ^ + V Aggregation + + + <- - - + Dependency + : + + + o<- - -o Interface B specializes interface A + A B + + + <> Stereotype + + -------- + | name | Class + -------- + === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/edit.pt 1.3 => 1.4 === +Edit contact + +
+Enter the information about the contact. +
+ + + + + + + + + + + + + + + + + +
First name
Last name
Email
Address + +
Postal Code +
+ +
=== Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/info.pt 1.3 => 1.4 === +Contact Information + +
+ + + + + + + + + + + + + + + + + + + + +
Contact information
Name:First + Last
Address:Mailing address here
Email:foo@bar.com
City:City
State:State
+
=== Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/products.zcml 1.2 => 1.3 === + xmlns='http://namespaces.zope.org/zope' + xmlns:security='http://namespaces.zope.org/security' + xmlns:zmi='http://namespaces.zope.org/zmi' + xmlns:browser='http://namespaces.zope.org/browser' +> + + + + === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step6/stubpostal.py 1.2 => 1.3 === +from IPostal import IPostalLookup, IPostalInfo + +class Info: + + __implements__ = IPostalInfo + + def __init__(self, city, state): + self._city, self._state = city, state + + def city(self): return self._city + + def state(self): return self._state + +class Lookup: + + __implements__ = IPostalLookup + + _data = { + '22401': ('Fredericksburg', 'Virginia'), + '44870': ('Sandusky', 'Ohio'), + '90051': ('Los Angeles', 'California'), + } + + def lookup(self, postal_code): + data = self._data.get(postal_code) + if data: return Info(*data) From jim at zope.com Thu Jun 20 18:33:53 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step1 - configure.zcml:1.1 Contact.zcml:NONE Message-ID: <200206202233.g5KMXrn00454@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step1 In directory cvs.zope.org:/tmp/cvs-serv446 Added Files: configure.zcml Removed Files: Contact.zcml Log Message: Updated to work with current Zope 3 === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step1/configure.zcml === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step1/Contact.zcml === From jim at zope.com Thu Jun 20 18:45:35 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2 - configure.zcml:1.1 info.pt:1.1 products.zcml:1.2 Contact.zcml:NONE Message-ID: <200206202245.g5KMjZs03390@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2 In directory cvs.zope.org:/tmp/cvs-serv3381 Modified Files: products.zcml Added Files: configure.zcml info.pt Removed Files: Contact.zcml Log Message: Updated to work with current Zope 3 === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2/configure.zcml === === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2/info.pt === Contact Information
Contact information
Name: First Last
Address: Address here
Email foo@bar.com
=== Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2/products.zcml 1.1 => 1.2 === xmlns='http://namespaces.zope.org/zope' - xmlns:security='http://namespaces.zope.org/security' - xmlns:zmi='http://namespaces.zope.org/zmi' xmlns:browser='http://namespaces.zope.org/browser' > === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2/Contact.zcml === From jim at zope.com Thu Jun 20 18:57:16 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2 - view.pt:NONE Message-ID: <200206202257.g5KMvGG06089@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2 In directory cvs.zope.org:/tmp/cvs-serv6083 Removed Files: view.pt Log Message: Updated to work with current Zope 3 === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step2/view.pt === From jim at zope.com Thu Jun 20 19:11:37 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3 - IContact.py:1.1 configure.zcml:1.1 info.pt:1.1 Contact.py:1.3 Contact.zcml:NONE ContactViewPresentation.py:NONE IContactInfo.py:NONE view.pt:NONE Message-ID: <200206202311.g5KNBbc10171@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3 In directory cvs.zope.org:/tmp/cvs-serv10161 Modified Files: Contact.py Added Files: IContact.py configure.zcml info.pt Removed Files: Contact.zcml ContactViewPresentation.py IContactInfo.py view.pt Log Message: updated to work with current zope 3 === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/IContact.py === from Interface import Interface class IContactInfo(Interface): "Provides access to basic contact information." def first(): "Get the first name" def last(): "Get the last name" def email(): "Get the electronic mail address" def address(): "Get the postal address" def postal_code(): "Get the postal code" def name(): """Gets the contact name. The contact name is the first and last name""" class IContact(IContactInfo): "Provides the ability to change contact information." def update(first, last, email, address, pc): """Modifies contact data 'None' values are ignored. """ === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/configure.zcml === === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/info.pt === Contact Information
Contact information
Name: First Last
Address: Mailing address here
Email foo@bar.com
=== Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/Contact.py 1.2 => 1.3 === import Persistence +from IContact import IContact class Contact (Persistence.Persistent): - """Contacts keep track of personal data, such as name, email - and postal address. All methods are protected.""" + """Personal contact information + + Contacts keep track of personal data, such as name, email + and postal address. All methods are protected. + """ + + __implements__ = IContact def __init__(self, first='', last='', email='', address='', pc=''): self.update(first, last, email, address, pc) === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/Contact.zcml === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/ContactViewPresentation.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/IContactInfo.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step3/view.pt === From jim at zope.com Fri Jun 21 04:48:33 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4 - ContactEditView.py:1.1 configure.zcml:1.1 info.pt:1.1 Contact.py:1.3 Contact.zcml:1.4 IContact.py:1.3 edit.pt:1.4 products.zcml:1.2 ContactEditPresentation.py:NONE ContactViewPresentation.py:NONE IContactEdit.py:NONE IContactInfo.py:NONE view.pt:NONE Message-ID: <200206210848.g5L8mXg26335@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4 In directory cvs.zope.org:/tmp/cvs-serv26321 Modified Files: Contact.py Contact.zcml IContact.py edit.pt products.zcml Added Files: ContactEditView.py configure.zcml info.pt Removed Files: ContactEditPresentation.py ContactViewPresentation.py IContactEdit.py IContactInfo.py view.pt Log Message: Updated to work with current versionof Zope 3 === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/ContactEditView.py === from Zope.Publisher.Browser.BrowserView import BrowserView from IContact import IContact class ContactEditView(BrowserView): "Provide a user interface for editing a contact" # Assert that we can only be applied to IContact __used_for__ = IContact # action method def action(self, first, last, email, address, pc): "Edit a contact" self.context.update(first, last, email, address, pc) self.request.response.redirect('.') === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/configure.zcml === === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/info.pt === Contact Information
Contact information
Name: First Last
Address: Mailing address here
Email foo@bar.com
=== Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/Contact.py 1.2 => 1.3 === import Persistence +from IContact import IContact class Contact (Persistence.Persistent): - """Contacts keep track of personal data, such as name, email - and postal address. All methods are protected.""" + """Personal contact information + + Contacts keep track of personal data, such as name, email + and postal address. All methods are protected. + """ + + __implements__ = IContact def __init__(self, first='', last='', email='', address='', pc=''): self.update(first, last, email, address, pc) === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/Contact.zcml 1.3 => 1.4 === + + xmlns:browser='http://namespaces.zope.org/browser'> - - - - + + + + - + - + - - - - + + + + + - - - + - - + - + - === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/IContact.py 1.2 => 1.3 === +from Interface import Interface -# Local Package imports -from Contact import Contact +class IContactInfo(Interface): + "Provides access to basic contact information." -class IContact(Interface): - "Marker for objects that provide specific behavior" + def first(): "Get the first name" + def last(): "Get the last name" + def email(): "Get the electronic mail address" + def address(): "Get the postal address" + def postal_code(): "Get the postal code" -implements(Contact, IContact) + def name(): + """Gets the contact name. + + The contact name is the first and last name""" + +class IContact(IContactInfo): + "Provides the ability to change contact information." + + def update(first, last, email, address, pc): + """Modifies contact data + + 'None' values are ignored. + """ === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/edit.pt 1.3 => 1.4 === + Edit contact
Enter the information about the contact. -
+ + tal:attributes="value context/first" /> + tal:attributes="value context/last" /> + tal:attributes="value context/email" />
First name
Last name
Email
Address + tal:content="context/address">
Postal Code + tal:attributes="value context/postal_code" />
=== Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/products.zcml 1.1 => 1.2 === > - + === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/ContactEditPresentation.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/ContactViewPresentation.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/IContactEdit.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/IContactInfo.py === === Removed File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/Step4/view.pt === From jim at zope.com Fri Jun 21 05:20:53 2002 From: jim at zope.com (Jim Fulton) Date: Sun Aug 10 16:40:36 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.13 Message-ID: <200206210920.g5L9Krd02173@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv2081 Modified Files: slides.sxi Log Message: Updated to work with current version of Zope. Added Steve's original step 6 material to step 5. Added a step 5 on creating custom add views. === Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi 1.12 => 1.13 === From steve at cat-box.net Mon Jun 10 09:02:55 2002 From: steve at cat-box.net (Steve Alexander) Date: Sun Aug 10 16:40:37 2008 Subject: [Zope-book] CVS: Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 - slides.sxi:1.1 Message-ID: <200206101302.g5AD2t132664@cvs.baymountain.com> Update of /cvs-repository/Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1 In directory cvs.zope.org:/tmp/cvs-serv32530 Added Files: slides.sxi Log Message: added OpenOffice 1.0 version of the slides. This will be the canonical version of the slides. Note: I need to find out whether the Luxi fonts are a standard part of OpenOffice, and change the fonts to standard ones otherwise. === Added File Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter1/slides.sxi === PK h,&mm-Pictures/10000000000000F5000001094AB61EAF.gifGIF89a eb, ڋ޼H扦ʶ L= $ oLI*J)7`%vgto^rؗhgw5XxIv((g YYzE I9:)ji*k:뫡#v5,H;:l!,=M}=m >'N~dn?#Ob/< …2|!ĉ $Rhb';z2dGa"KX^Gd|}.3X7YoUf&!a`{ "ŕۣ"H emi\ JJjz)dJdb7Us۠ie]Gq:z끏,%񑭼 ©NK&6gx{l~j~.rbqo -;+ R밿/TKq ò̎ƦpǥȘ|ɗLʉ.>0g,sl38<Ϧ-t8EDш$}DpJtWcmYA]+a_SF[6gSog3qܭ7|- ^OE^ڌWN}1J$U>-S+܊p-P:nŒx^kL.z&njX֮D[ymOy|4_js4u@f8GgNr*3x;<@ HLX鸂 =2ϥC a,;ެ;!R}0IENDB`PK h,i-i-i-Pictures/10000000000002D00000021CC3C53A0F.jpgJFIFddDuckyPAdobed          !1AQ"SaqѓT 2Bb#WR҄3$Urt%uv8XcsD5E671!AQSaqRT"2B#b3r4 ?qaġgNDy8EC0!d#(ReNFPd'ʟ!d!(C)d!(B2KYʝ/yd!*tBYʝ/yl!*l同Yʝ/yl!*t同BJYʝ/yl!*tB2YJ 同B2!d#(2weBFP'$7NEy(aw ING֞7}BlY7cq%NCYaJ֥ZQ#Q}n,qxY{vȍM\$s&{Q;UT@=W(+eU 7K_{U*jh[$*"֢jc,}yu,ޡtF_V5WDb5ʪvl Oۼs+dXoZܞWm^٩]t]P qqxlKL [6&˱[CE|_br.{Uô ~6hFnN}׭kяӕH:tjy42ŸMty]+N*HLNkU CZ]mv+uerZm:{ҺfSA~*jwBP%뇤V-ztqc._3CK!,Y&=)/ݓXn 砽Zj+=M|YSq:jr9qk!URY9V7Tȋ[QX]XS=?15隣RWƕ6ްȬDkQU܍]0NAhلA|٥=mCы+Xk$jNjt}`t])lM*nuHeL cQ\EWq3Mgz! T=n5Jf$Z+ਫ਼tE9dU_jQrN(ULƗn8^X%s쎓b:inVf]#b"T *(fpbyY.U<[劶IKY$kZկ _CiknT+eduTP٠ZdVjm8™Zygm=]Lo:^+_J"G;H=uWMS1S*ns^{c5uEE⊊ЮX}꟧~v^jm'L䒞GE4ODg1VU94}s-:{7_N3>8br>zt6y]nfQ[j%2W5:9\M8n&"f1=S1\ʈ^TDU{CjKJSi7 ‘ʨ#dӂ·TS]SםᗢpZ])~sBڲ5]FMQ,Nw#v;E7,ޢcDǢqQ]QT`噶%6 WGm["DY\WETB˗赆c8Gm^;1 Ľ)t1^Abnj\'mKwII:8E5DDtᥞj*):RFTK! S,eO>BFP$,%NENFP$' 7NDy8E䡉Eq8EĘt;>-du7,߮6>;e}ƆzvHIX1j5SUDt]Cٱ+=Fԡcڦΰ?ҪO#v T6868ixY*oW]jf""K:5Q?i"}0bbVZH }bW\i54s%Uɣ^ekPj%˼X}mnma}LInMy٣ ;^~]5gX1M[S㩥CXv{Q}_[U =,/k%>+ދ5UFU {/허zjGommv~RV9`ԲѫWƴ誊+uk-7CSvmq|2r뽞S$o+dD]9UQtr{sڦ#m8NQ%芇M+<:W̯su+}Azp&*2zlS\4U1jyTTEE O1-LCs2u 5 }f6βI׵%VY$G=ʾ'e2᷶nNQ5U*j$>%*Q"2;ޓt]u Sn]'YeWO[lbWmZx9u,j+dM{QFߨvn8p[n al&'卭F#]KnMN--Eu۶v=kOOMKK۴\j[n|2GK,ꑹpg"$MLw0Zk-p-`lճ25j,9MUtN$z?cu6 _d魔YFb{imddrg23Lׄi#'OGWέw͠]:p 뭱qobNR*F3Y|V.1^vbcgҍqyGTɼC҇K[io&CqY9.4t:_ye'Hs/1M%437O6mNU,42dPR2\[α9DbW>nV7'jݫQDa +j;'k0uMۭ UbrU h䙎W=;$o/-Y{1O$vvgB#r WsL*F*誘fcѺMxWck-Ss鼛t٬Y bsz}(M btU:DDFiyۗ-8UjSWy΃ptvˬP٫쨣|I5r*Ƚ:.*EJ\λ!w)NEyV6Z$ZFQΪ]S)Vv*=<ьHO/2Tܬ eiȋf]˔e6QUk0i|/[!Jz,hϫgn[N}.]ƩklE;x_Q?M+]-ᖌ@ɣ|YbxmI "xXD_zZ:Zprr6Wҡu0w7RW="G1܉2*/)iŻ1UGghbӞK/M"۳{KdUr Sgp{EE_7v'=ן+4OOT婮։nuﺿ!ryr??^߇*t2JYJ)d#*|IYNA7e Cy8bQNW^NGq(aL?r?0>ztU[eDfZ"#O+;khl^U@/?:ݜۺܨe.תwunJetOPx:;z_id[.iGPuaU9dfSeb14JN.5UD:|[z:aڛMQxqn1"zx7+U3)dljbL$&]=7aZXejKp F|Iyck _y=C2I-MDz,2+d%*Jس2gOđ~:dܞotsݞ\7% IRARogz2i9՚ώocTv;%Z#2#1N֢"_3se"lM4;u5[ЧM[/8s0%Ĭ[ƱZXhh+հG+ZUT u_~ܮn$ h3:(]#i ֺg/pцc[~V++]Ǚ[s|ZŶ:zV#=Q9s d=]wZ*PU1A5}Sb|΂9D7=ZUj"ZN«gP8VXΤ3aejTܧc2k, "zZ+ D⬖=N"wp31x1.s[Dtk>MuqXNU=ӲySJG9|tz_[ٖ*ڿnzGܩWnfՔזXg]G5ʜ _b;:0Nh&xF4RWTSHI~34_wEc!T27ڤ;=kgE\G=UM,\9Vf4UЕ a17n_1;sh9jkZ*)EQTc z -}}۵lv6M9.{6.?L-RQWTx){l ᫜G^GiNn(畖iƬz%N\65M`e6/3c69esQ{ԍ62mՍ^;;=uz +gq[8ovQS2Zȵk9+ښ?+Tz#]v1f*Ɖm׾s٩wzl J]_RFOM$z7cVk?T֦3F6 9bv˱}/Deoxbfbm9_ HG,j&kelMf۷{|2ȑUEG,gݱo5ۛvrNJDO9L٫ m3vdY7(_+*}jKLoDQMQ)soglv0OoK1bv+VmRS?*tҖKYʟ'yd#*|HYJHN !ABy8E7QJEy8aGq& ING֘KRnÿfVj:Z-= tqHXA-,܊9^<]E6 Ku_9QM{<Q(i؏Zskp˱;c';jZ>VGPrGHOP baieհM.aԙ]kd+ᬡFPB5vK XctEkƸ]JxJ"u:ӥ:im\~TibOI9.3u.3GXKx撦f&-]d|jn֢YLD!3߫lwꋩin b)ҭFZrJ:(1ʼnLa.v fYj+UIWcG[IclE_ 5ob^SDUan_J{m]gW<> N'~ZU[;ޔW3^ԔۊǙE_ @-Yc)o6k?}ƮK"[}Uar2D'C'#ܯ]E6昪&'LNͶh=ãpeMl,L;IըꌵlӳNɹ8v7܋+&zTcrTxpThՎG^)Z.WMs SzicDkl J]li,OD]Z/sUZZ***uۦ;5F1*iibp4:SqJZVۙ㳹1fD(9Wx [IU$JVnh(c'U4Ft;Q][{ew4r]3+LG?sTL^5ߩZ;Ty7܌'GG275UnBN)[)z+7"l^QzilǮQvxs SvK/Cw7hMcTS9*y)g*rfdmU~~z}#1\[W짡 iS,eM:^FT{!S,%NFP$,eBpHY"!8a Dy8E! 䡄WQIC0N2;C' #<#(' J#(RNA#(2B2!8FT !@@>RFT{!S,%M:^BT{!S-eM6RBT{!S-%N:^BTKaS,%N>^FT ! A>BFP$,eBpY#(o''0p;Caӑ:ft<0PĢ"pD0'Bp@A#(B2Y IYʟ)d#*|同ҖB[ʝ/yd!*|ҖYʛ/yl!*t同IYʝ/yd!*t2JYJ!d#*|Yʟ!d#(wB2!8FPd,PNCy8ENpĢ<"P+($áݤ~S#ջןUʉ]^?{vЯTƽ~pW^~ݿ8+p?ynߜ׸o} Ak[>z5-BP^?{vЯTƽ~pЯTƽ~pW^vϡ>Y%sџ~]83?BM;cwS?\jzL!Ժ&vOI8u*ŝ/CtqWI؎׷x3hn.gn6cv ˎcf:W`^k鞳b:@=F/nf{gاz~){wc4_/C:fn_,gO\?WWt%{qaNq^^Wϊz莧׷swqa7~);:#zp̹]\>T듺:W^G^듹Ꭷ}׷qq_~nW\czgEL\W]rw|po]~rW\ſ:zaum]~vWjuſ:z^rUk[%]cW^$_֕(g%]|:zXe%gY3>%}|:zU5reY|3ڝl|q^{s<YU\yků:ϕS+~/na~_53Y>VOT8IuXU\yků:[?=P%nwUs>gkUK?=PGUoK3~5})g৪WM^ܚ۪gs5}'c৪W^ܒj<9\US?S^܊*?gͳ5Zϓ+nAu_uov|nJ߮|;խS}^Oange:{1k! z>qv|_çS=^9x;uk>G/ٍN?S^۵9ng:{1/׶_oϝg{jq:uv|_çRo;EZϐxtvcSU+>:_ϝnge:;1)/ng:;1? /V2[lm  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m  /V2m ! ! 5lY*bOX4d[ڑ9eXo! Zy5ZMPz+_||V{M|3޹zyԟ^맷{S~p]S=Hy_} ^ԾI kͽuzҍ헞umͷxiG#]|FwFnޛsr4glբ_uj:jw jETNDf*ВEkZrZ^׫o?T&ʏ![]k6H({;WPUUjǛwsuG$a x~i?jѯX/WN> F1(?,2wl/Zh$xk(kSx/:|d8FD^E~6+EZ}5C%E/~3̪Tj[n%|.Nv0b ΰ3\vːchŶ=\Q2jNӎ<]{vW,tOm_m_ KKnxɲuJʪu9^}S?ncӍs$[`=Hc{gnղ1F*'c<b{Sjz—7x']pj]WEM̪S웿uQ3X/&*j h']klUnydTk#6"r;U2ޜ)km@ۥtj6hz4lb{uO_4j;D]ZاͷUT#O6z~#\l[o6+dl:++QȮ5ǝ^^dENDM;_g>v,hpʹs,/sUcݫS6&nIVOX}UE+&TDZT'HkUrYPZؕ.CSSvO?1To ~( l}mj;Fr9GՖUEi)܍UUD*K=Ln;/1ֿhwjO)xj*/*}Ϲi>;_;7M[ME5 ːإDLzY#XeKxncj#1͏xv L&-E D]]Qoz9罱{W-{:\{pWn&|Jz* ӃبEN㽷v3p`W;?tWQ5Q&jc]g9nhLLJf5ET viYdMb!k W "~e~?S|Cwu[v߶_7f55rWjeɽz:ٷgkXXO'zò9\\ޔاf-8y%(]..yܪ5,h=];9;"+e=T<d鈞sѱDliZQMCjQzO^i_[M*=9UW]HӚݷv)jD=3蟸,ژ¾2jV)j$dǵS+UQJ٦3MQO"tW40J]N%fsP,˻DAzHo4z"x>B~bjg>fmjcWQ{CM$ךT_J6=4M?}:nܕgy;?j02OܲU;w[܈}+/DQLhpv[sZTj'jbgJc.g]r6eUDDFF^[/kVrwn$2G Hg ۻ\"%-ZiZu-9c9 طn1}{V8z_XٞRs7ZǭeTj5N_50޽O^`=:bSW\^T*^TA-\}-"\vߣu_}:J g&[%OrzZUUښ,Sܫcا)j?lu/vmEum%k_-Ҋ7jT+"^PY2 k]%<11ADBg<"C(>-YQfU*Tu0I<2TծjC1T;+&{CxrX}X$-5v|6h4Ske3>(fW6]z$OǻUj.?vzZJ.heF;%wOq=hYFwLkbyRO+YUr+(r3f?g:*9(\ۭ9)6ڊtTZkbkW:ukէ2j!N.S6N[ܹonth@zZy**#5ij}%E\Lc,UTS s eU+bNQ{5jqDkx>k Rs_Yj? pk*&m4UVtTeS[stQLb39^Vz0tTTKr+MS3M3T Cwk0+KOːfĨ笛?EW5U}Ù\Wrcl{껣F9̶˅5i)[hYf:":(b;o6SSFU0c{tU+}}:l<ߖD8VEdEDTQ}~n45sSS2jr|udYwQxYxj(oݛR޽¶W5t{5"k^s(Z=Otzޖwc{ee8m֫M4Tv};8`QFֱDDN>USTΙ}""0 n6[mo_jh芊^:{ݧwEQG'KO5jV<ԾԊƬUj"/A>xNR"n|ܽ8S CWQ+E=uUUT)!LˤqsW9QNS8 v5خYW,(7ElQ7UDN<{z_#O,<컘Hme: |nI39fn+ ~DVz2V+UrƨD׊9ɘviKkVceuhhi|,D`ڍdqFj"""hrU5N3DF77nn a75it U37T]D]SWQz4\sŒ^Ūο &G7S?[d-/K-CEn\'] eHw!;tMuE1gjf&g󣸵Ww)jүjx,S>_jG4=H)rn$E{!6խUSlWTtKku[bz_KGHw/uqO_wjъ(ȋʧ7UȦjfeƭ-6o_P6ܪaedZQTb*舉!mörDN?NF7*t(ۅҖƬWK#SHkSb![ӵ\՚N7zzg+Mncs#E飩af+]<=ZvL~>[ݻ)«b7-#eDZ<)EGlOq8^.s\\|ʮU5U8̺j(#!pHclmf.=Vʨon7f?Ok}ϝ܅Uu_Oy/VrS{;D^H+ng5 EK~%6r})1Cn6WgtQKzV*CU8*{/wr0Œ>w;ur-ɼZWCN*k}uYqM1yc2iS3(z|&o=BC! QA̍uEdCUȊ/jSW*"Q33r[bHn'ݛ3̪"M64-x׵w_N3=;f65_Ʀ~3wkSZ9Psn |5>SV_>asK:C8zyezFKh|5>!q39 ǾNw;gڻ-LԲKVp?tp"f?+;Ɯ>j.z$IE Ulny;qEs9ՍKk4SfzGW9ˢ"1 L-qzuEagK"sjW{C %VN:Tc{ݮp|AemnU_$77'C;Mukn-EeB4rs[>O׷rqef٦0z M@7g\mtofDRtU*SEQtW9~|_rϿ7]2*3E9.z#Wk}}ջ*jG.T]~<7={DGhgǝm~#$΂'9WDUU׽Ono'j(=fj^ԬkO\m/Ut4x#ZUJ3,S\ -Z 韡6qw斲ˇèŶٮZzs#{jhؚ#W1DEުm؞N^gwf妈۸EoPQT4eS[cl0Ci㍈kZ"&jgK!0 󹼖UǷ'1.[zt[5)nb}g^{YQlJ*UPS^z+U;UDĪױr'7JqS`sk/yUӂj9*;ӎi}64'Fuܼy%2#D_EʜDDNw#b"#㝫1rz{8uwͪ"ﳶab<һUx"jyzZQ5W-RaL6Cͺq7)2k=v%EՋ*"MP"+W:k~q%SnFZ1Z 9i{L=zdnJ<Š Rr5fM;cw=w1,sQsɢӴ0x0ʼ\mf8ݽhkeW*r1<|%! lf&9*c{7חO= sEs&3}3V@ly'y?ʯlG]ܪx :/%tLB{$Mw_ .[=q侈n_iO?Tƣ':[:flŧqzQj]}܉XEfOU?bqĔ+=xr.[N78 hΘ\ɷ9uk4׫sQVhzڙ-Myy5p~v'D{u6#}؟.J^6r^dtV"{֯ձιikj̞&sN9n?ܶ7_ziZ̉v^(~ʍᖢ<orenyаMͲH߽PbJm\ȞD z!}4Yuӳtdcomo*m2;Si޼tF\sGGS }kM>[OȨEEODdW5ܮOut+TLF)Q32ѷS7ugkZxs&f{U^j CΕ6(uۛusS/4OGHB8-:bz bӶbaY{EU1=ʽ"-g.źtϢZvTy#UjVXN'ր<-5LLv:9=M5uEEEQLN0-M[+]iWW4NJ\PH+&vuO)kp[vZ?}1"躝gHL;ۜέ]gT%wgʫy^?ʯWpg)͈G,|qrn{'G)hdl|RQs\QSOLLNqs0#VVS[gԴY'ZU%E\43,UTSSXO;vD*W9zq^<{C<%Ób;eoN:VGh֢Ss1Lc.j#}:_Y qLF^iV5<¨$jPnSQ} sz/4W6mSyvR5jk VDTh"sp^_nMgyY^xh|?+riG7a+zI\=Z83˦+5sGtIҩ׌ycNwp9oXW}=}160sl~w6Kj.TkM{JJgMSQx*/^ /عb3MQ%[MbgX0ՎMrGGK UUTErkR+TSDc(\MƩj˨}dX(rIQWU;WN>|'p{Kޛn~J45QQ$KSS*GY^U{UOE1s8z{&c*txmj,DVKG@4|jN쉪wc_GӗmZjWn7gncboY?D_D7=}W{/OҼs~grv\A_9ts=ӏJ?h[:sOtݭxcȝ __GRs:0LN߷u{M4ӓื{ۇOoގ|t?C^xm _OKj|~14;h]. "{gT~𽷑}NFpGU?N>QO>|x_{>ž]?cˣ׃kϯۯ}soonG'"{G95o'뼍}a?Cm5ï;_?)1,{㷏.?nCv6#c?PK h,g-Pictures/1000000000000073000000814BB651D8.pngPNG  IHDRs|{gAMA abKGD pHYs  ~tIMEoקTIDATx[ ETV:d;|0TcH"|t͸hyY9EA(h͢Y4©W6t4;׵,O>GɃ\%EI|֤gXU}kil6EA(hE >g6K@6lӏUſ0Bsˈ:e%>[%/#f * cּw?l_Fc@M*zD< dwfe|d7~:nfPg=ӡn P, EA(h͢z׳p=k͢Y4fQ, EA(h͢Y4.5 G4fQ, EA(h͢Y4fQ7b+IENDB`PK h,-Pictures/1000000000000072000000BC35CAD488.pngPNG  IHDRr+]mgAMA abKGD pHYs  ~tIME02\nA?3 F#)5WZx."XR[M]OVz {)k]nge_xXj@BV MBV Z!Xz@עV Z!P+j`BImbB2cӛ&9|aE땘2xE-5Z-/2aSvmVa0L+7z&*RNքE N{ 'lU]^ִ>MҀ$BV Z!P+j@WZzuWw^WS^kOW-L0J+sHAyZ鍰*ڹ utlH>~印z㥐?d#lulHsقE7.` ] IaZfw[Z÷Xv [bBV Z!P+j@BV '%h~;IENDB`PK h,PP-Pictures/10000000000002D00000021C3D8DD9F5.jpgJFIFddDuckyPAdobed          !1AQRSTaq"2Ubr#B3c4Dt&6W s$Eu7G!Q1Aaq"2RrSB#45b3sC$ ?qO9i9UŻU3V>kKWc#LS 31j|u9yxƹYWm34ѝMt-iW߲"*W荑5Ljg TSt]^V']|Ex!F^0};}ltYۜ>shz^oڊ.]'ES+o^Nײ)JNg?u}ݢ}x hʊ U#f#<Ӈʍk7j~),xW}iȹ1LXkغΑ#kLňvtd39O۹vg3[>݋{6ĹMUU31v&;]vv+il4WMq377O=Wg?jh+3zb'޳9z 6[/s j壳NڽO%w 99.[ɪo;]3[M˷kz)>9:ckNf)jjHîgdy|W9nWo(lgE!wvȳu~oJ↱UjьNΦZg#k/Xܦ{wKbݺv}? eAoW6z5s]uGnQ+?=Il>ݸ!v,G߶ܚhM7(νCg2ӎ_31N5v.k$~Kן2x_3N<-tS{cxTyqې2YO+=rG8cco^jה&foݧ)v3xkϵϵg fp{WØ{Wmjh3/E6lǹwZ?{0=Rws V"iLtں.UUm3=X=p%LbYgb8LqUkEy?JEtַVFf'hL۫eQ>wYKTrs{Ws`oTdۥ21/FF4WTy'tk*18N{}=MtQ-?ԩqm][\\nkTuoRo\nkTo\nkT|^2}NUqq:~OUqqVAʷ\nkt|^2pNտqt-RQ>SAڷTnk|G 1pNտs_L/To8)o u[*75J~OUaSALn?0pRտxk/Q{ALbz?m/Qz?m[&y[&75io *q8io *ԼD5թ_ jԜD5թ_!8/ }h_$jql_V|G }h_$gQC_mq}Z>8)qLoVSG!  }x_$z,oWNw5|y_k^>89wWNw5Gy' ;[#<'yC_k1}p{WX>8Iw{U#<} ǠS} }#<} }c<} }c,wcv~d}`5>/;i|?11>O; ʧKGlD`.N߉UUފߪ6n^j"zfe4Ay|OՏ5ܢnF6ۍ[t}:-#f?)5ˆ2+r9ܻ}7.]ܲztiU7뛵7)s]ڻ_Kf{Szj=#clQ=s>-{^r>.rwsb>)۹Ӟ>/qFUxLŌks4ۢ?{OKrK9hcYwvrC\S]ʦ=2Dr:8^v6v(DLwoQj1ps8C{ n;E;V {f\ޢzSݦOZ{ĸb139}+%&8⌻yk*k""&biе;nMӌ>zV);=x?+&FU3TESz"f*eR(b>=O{fv/]!Qv說&b;wRB⸻wUߓ1T]+a*}%]L!qd}%]L Qv狼&bwUߔ۾bwUߓ\WnzJAIW~L!q\]*ˎbsUߓ1d=%]L!q\]*a+=%]L!q\\*a,r礫&.\w0˞E˞=]L qrW~L!qdx_q#oI|]RVi{368rk)6FٖF#yZ9nsnvSժ*1ɏv!i'gb3~ 9dvvZj!2lڪncYqr#rpʷnu:.ݧ_ ֛kciOs~> Xɦ5ƿK:Le{UN3<ճKPяޝks.mQg1+k^OoVj#5㳘oCveꞙ]=hT}lsB.R E\ \"@.VpAY!*Hp$8$vh2@!%Y!qAY!HE\ $v\8Eddd VHE\ !p⫀d U+$ d\pp UT-n+9jU=m)ٮ3tb}Sl˃hiU\[5TDSf眇{Ķ𪋞xug6okę=v蛕~v}tM'?৑:juzfeD0;pQ{&lc[u=usYyj&͊<ܸ"M:*v颞uUU6QlYlxvմlؖzlZ4莙f]*ic}f[P?f=l}ȝj":r12٢5sܴ>׾v3j~~7NǶ]3a+~$R B* VWEZ ApApH.W#$  VHq VHAW2B+$";(2B+$ Ed 2@Y .dVHE\ !p ⫀dU Ap⫁W.Z*ApU W@ e|mpQOZV-UbkN|SeWith4Apܼuǽb%fɎ?.@1LvLKZvS8yE2.zSUw'Z]ic|qb7*=vݽTQE۳բgMj";Lc+tUDKܶ.8~moSXv5ݫnh#<;Fk5sb9#j"clq.Qn!-Qn՚i2Y.s~a<{Wk\_ql柙uOf\/g?MaOMqj9m3MpEq^$E])Ln8njv3x365V0ٹsw]]uL˖_)vh&#]EMQ1/?ksiŢ=EƘ+݈1zeɮybXlkƑfi#a -*W.T *2B*\"@.W2B+$ E\ p2B*HE\"GeH좲B VD!\ #$"@.Y!HE\ AW2@!WU VHAp ⫁W.W.\ ApAp WcFGV}z虥WQnp9j}x\~mN{<ڱx'p⺲-[HvG;O@֯NvTzkZJlWj\N yۧ]LDv5f5d-ZB"nKי9A5} Lvb?my8>d#B/7xz?ȘuwKt9|kM/r#UsO=_!:ZӋ{5_?~>A{|t2,z%t<w9鱋gU\zG:WpacV9n9X."iע55QMf3 {.cmyMWVNmq6?Fuq^UktLi[p&ݨyvOWҝ ;{xS^U'>iNㄕ{}xS8IިOW;UOӹxITsժ3qN~`a^;UxOӹxIWUOS%QL/V|ʝ *baz^;Uj'̩ܼ,_6UOӸeQ|/UŸ1qʣ^W;Wj)w/ *Z'ipVOӸQ̼UŸ1rҨf >aN㆕~fz^;3=V | +g`z~8iTsC+NQUœ};WJ'N㇕G4=R Sxy\sOoJ)SqLTœu;j_8pN6*lm_8w/+lmާ_8puN67Ī9G~#ruSq+nmާ_#ruSq+om_8w2ԫ\n^U}J qpw2USeq-?ԫT̪9Ƕz~eqMԫ 㜻g8;Tsl)JgN&:6Qq0wRV5Sqνku+u~_8^UF Aʣ\N"q+/v~STsj z Bjym>sܮ9 wwjzm1swнڣO\}aqm} wa_O^O`*9;; |1{ Tsh_swv~£G^ʣGNh]sWUW\vg]sl-[>k0]ڢ&g;f;&7*>op>{I{k)*DOn:5u:d4J~c7TxrbݸZ~ֳ޵5GV嫴LkEqه9Ms'1MQݵ{Ocwr[si26Ms+I:|Z;]hu _j4^FjQv3qbv,ۏa2̑F܀j uYTU* rcp7XX8M̜̘E)UUTQUuE43)UQLc;!_Ͻۗn<eֵnG2E:Dj{zkۘfclm/jUjצw|cX5QnOW>6S=iZsobg+bvLtm*jr6sy^l[.xVc456.>V7\XyNN-ۯNgHS=15[u9vTvkO<eCbųz pܿ ٳ[) N7'}Qb|sCcyN~핟U\ "=^ֺLet;G8c<,-g;V|DknXpWMꙋ+1>-3; G^WbmevG{Y;B0.kٞ}o?N^;cf<g;g/yVr{ԜO湿ZM>W9?̎4_'os3O~sam=޿N'\-SgiGD[Ow79KTڟ9dtO[7_*\WL᮲=(yizqk|gƦvu!hvڙ|4>G3euNYm[kM/լkߦL3 Rψ=cz݌?`DXY4z{|.v*5G׃o_W8MSxdsc[ o;z>f /řgIOLvc+w/_b3M[0em]=&&<|FۼnvNӲ_*>=ݹ1LMSLDjY]DcUSgd8\QLVȈ\ >~Q9sߤOɞ}orim=޿N'\! -Sgj)>l_jf{&ge{ۚԿj#W V/G-rp=.]vbutLLN;~vٷ. s)}:mYj똢*t>,W~65U8Do )LTzaovw3OO#}?Ik%~L_?2:'g޻"]nu̍jtJ)S͙FücVڽOZq\On&\yNen2i۰ڷfͩ7"7*3L}|EbM3&y1 &7;?ZM3rgǓDu/n曛.VE1:Dɹ?*sU1>]Z|=X?t킊Zzuz^1j&hU/hy8o]xcڱJ7_bc&~?zWj߱9ɪ*11lmje,wzO(86q6]/`ߢqZ/]bi1٘;Ekin϶qO\#/l\zQ=g7{Fߕ[[nٷܯ22oQ=[0?ۦuS3t}E98;iy"9'$snmY"9joznSWy6w]9UEmҾo֞f#^gD?j9lM;*tysFI1v$S+ 8XM1,f3ff'v,]6SH^6c3>orƢ94OgXL}-;D!*rf>[iG7 usZf_3U! Lc6OtWwQwf򶬉9kZqQWMfSVkvYKęIF1gLDśU<X{m5ˢgVST1U_VL۹LLM3ϕx@۫m5oO=Li[ǒ叧4+nk3C{p/CpGCMsUꗁ|[6V5{TwkEq1=r 4-E;&9}ۦfjbe\A?)LUkWLxUL^1Gu:gW z#)?p> 1ݾ[&]ƿrj.UUMuk3M]Y=۝z=>)63wsmεSo1os>xof{[{?cbr6 r.U\niŹgJ*S؉ӳ,g{Tۧ7n]&|0ǟ#sT٪q1'.L^73/Q:ږ6?>Ks~ 8g3*{ju*MQܗx7w)v]1N<4-24Q\c;z%}k7}\+yur5{qƚOV:Ou~tL;yxױ )v/.wclz{hk%ٯ8/=Y]]̮NiU}Xk}uLʧmSŊZx[otw22snkխu3٪f^jܜ1ӾyͿ2:󗢘>ڰ3/ź-j_^\]ƪWlf!˞w{1o6?.:=>v"bffgzdFE4SLUF=t#8\G~Ʀ7>\{OLQgkmMSwOh~ `khy^lg86~qYkTSNWӮlN-GE͜;g{1-ҝې<ʦ_p_?֡5W^vomG놃WoT<3Ga.q˵n.Wfw! %Xc|3ԢgY:gGE3jC_i9E\r,DnT~i#շ4iD\aga|7nj\LuLW0_ytf-/yg>p_=ſy[Ϫ^r't7>qUٵLMQQLSӌ6.}.0mr2OMUt4[?sk%MQUN߿E&|_w>-:w>clU35SMS1]mjUvi4[šcy6<7ڞYꏧ;l~uM̫j)x^/MnW35ӲoK'kڝ?W͵c8VqlQEb:$nˎ Ċwir#xy4:z"zwLq'K[4"/= F0żz>9nة:}1GUS1>)\=J16,;tFԏxz}@tXncȈ\5تt]Y &f3f9{?lDعݟTݶ˱4Lvu& sW^iV k^b9_'CznafhwۑNU*! Et5v:;Qyow6Dljcۧ(ӶgwN' b-\<;j2)v[w)^yz2ՙmaG7y^{WS|WcnLG.4OE_6nV}-xf18+83uY~/~jiNO֚g]W7W]vU,sL_lJڱl=HsqµTufydnx̾(3pEt߿jm;]蘙'Z鉧OhgHnv~ep܊YgkZԏz/2f4\v^'ޏkxg]r3-QcǮ5廴1ܘt-ܪQ]3cت&'^ s;'*ț9SLM]j(K}߭hc/Xv0p/;Դ7q?Nxze ɉ[}1em*'"(<YO ].T͙t~Kh3q5S! \ETα=je>%8Ggv6}/?*cL"fz"5}kn3USݻEf|ٹ+M9w12rtGզ)γ>+3rc;k0toߋLYce1&{r7#s.3rt-Q៙-EңSWM6L-ur#w{u_!yE=_7L^at?h(w~ R [{o?_?\4#~wp礹pFs;,χtO[^|*{GCGѿT= p*ͱMtSUz6f#iEU}z,-sW.ZzLU4Y%S1ܻOLL;v߱j5f]1}r-v/ZLUnSU3Dç118K*{*o\o_On|Ggy1bmc_mQGDGC~uVO/ElF|skE\qpUu!/e߷Gc>U5suaP~D~d{تXΏOCǹ?K^c;foQr&q)TU7?K40SZ|1LLOy=|mU^zi]hyilfVNk.+w)f:bz{q=}z媦cj51xik7ngj>V}8w(Ţ7G6#6S1ӥyXƝph7^Rb=-TS F›чo%|If]bs7sOZ$Qv*Oi]6gnſdT9L/,e6w/m,+V٦.DFh Ә;W?r6|ݮ3<ߝ?{]9u}tFv91n*91N9]Lt! &vu ^1گZݮnvvܚnWsskuf{W]OS\v{q=pvc)7;pL=X b3MtQLLO >|4xV8߀x**xoV]EʭfQ3Nw5w43^DZTN|36{U[`+zMq\U1)r[s#?KEDM{e5v1)(?"?z}z2z=?|M4Nҟs#~'ӳb:rͪhi~DtSC뫵TLa9Q@˛?[9߾   cX{]}/ݺnSNgիoN[@|^O]y~ X;s}^W@n Y^>vO573ih .u:Ao]5_dzƞc^`NS٠F>i]bd}:罚 sJFIFddDuckyPAdobed       PK h, content.xmlےȒ :D~svgjU= $@&@3+[&=A S%r p#$Agwd wrGl}w^h;L]~o'/_}?y=MoYYnx;>Oi/n~Y[/4LS_h/|/=orXܳ__xݝ:?4B o8@6fs1􍧭q\_xrӓԧtzo~W\7v控_PwYڷ#$:P2ke oG>7 7`Cv&wGχ" ܷWΆGgAEYAMp'?-S/w+ Os}X+yݮB 7y ʾ=3_qG;逄ÚAb8@z@ ^}K?KX?@|6|d}=k /0\X;}'0TǃO Ը}|O`sk8pKG|<MAl=>&a ۬.-P g=\amQz gONr GSXzצ2ϚNḩ0g2ݴ_'W*.t|juKKoi۹i=B@MW"68 ]*ЧW岼g:NZқi./jOGz;>=KA_ {Hl^ Eľ>sK(?WOB^U u<<=]U{:?z/t{ W3|ζ6̔mY,L%Äᡕޱ8ֶۍT(iq޻SxsSAEUP^Ch)f+gU%,w/kEٮ>O*| XN:?SU4H`=eػ:U^5Dl 6N 8wSylIbZ ! SAHMȝ,> hYXWrykpzw઎&ug{{֮l2P7E*}WͿT "ڮ 1e ux7[d(_%Wkq ?;vio_Fp[h6*nZo*! Ğֆk K~a9(R,}rQ͵HZEm,̒?rZktcRf㇖'R"mXS.؉~\/_ \,,##iaCKes\n]0#R4S,{z7:U$ݓxH[ j~g|Fn^l׋q[Fxɔ}:-| & rB>|t4ΛE*߁ywx-)/.nvh\1 Cm;񘇄p[`ġ >A5FWdV{(oGk[L)TV9:jnh_P?ȇoT[rĖYA-9>SQjHat^ySwfЗ4E(8#5AYZ7jXԔD .loIIW/.vYS<%큩:y,NO~,&z^:hA7ye> h:mX*_g kb!Hlr|s Z*N Vn'urLׂja5Z" %o򊯩,0WN)44\ Seq,7l &xfƇ:}:xfZtnd 4$[󗀆uY!`:#Q9YBDQ_ء* Yl;/p0zpL:{ [Ӝ0tV}ҙU;)’vRBU8`PĻMZQNB uQd7L큄p#9{ xnt6du.fdjAbACe#)^=EG%cPh9|X!oN[y9v`)=5ֺ֫69d-<(ǦS1vT ˲`_&iH=*,Fo@=j sҠa/Hc|Lq2C/Wp`YhI?Y.ЌJԀ!3u:ۀan?yZ[Eƀ{q1Gi SqDƀ{1Gi G oEe R*۬ho8`T6(Y&N6xUBxpA4x$KٜWz*[ ,>6Wul4xO AVzvM:-CYYBVEYtphNl7eWveȋ~)j0\w\{T^:.L=`*r 0u0  ơaQhoz=LQ3 DQ L?8?ϓؤ;! OM@Hu,k]jB2-HsXe|W0֓+Ɛ .tY(ȴ\ 2m8v5+JFCnKcW7`{ xu^݀'<pH#tz]mxWՆw]mxWՆwtpQ20jC~um^Ţ&!*]ŢXtbU,bbUU95BU>W*\E^)찮&\W*W]媫\urUU䇈Azr]EhtU4FW([4/~ SbMǮ9Lk&5u$f2{XʪWY*!ʪWY*UV=_P|gīzU«zU)*^E=E;oֽ sCg>Okciie3ȧ {\om$X{eC|g;D׾Xn/{&䏼C6iFv}K`鋷= kB{ݱ>_>Xvcz=7{ݑQC$DZiR{-|4oT@e|DQ#wj[`<ӟ\9pF|s๚wF`a+7攇Mk#v=v]/DN mY\v P4au;z?VPO ':RY3rD^-lWȦzl_U-\*6n/V>R֧q[ FqLت_yVBp |cq~+'GrDZ\ $ܟ:~WA,<5!ށܠj7盖oxo zeS~A;WEzBOp[7j X-ykC ^KYƄq0Q` - 5@~0ft㭑#j7cv,X{N8Ռ_f(y zmPWywx?fܝ:ѨTͽGu$"hO6dfxNEoNqgm7h_q.oD'*~~ O)23s[Ji勣bxgŮ>c7pƹ qHBVe˾gފèIޓx |X&@V֛I׵Ou_;op}w7 ?:w{!Kݮ;W/ Q_0r[EZʽ%a']”X%^4`צ]g+c7Lf#)Zo;E%7Ν AvgИy=c BH_p\vQXz)Thu2iN@V#'bG^ז9Iඋv*cn=xˠ;0aP l1"g\NY t;i_n*0;_}4GD%Q3*/E#ՍK{"4lWhT PKfwY.;@ fY+X6Kvty/}N( VDO6㥚x$lZf^ mMkkv4 *A"G[%.>XOYF`->Oto"Dɾ m(ۍ';>\I0oA ԏtKxai/.wn*21o S xG77]HL]  ^G{MK3v?gn@3/uohO]{ ^!C3+{=*G++(hB,< Z~nM>ֺ{l^B"!S围ލXbZ|r}BXw$7d0 Z6b e ]pgmQ1Ri{AIr6m*/j~OфG(b!"Dŀ_J# x|!,O1"ZJr4Z&wflSvY%}=XZ?{ւ gUYiD|)w=Y4ٍ sc8γ (s 4/e݅q0; f+jm!8x <7pYpiX(Ycj3g R,%OdHddox,} )k5eE÷f*1jjh.L eU69lRfR2Gdw[f G05 eZc@Ը6BLAP.^ B)25~#҂0Vi MwLT@ xu֛#z}ᢐBWKG.&sN0PbףD}.}Ɉprsv GWNamU3|&lx y"|,NΘ/" rM/U2vl(Xgݬ„rfg} ?J[RHqRI !6s)P qdΰ7[]$xN?Pj6×/@/|̎?=OMGlk8Vb6}̾Zlؓ 3+7> s L i3t'zJzQ,D^Yvɻ|W8 $}{Hmѧ}}|^aɋ7%vBr7Lxn: Z|.O8Axh ؟_4[> msD D%ߌ#Oӥ 3$fp xciї~_!gD)"4/X.^󖡤ݷ-TgϵDJl?Sf6]HHeH6+zgߡX.B“?SZcRYa_k!ipqE#"1v!GzCݮD }%wrzMAxI&E&}6Œ Q.slp#Y+zD 63v#wLR*Lz5t_YeqZVּ{Ƭ;|= ;?TηB߶{ohH^O76 MsFdCx&*HWUfzͱYAxӸҍr͗Oqv_k#`]Y+s5qkF;0I /*5>,sRK{UW+9LiobzaJۭviVP_t-'*{k@dnQdh |k;ZZ23M 6֑)ݍq>x~֝DovWqGBaeXPQ4 d,Zz&{ڄ4+ _2!- mt$Z%nӛo[buL$&r - >f *+]|EQ @lo 'u4fVN0nj@bv,r\m=0R=)m0ދfT݋8#П+AlѴ ۆ} ieA~γ3A.b uD%#-i.Ĥ*щ"7J- ʤUV m="]{]vTQT@ Gd:RGq&BF.UXԻuե8 l,*4V}21ECXT=a7-<"adz5DtxT>ڳD'9ۼ G> Y 4ˡ^mM3X*Qg=3 XS'(:&fY lal*%?]6- ,),6c>ʧ&zXG0(JEb|R7'چ:j6Kyz t"L]sē :/G Oh'}]tu@ FFh:D+qL;XY+I1|rR}oXK^T<F)+3 0.xh.'ױ AuTbLo>ꀝOQ?wV{bar '#J ݰ^3}"1 vpUO֌T0^2&eB!%=5#/ X$t>(AAb{xͫ&_sמE3%j-/8W=HM7E wy f7Uw*iJ(q;PRrT Gfn p 3:eo~^UY7÷IUfO2ʎ\8snru}ZbR3+?XhL%JjfbŋpDd!޳ۜA5pߢ$a؂ ?`~14`1#W@%FU;l{.(o4(P&`a>:GI5d1:;^WKWDf;f,(o !.,#@`YmY}âYĀK6T=um1'jTzYb+b&#&=pBj[lH3B7%%BQYP>plJGKlSX3x_m-zrY xIUB+cZ7!b.[Xx\Sa+̳+ W6|I MR{JNy*#VW|_}K(fe C Pa:uƟJ7n\\PHшj ,kFkփfj֭,vM NONAÓǑmJp| Zz=L2zFU"R JS2z[Ko&LhʡRKm܎B*@U&}2ӓA < _nKǜ/ئMkalPZ0IL Myml5GNׄBI;$|IWL?Ex&Aۚ{Jj<f̽GM(S7IzĨ;Qe셚zfxXFĊCw!B% +ddփóO+o<.qr3]G온a TKS@P9nKs !"uRʂ"xߺǻf8bxuk#*㴲9hN22 9!:H*+:yWC! "r+{m*kIʐQomn gˤ<Zѫ?R$`WQ(-9`:5?F]/]X')gwR11vz&]@c@\y؍bSimG\TMu&<[{K-4;E@Ez)behtU 3-czpPm>[GT&ZT}R \͡%f6N *VT/RckbUO·(?K(5шjNqh4 [Ohy#Yz@UA?3>z2¿LU8Ą%eῦaM|@Lsbq gE|=W(1R\F'zN}ܨ6AƥPb1|nُ2Y!fP>qݿ\9Z$}blÖțK hE>)kq'vFf?uRa>mn! Qއ>q{p]doq6+M3j4DsHL%pRŔ{?EE$C:1Րh(2-PF%lόՀ*T'YO ^́vj,hh[OjE㫐/e9q15^C4d+Q;px˻IP &pB}]it#c§aROi%+D QRJ"D<0"XD4SDm}hI*Q7&ug]t=6av?~Y]~I(j\c# uN2)č@K3 ^s'&5䂪iBnyu,3 7P`J==V#( n<%zrs˄QE#pU>8V}>ؠERrИusqavw88#U.pSvU$( H+#4DʘW0Np/"oƜ;>y4;b&†RK1@''h2fڏ\,lǹ /炠n-癒Xk-#syXɄrW\ V¶2,ۀ=cdIax(KaP}2XppCD ,@N[u]3hC|&{sD};e^):pbeb$_,ٵVOʕ} ɕ}V SM@[d]亥 Q"O ,Ӈ" 5ieq!e҂|+IMn7lW&VVb?.E{LÚ1G4,%&Z&#snF 97dά_!V="?`O a A+vA%"Kv FҽTm.W tS| JY +B%oe DLh ~ͼ }ɞ"~DP$@hwӠfNqeG &P$HMY@)'{ܿU dQ-~p1|q =-M96lHg[fn_˜*Yu ^'{)*@*?s "Esw6N$-Em5/"/x!"A>UYt ?g4orQ}.p_Ѱm}'YUVx4l Bn6?,cL YcF(*} ^B"QQhQS oh!ő*pDab!rL!-v /l||9Ї-szLPxCQ2'㌾Wl}]jXbqPc{)7RӠ[y V|aZR8mF`ϳ\UovsB/_k#Ib1{ pVs.~) D(GC²@!-RŁ 1PpBB`2L XiC^_H85xN>\\H~B+NBNP2ŕV~ "53hWȽ7kĭnU0 F7z~Ͼ?x՘b-.#s'"p6t=XEHi%=WL\}:QkU]qJ; V!Pk<( 飼ў"ω"qiBD`yH cE-JΝ Zy1E0"[FMϼv3Q[ ?!v}e#oS ˛XQ4V$D1EuQ DZ| PHOBF ;qL^[/pDZZ"/޼]`H|o0lIQpGdPxL|vGsc3:{/K겇d8ZJ=Of&@fo `\f~t8YsGF,fb2xWU s#$ĀXV SD+< .3?66@BLnlf^|Ej fÇcYFk99h5rmsCbT8[Yb+:-kx%PhERSWR66|8伨iar8QPx^"/Pf0_f6:^l] |1Z&{I'@f!pa"6d8ʍ3h -!:X^ ɳVv@Apz?vRx&q{t |Qui7^g|a<–Yq|-7plۿ_DaԿh4D·}@hfurD%#Oӥ9s03Ib_ bXgYїa9|G Ԍ(uGIo[.A)zǹDJl?SLf )} ru"w"V^zGvnTƾ.AءT|EHAlGHH ]ѴoP+QC_k{4G>RCZ da09D4G58CJ,.`݈_NTZ :bɮYL~(uъNy1jDbrn}iwzzN;|wί=ӟ=i3CLg󸟋׳OÀv¿ }[9p<cu_lPn2GXƷb?Wv Y^ߴ9| -* Z`S5:!G37O܋(opIaXhz3 ZA$ĂywvQ29ĴEadG*o쨜 (T\-#ŏ&ueA7$%\4E{2@0`Y1nqJD Н`[՝{ ̲2q)K•B!ZVq/ iLI i-~oq:nō-`ϭ:?}nOT1qD,weB0l;Hmun=/h_wgVΠS/)j@M 6͓G >f*#$*P֓FwN$z^Dj{ c⭼ 3O_ :}>U wgpRVvP>_+$lx E1ɝ>ULjSUm؃ZX#.*DzS{iL@ps);&iڏ,Ki&6>8%d%,nDa!״d'u[ktR~IzTOՈ@r_+DmeTNcޓ(ޕ9S إ ͠*|XAL 8yP=TjI}G6e-K-ֆ! ,i^/f/翱Kׁ *PUR`^ ýs4d/=0=qo41i"n.QG*tOҟV^*FlVlWЫ7^+SJE0VBO K<~T(.CF$#O*-#GiLBHVJ<)343QkڏX0Q[|Q8l¥UR1YE9YY"gі"ު Yc}yNY+lELh䧒CϞV}b33G'ׂh۪+>+ kЂ̦6(l9{P]=Ӥ|86i{?B,s`P-kl];T+Ɂ$AaD6#+K%1W2p>qfˤC OF y/`qbsmqC6Bw;G9pBخ;]0 /޼c1ѨIk1uIB*oanˠ:"Em"T݃C.7X 2ɛo~y;HOѳ}g i?:s8^,admFvZ XS8ʐVLB5PgLY D+/0)ߢSo]v\+фklweJ^]HNU+㟌Ϛ;v[S9eEZ̟踠%KV'a;kg ?4?`yʳßt eyef[5/$L#P=[~$f}A+A]޶JzoЫ/@?0Ǯ0VmxWiҶQ̋clǡ0yD^^:躞x_.Jx5ml|K~">?xh3o^bzщG3}8q}7kLkZM?z<F'& }yST)tK㺀N1Lv{'7;a&[]{hlGuvq?q@ aeY dMՃ5c,HDwA Wk3*#"GhYFJl`4ġpHKNFzLNurS/ 7Bk=-6f5OvjJjQ.|x7{ a, ㊟YD[)(aM8CedVLW(yȹyUxS08?.2TL=ףXU^%/ɦMjUM&NM:bv Er|& ӝ*q:VHN2:_0ixb!hL!R;(s4g0,mOBOOG'z^|E*vcvNj?ybf6raĿTDx/mߚjzTH]$*Mؖe ' !IeS$KIRy f)<^k+7ɗ/hg{w }Zi"`ZMʜ/.*FHa^sKXOTe 25H'mT9%ah`zGp#gnFLXml=R[8,co|LC{m%ب cyXK E|<,(^' G~AČ Æe ~qqCSܹm=b[C 7 !hr *Vr3^ +P-㪭5~a3-Hx5>*o+BX=k % %@FE[ T/ XC((OG r"LjH8fbjE^@5r@Q@%~*\iLἌxË' P0'kc瓇E(ԩ7$)*ͫƧz1 |K^>bx~SZ$tQ2[ E^2Ϩu,IRѩ2cˎQ3lj; U5K'tn"V7*_{ Ny۾uuomEҨUo%y8?+lƇl$v0hDǓ[ҵ/_ko f@ ]bTI]BY}I+=S0zw:azV]_@H@3#Vءp%Q|ߢJw4RUZ810B'erp'%/^9Eb8 ){n`y_hchjHjj\xʴ܍^\e$)|f Ŕy4།GyL~ :K`p2 -kꝦ(`k<;i3z8|3$P Μ*qFxc8YnHrs޴)N>mf\ j&<^ XQJ_$l0ýY1@A3,iSq3ͩgU_34^+,3^ڲb:-|4Ȋ)]HQ^zQ6J]oe[9 sJ釆Ud, @Urx/ˮT—(kĺRفgH‰Mz[z"gB揆ocP!7PKM.FqHrnRfX?8j ?ƨxRxNS9Ez T7#ʼnzfzؖ Vq!.*ƕXNʚYBKɄ&XfRnP ձIrC*kf.}\23"6يUdx ʝ=SS>*Ws*__u(_kn U?ӆBz4tF׻T&uzi zǓ*wC%f |\Ƙq׼hڶ \; :{DJ_ >#F^\%Hge_^E7| Wyqtؚmq-۫Lz鑩; O]ZHaHX&cYHg%WtUa::A/ jҤ,z{}ϻdkXxվ>TNXAXVy xWGȷՀ,tm SDJ Tsszt^(ǓK7jj}=*,8nR-[!gE*C! QރhJD@¥N`X(<@Y[>vZZeڢ /OVĦߢq ٭'kH~u+=x yT+ zʹ8XǧZoO R3qvڎbZ Cp ֙#ZKE789(DEM8#g6;g_c ^BUvU4;osą{x$oqd6 ]뷆ͦbP7N)y+x۹Lz0-`t;6l=|Tz@QY #%-gQ:^ܨm]PM4MCE,qDNKS^.whW3fĠg[MpLxbPSC6hIk2m 'Yh<3#(lڷh g-{,Gu;2vnyy"2mItƹ~޿'&nҖ&ֹv 7nd }}X̘;~OɉžΊd[&y xAmX< HP# '`\3_]eYw(!349XSp'^o}XߠX4#O|#ް<jXc*F"fÌN"AuyōreNW "Y_|bORZ) \<>`l{ G NەSV Km |-nyy ~AU{ 3B-Qhc {9Yj *j-nUֆj!>pl"+;һE۞sK7P<9 rx# 7V^A ACB )?Wc`H.0$7UdGA?+ygez8(DCSWHUOUww1>4o-^E>w|h~ݥx6|^JYЂ^@p1W^H3Lj(geaVTvyk [o\Sqd<$,aƦk1R{%EOPcac.vwQ&.W[ݭ ,#A∕RbDUفr,XH-(՛(D5,X"NkcƧR9R"oX#z[t-G I_\8j )acrXQ?eeDQ.-\p=;2.aWf'5ow (x%%]$QAX +*gw~4KR,m% B{,st4HrtEwỷ&Om] Eb͸X_ 4{Gm0Q%dpd!78 tMS5,(5sϱ 3S0y_JV\*ERv+$jcf<e?qg&$s띮\u' 1q?w~?tQ?bMZ ǭn9k/C~ U.0C-MSQ-oԐ 71,@H9 Xbe1ل'X5 46OsL]C 쉔{(ؐ5q2R]vȖܮDMe'^zK/e0FI;i뜯-jی=$y~ٝ-kXӴap_K8:[l uދ7 [)՘3b_a6K|=c})xKco|! +k I؝sƉWk;Mk7%/'$eHd\cwi'mu.(Tw4ϔ#۶DSB';hBA1Q$VNvp+Ue8[ b oU i6yZÎF ɜK7.F9(|ed_9+'++k9R4izooYC7Y_?fY'O}x,TB]zE-l?P;qx ӥƼK?bEuJq73O[{Q6"w'YCV{*8 cv13|=R$X@ 6vH]u`N*A` mCEf1YqK-E'1!p4=+ԬoTϦyJ_Fln(UG\w7SfCflw"|U1VQOiWNᝲZak LR,Q{WvJ{Evz_ex/ i7,HK$pty ¸Ja") pO7Nۡƺ_N҂ R, %宍T~@ krH'Sz> lzEtWvu9B[[̱*Zǥp]8 h`2Yˍ 72KȘc^Hd@6x2x;G첪[Ts06yfv& +Ց%%7u0K9CP}Zɫu-;viwl}z׷10?a ׇ=p62KbWS.Q|JIJ ,mQLx`XSlM)0x9c>n| 5Esgzh UgmwKb/}1P C_ۻYql*s'q_Z^rąsJx2x5U#j+)%/_]:$q5Js5̙smG OxtV}%ڎEh-mJvo"Z^cg'_y 幢Oq,U؇9ʘ f)]Ѵ̟4l~H``KY<m Q4#k{erB\-eb5]UJM9l=`^BҀ_ފ\Swzt]U}яT~q,O1էCs^%ZSB0A~@$łSwȩuGmzKQzzzoښHbqCDjxHJ| ʀ%TJj=(C,.ծ 2WR.Iō}I+]}ПߝN.v!af.LXT%SԤŷ,6t TT SgΟ;/{.oN8D.Ȑ^,frMC\7w Dʛ[r'ˁ- !,k\%a1jhGMeMe4{Sn7 ^mC' Do!O6(֓W=zo2#ֵzQi8u7jC. ĂibhpixBT,"l%!v.٦EcJP(iGeٷGX*0`kΗ y L k&$a._=3k]šc ˻M"34Y:S,=wv8D}4^w.PRD2e,"hס@8*PIAF|`4{8r C.bo nE6Ia=ck>V S8r/DoW❕|Q)f⒪b}T_a8b+ΰaq ݗ86>yKDϤ5A^%hRlֈ'td~GbjG +g9p7-ܺysdrPKShPK h, styles.xml]͒8Sp+j}ͣ,@**n H|H$n{ap=R<`:^p=?|7p7+7Hq컱7x+Ɠɇ|P=L&7w7R&{HŸL~y$!'qFox702IWInʲ 0G,i9V )[[$ cǎK!+y$&{s'%!*RmhY%L".썟a-cŠ^zx#<àk!wʍGۚ7\+;(X{X G_K4Wu2Tq5|5 wl0JIg'س2G̗t=,:!-9" +d 3*yUEj!Q'Fku_%J?7?LpބKr^#[IfݱIxm7z3f֛9 G\'ks6WIڈEc42Ƶقh֛8mK!`DpgMOe˕JƩ%(`=xE0"R+\+$\mJRm&!%B< c2g6qaf\v-'Ol1j>l|bߜ䷟#`ڧŔֽ576uRuEn7QYf+RYvNEﺬP hqy;hc7a*)] ZŮq*u:^aj@f/ / f{Y@ȇk  %^lh(6JFp7Jj;mfFTMk ozzR}>3g} [6tͨ OkP9V'΂'b4{g;z_i1i&E +@ݰ% kHf# p}_-4hEE E#E& E"z"vE"z"+sMaAk@征4D k9E3 rT(%S`SMu[vT`?U(L=XH fHJfR5{ /u[^/Q jgXwT 1KdiW(' B/ SJ&Yl~(NE^l-\o+VJ";وyFY8۽_7D,j5[˲TvmS4]ߵ5x`{*I%lvH:;QźzT6L5 [}V7b)P^**=7v7Ƃ0qdy+ 7S.w.{ٺg]8Pr˓vOpoW<wX˓qOf<ӴWL44stRb ep^0`J`@5tNStAg(t:st0 f@T YF0Usc4`vЎ0 Y5:vI82w@SPXW9s kH`dZb02`-1@)3TL`S Hnˆ')Rt`Wa7}{*R^F)A~ Pφ'_H X'Gzl0__qO.\pn .\:O .\x>;[ .#^|C'va&̄"3L(2̄v̄ T"3L(2"<]W,zEx:Z&"5HM(RԄkHMx9s E"5HM(R"֚HM؞ EjS&LWGMX(;vA-)CZig-5yT.?f? ٝRf϶g>,d L~%+{!5"sS^Ĵhϊ;"NZ/'=aʙO8HoO~e/W' Z"?Oxo~…k/D~"SH$, qя!C"aH' a^i%oƼrOfϮ8\en\%  Q,0yq.,Cğ # zc]-jamk)H bʑ#Sl>f}9yIYXj`ROv-)'On tk7NCg!%|+CTX7ϣr֋x8vt-CV4ZgM̚#mEui "5iYy݂H{FBуZ4 N2rݠd#KU[N' +/Ht =Q@ƭCN23L]b:;M}S~W:|ّMgU%}q!3AAj= 'ٰDژWօݡ"MYDR };]}J_~@ }oJ_[vJ_hGԞҵ6::V߳<4lma@ c#v GՐ:mo2զ}n~K?6I89S'aёwIDi%oiRFqcq"aϑrv_,eɠXnR{xsč gIEy7*%mp qcv`hu gI 8pcvaix@Cx2Cz|VAm4yLn`lfCc$iR ~̍ۏ)2v0Sl?&`Ǽ >a'v4}-Ss.ꆐ!34q3[XS& :^ Aeu|BC|,=\ .OXgt$ŸTՇmAD!ۜCHT)UD"QHT'4^b*yiz~&EHKoLۛ6︹)--Vo"&U>Ҟ.[K Ǖ` ʹ>YnVk OpenOffice.org 1.0 (Linux)2001-10-24T13:30:49Steve Alexander2002-06-10T14:00:20Jim Fulton2001-12-14T19:51:15en-US151P2DT18H56M22SPK h, settings.xmlZ[W:~?YxåJR."6hpp :9kCis5޻x H3za-Ğ a}tr{aBq9ү3᭱ .T^Q̦:^#\c ~A(~3WtG ;G-}LC}2{SeFm-t\C[eEC R5z\PɕFtXJp)ыzX!(O!Q/G]0<= 'yFpb> xߠI;QjP ^wo#!A]ZP=!QLlU;S2 -iB3n<*-*3CIFo\5:2~(vsAh zsc'l߷q(ק ,Cҩ(erORm(t )昱ɟSVȶu/nB$>WX]D<. f32W_XH! &LS SQh jqɂJC6Ɨ 99/@Ue/Ҽ+B5f a8ȕ+#"$c=dq]c|=W_n.JID4DA/c9%'*761UU휟w'`6WP:4~8ND]*b4¤i3Db̗󖆶oG yj)n,9⾆ŮX+鵀$%J-i/aYHG@i]B/DZWǠ< 59Ctg,tds8 u$Fs"HXlSye:cLh=~/L#n-pu=.q}G^˫ݻxi$/yj0Ǫ'o5ꁗ2GQEhn;n@"~7/%'kΝ|4$V9h?uBܟi?/7am>> Ѹ^ǻo[5b [8V&|\_j=:7U;ߏD{sPAIt̜#r<추ksPw@ӷ)%ƲRUA-`5PmW#rVA\0m0CGͫJSL{+hLjMsUu\7|G[ƾ=mn)zVr.]'0io!u_wWʏb^_x5RzyC ;I~0V.;`˧su^ PKΥ )PK h,META-INF/manifest.xmlAo0wZP4V% @5WL}MXځV5+LhL_0 PLUoJ)&_aY@ZKJYNueu&,IPDB,x=J Y!*Zנݕ\zIŠ((cc܊rl4Gim? ?gDY'}cxFQk[ر|#;ݵuI״`vglj[%d:=NcGG=|LK.E}*OTFϯJ[SB7PK~bqrPK h,&mm-Pictures/10000000000000F5000001094AB61EAF.gifPK h,<-Pictures/10000000000000400000004077CDC8F9.pngPK h,i-i-i- Pictures/10000000000002D00000021CC3C53A0F.jpgPK h,g-~rPictures/1000000000000073000000814BB651D8.pngPK h,-vPictures/1000000000000072000000BC35CAD488.pngPK h,PP-|Pictures/10000000000002D00000021C3D8DD9F5.jpgPK h,Sh content.xmlPK h,`s 5styles.xmlPK h,M Mmeta.xmlPK h,Υ ) Rsettings.xmlPK h,~bqrYMETA-INF/manifest.xmlPK FO[