463 lines
21 KiB
HTML
463 lines
21 KiB
HTML
<!--startcut ==============================================-->
|
|
<!-- *** BEGIN HTML header *** -->
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
<HTML><HEAD>
|
|
<title>Making Smalltalk: OO Thinking LG #65</title>
|
|
</HEAD>
|
|
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
|
|
ALINK="#FF0000">
|
|
<!-- *** END HTML header *** -->
|
|
|
|
<CENTER>
|
|
<A HREF="http://www.linuxgazette.com/">
|
|
<H1><IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png"
|
|
WIDTH="600" HEIGHT="124" border="0"></H1></A>
|
|
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="puryear.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue65/steffler.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="stumpel.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
<P>
|
|
</CENTER>
|
|
|
|
<!--endcut ============================================================-->
|
|
|
|
<H4 ALIGN="center">
|
|
"Linux Gazette...<I>making Linux just a little more fun!</I>"
|
|
</H4>
|
|
|
|
<P> <HR> <P>
|
|
<!--===================================================================-->
|
|
|
|
<!-- END header -->
|
|
|
|
|
|
|
|
|
|
<table COLS=2 WIDTH="100%" NOSAVE >
|
|
<tr NOSAVE>
|
|
<td NOSAVE>
|
|
<center>
|
|
<h1>
|
|
<img SRC="misc/steffler/makingSmalltalk.png" height=53 width=417> </h1></center>
|
|
|
|
<center>
|
|
<h3>
|
|
OO Thinking </h3></center>
|
|
|
|
<p>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<center>
|
|
<p>By <a href="mailto:jagwar@magma.ca">Jason Steffler</a></center>
|
|
</td>
|
|
|
|
<td WIDTH="200" NOSAVE>
|
|
<center><img SRC="misc/steffler/penguinInBalloon.gif" height=230 width=200></center>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div align=right>
|
|
<hr WIDTH="100%">
|
|
<p><b>Article #5 - Apr 2001</b></div>
|
|
|
|
<h2>
|
|
<a NAME="abstract"></a>Abstract</h2>
|
|
<a href="http://www.magma.ca/~jagwar/makingSmalltalkForwardingPage.html"></a>
|
|
<br> For those who haven't read the previous articles,
|
|
be sure to read <font size=+1><a href="http://www.linuxgazette.com/issue60/steffler.html#statementOfPurpose">the
|
|
statement of purpose</a></font> first. This month, we're going to
|
|
discuss OO thinking. For those looking to read the whole series locally
|
|
or information about upcoming articles, you can <font size=+1><a href="http://www.magma.ca/~jagwar/makingSmalltalkForwardingPage.html">check
|
|
the MST page</a></font>. For those looking for further information
|
|
on learning Squeak, here are <a href="http://minnow.cc.gatech.edu/squeak/377">some
|
|
good resources</a>.
|
|
<br> This is the last planned article for this series.
|
|
The reader interest has been high enough for me to continue with the next
|
|
series, but unfortunately my available writing time has quickly dwindled
|
|
:-( as my wife nears her due date :-) So this will be the last regular
|
|
article at least for a while.
|
|
<h2>
|
|
Quote of the day</h2>
|
|
Reason never changed a man's opinion which by reason he never acquired.
|
|
<br> -- Mark Twain
|
|
<h2>
|
|
OO Thinking</h2>
|
|
If you're just getting into OO from another programming
|
|
background, you'll soon realize that it requires a change in the way that
|
|
you think, the way you approach problems, and (IMHO) how much fun you're
|
|
having. This month, we go over some things to keep in mind when doing
|
|
OO programming.
|
|
<br>
|
|
<h3>
|
|
Breaking Linear Thinking</h3>
|
|
This is the first hurdle I've seen many people trip
|
|
over. They're so used to programs with a main() routine of some sort,
|
|
that when they first dip their toes into the Smalltalk pool they're frightened
|
|
off by not being able to find a linear beginning, middle, and end of something.
|
|
Realize that Smalltalk is about working with a group of collaborating objects.
|
|
To be sure, you will need some entry point to your code/application, however
|
|
it likely be in the form of opening your starting window, then saving/stripping
|
|
your image.
|
|
<br> Thinking of problems in terms of nouns and verbs
|
|
(objects and responsibilities) is a more natural way of thinking, and often
|
|
leads to a much different decomposition of the problem than functional
|
|
decomposition. Try to identify which objects are inherit to the problem,
|
|
which objects need to involved to help out, then think of the most basic
|
|
responsibilities and distribute them appropriately across the objects.
|
|
<br> This leads us to our next item: OO programming
|
|
lends itself well to iterative development. It's a natural activity
|
|
to define the basic objects, then start adding basic relationships and
|
|
responsibilities. If you find something doesn't fit right, then shift
|
|
the responsibility elsewhere. Flesh out your objects and responsibilities
|
|
over time.
|
|
<br> Try to use short methods to help maximize reuse
|
|
and maintainabilty. If you find yourself writing 100 line methods,
|
|
then you're still thinking linearly. The average method length varies
|
|
depending on whom you ask, but it should be short - somewhere around 8
|
|
statements or so. Of course, there's always exceptions to any rule
|
|
- this is just a rule of thumb.
|
|
<h3>
|
|
Decision Making vs Commanding</h3>
|
|
This is what I often think is the most fundamental difference
|
|
between OO programming and procedural programming. In procedural
|
|
programming it's common to do things in terms of decision making.
|
|
You do things like:
|
|
<ul>
|
|
<li>
|
|
<b>if this, then that, else that</b></li>
|
|
|
|
<ul>
|
|
<li>
|
|
For example, if data is an integer and user input is a float, then convert
|
|
the float to an integer to add</li>
|
|
</ul>
|
|
|
|
<li>
|
|
<b>for i = 1 to i = maxRange do this unless i > maxBounds, and if early
|
|
break condition is met then break out of loop</b></li>
|
|
|
|
<li>
|
|
<b>1 + 2 * 3 = ?</b></li>
|
|
|
|
<ul>
|
|
<li>
|
|
This example uses operator precedence, which is something that most languages
|
|
have. The statement is evaluated as: (1 + (2 * 3)) = 7. But
|
|
to determine precedence the language <i>needs to make a decision</i> which
|
|
operator to precede.</li>
|
|
</ul>
|
|
</ul>
|
|
A common problem that arises from decision making programming
|
|
is that you have similar decision making being done in several parts of
|
|
a program. Then when requirements or needs inevitably change, there
|
|
are many different spots that you need to update/modify your program to
|
|
update all the decision making spots.
|
|
<p> In OO programming, it's more common to do things
|
|
in terms of commanding. You command (or ask if you're polite) objects
|
|
to do things. If the object shouldn't do something, or should do
|
|
something differently, then it should know that. Since you ask different
|
|
objects the same thing, and they respond as each of them should, there's
|
|
no decision making. You do things like:
|
|
<ul>
|
|
<li>
|
|
<b>object doSomething</b></li>
|
|
|
|
<ul>
|
|
<li>
|
|
For example, it doesn't matter that you're adding a float to an int, the
|
|
float object knows how to add floats to itself, how to add ints to itself,
|
|
how to add fractions to itself.</li>
|
|
</ul>
|
|
|
|
<li>
|
|
<b>aCollection do: [:eachElement | eachElement doSomething]</b></li>
|
|
|
|
<ul>
|
|
<li>
|
|
Notice how there are no bounds checking - a collection object already knows
|
|
how to do that and does it for you.</li>
|
|
</ul>
|
|
|
|
<li>
|
|
<b>1 + 2 * 3 = ?</b></li>
|
|
|
|
<ul>
|
|
<li>
|
|
In this example, remember integers are objects too in Smalltalk (part of
|
|
the pure OO nature of Smalltalk). So we're asking the object 1 to
|
|
add itself to 2, then the resulting object to multiply itself by 3.
|
|
Hence, the statement is evaluated as: ((1 + 2) * 3) = 9.</li>
|
|
|
|
<li>
|
|
As a side note, it's funny how often I've seen some of my C++ or Java coworkers
|
|
flee from Smalltalk because this doesn't make sense to them. They
|
|
still haven't entirely made the shift to OO thinking.</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
<h3>
|
|
Don't Sweat the Details</h3>
|
|
I once heard Alan Knight remark that you know somebody
|
|
is starting to get Smalltalk if they answer the question: "How does
|
|
Transcript show: 'HELLO WORLD' work?" with: "I don't care".
|
|
A common theme among Smalltalk newbies is a need to know exactly how everything
|
|
works, and step through all the methods of the objects from the library
|
|
that they use. This is related to linear thinking, in that you need
|
|
to understand how a linear path flows to determine how it broke down the
|
|
road. If you find yourself sweating the details of the class library,
|
|
then you're probably still in linear thinking mode.
|
|
<br> A related theme is that Smalltalk lends itself to
|
|
top-down coding. Put off work as long as possible and put off decisions
|
|
as long as possible - abstract and stub out reponsibilities if you can.
|
|
It's a powerful feeling to define even a trivial system that works, then
|
|
keep it working as you add real meat to it. You're most often in
|
|
a state of things working.
|
|
<h3>
|
|
Simplification by Encapsulation</h3>
|
|
Try and group data together with appropriate operations
|
|
in an object. If you're acting directly on an object's data in some
|
|
manner, then you're breaking encapsulation. If you're doing something
|
|
like: anObject aDataAttribute aPartOfAttribute doSomething, then
|
|
you're breaking encapsulation.
|
|
<br> A nice example of encapsulation is the looping noted
|
|
above. The collection class knows how many elements it has, and how
|
|
to loop over its elements, and you're not concerned with bounds checking
|
|
nor should you be.
|
|
<h3>
|
|
Reuse</h3>
|
|
Opportunities for reuse abound, and not just from the usual place of inheritence
|
|
<h4>
|
|
...through the class library</h4>
|
|
Before coding something, browse the class library to
|
|
see if it's already been done for you. Reinventing the wheel is definately
|
|
non-OO and wastes time.
|
|
<br> Another rule of thumb for knowing when you're getting
|
|
Smalltalk is the proportion of time you spend browsing the class library
|
|
to the proportion of time you spend coding. As you gain experience
|
|
and familiarity with the library, your proportion of time will go down,
|
|
but for a beginner you should expect to spend the majority of your time
|
|
browsing the library and the minority of your time coding.
|
|
<br> An appropriate remark I once heard (sorry, don't
|
|
remember the source), during a LOC metrics flame war is that Smalltalkers
|
|
should be measured by the LOC they <u>don't write</u>, as they're saving
|
|
time and maintentance costs by reusing the class library.
|
|
<h4>
|
|
...through goodies</h4>
|
|
Smalltalk has a rich history and a great user community.
|
|
There may be a freeware or opensource goodie out there that will satisfy
|
|
your needs. Have a look at the <a href="http://st-www.cs.uiuc.edu">UIUC
|
|
repository</a>, or search the web or ask the newsgroups for goodies.
|
|
<h4>
|
|
...by approrpiate responsibilities</h4>
|
|
If it isn't your reponsibility, then don't do it (or
|
|
redo it). Conversely, avoid responsibilities as much as possible
|
|
(only take the appropriate responsibilities). By trying to stick
|
|
to only appropriate responsibilities, then you're more likely to reuse
|
|
responsibilities elsewhere in the system.
|
|
<br> For example, don't have the responsibility to login
|
|
to your application in your client's login GUI (a bad practice in general),
|
|
if you later have a web GUI, then you need to either copy the login logic
|
|
to your web GUI, or factor out the login code to a reusable object.
|
|
<h4>
|
|
...through inheritence</h4>
|
|
Now we finally get to reuse through inheritence.
|
|
I leave this for last, as reuse through inheritence has been (IMHO) overhyped
|
|
and often overabused with needlessly deep class hierarchies that complicate
|
|
maintenance.
|
|
<br> For example, if you're writing a hospital system
|
|
you'd probably want to reuse a <b>Person</b>'s characteristics of <b>firstName</b>,
|
|
<b>lastName</b>,
|
|
and <b>socialSecurityNumber</b> by making subclasses of
|
|
<b>Doctor</b> and
|
|
<b>Patient</b>.
|
|
<h3>
|
|
Distributing responsibilities</h3>
|
|
Watch out for bloated parts of system - you can see
|
|
this if you're drawing your system out and your diagram looks like an octopus.
|
|
This is a sign that there are too many responsibilities on one object,
|
|
and that object is going to get harder to maintain as it bloats.
|
|
You should try and have groups of peer objects collaborating.
|
|
<br> Another warning sign is using a 'manager' object.
|
|
Again, there are perfectly good times and uses for a manager object, and
|
|
it can be difficult to determine if you're abusing a manager object.
|
|
I like to use a rule of thumb I heard from Alan Knight: object managers
|
|
should be like real world managers: they should not do any real work
|
|
- they should facilitate or manage interactions between other objects.
|
|
<h2>
|
|
<a NAME="sweetSqueak"></a>A Sweet Squeak</h2>
|
|
This month's sweet squeak is the release of Squeak 3.0! :-) To be
|
|
generic as possible, this description covers the scenario where you want
|
|
to run Squeak in Windoze or Linux. For this simple path install,
|
|
on Linux you will need root priviledges. <i>(Note: you can install
|
|
without root privilidges if you're familiar with updating your paths, I'm
|
|
not going to cover that topic in this simple guide)</i>
|
|
<br>
|
|
<h3>
|
|
Step 1: Downloading Squeak 3.0</h3>
|
|
Go to the FTP site: <b>ftp://st.cs.uiuc.edu/pub/Smalltalk/Squeak/3.0</b>
|
|
and download:
|
|
<ul>
|
|
<li>
|
|
<b>Squeak3.0-win.zip</b>, includes:</li>
|
|
|
|
<ul>
|
|
<li>
|
|
<b>Squeak.exe</b>, the virtual machine (only good for Windoze, we'll need
|
|
to compile a VM for linux)</li>
|
|
|
|
<li>
|
|
<b>Squeak3.0.image</b>, (can use this on linux or Windoze)</li>
|
|
|
|
<li>
|
|
<b>SqueakV3.sources</b>, (can use this on linux or Windoze)</li>
|
|
</ul>
|
|
|
|
<li>
|
|
<b>Squeak-3.0pre2.tar.gz</b></li>
|
|
|
|
<ul>
|
|
<li>
|
|
Source files for compiling the linux VM</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
<h3>
|
|
Step 2: Set a base directory to run squeak from</h3>
|
|
Assumes your Windoze mount point is <b>/windoze</b>, change for your system.
|
|
<p><i>Note: if you don't have/want to run dual boot, just change
|
|
your install location to be whatever you desire, for example: ~myuserid/squeak3,
|
|
and delete the unnecessary files: <b>NPSqueak.dll, Squeak.exe, SqueakFFIPrims.dll.</b></i>
|
|
<blockquote>
|
|
<li>
|
|
Make a <b>/windoze/squeak3 </b>directory</li>
|
|
|
|
<li>
|
|
Unzip the <b>Squeak3.1-win.zip</b> file into a <b>/windoze/squeak3</b>
|
|
directory.</li>
|
|
</blockquote>
|
|
|
|
<h3>
|
|
Step 3: Installing VM for linux</h3>
|
|
This is a <i>very easy</i> thing to do - even if you've never programmed
|
|
or compiled anything in your life before. Here are the steps:
|
|
<ol>
|
|
<li>
|
|
Unzip <b>Squeak-3.0pre2.tar.gz</b> to wherever (be sure to unzip with directories,
|
|
this unzips into a <b>Squeak-3.0 </b>directory)</li>
|
|
|
|
<li>
|
|
<b>cd</b> to where you unzipped the sources. (The <b>BUILD.UnixSqueak</b>
|
|
is a quick-n-easy guide from which these steps were condensed from)</li>
|
|
|
|
<li>
|
|
<b>mkdir build</b></li>
|
|
|
|
<li>
|
|
<b>cd build</b></li>
|
|
|
|
<li>
|
|
<b>../src/unix/configure --bindir="/windoze/squeak3"</b></li>
|
|
|
|
<li>
|
|
<b>make</b></li>
|
|
|
|
<li>
|
|
<b>make install</b> (NOTE: here is where you'll need root privilidges
|
|
with the default install, as stuff is copied to /usr/lib, /usr/man, etc)</li>
|
|
|
|
<ol>
|
|
<li>
|
|
Here, you're going to get a couple of errors (unless you're installing
|
|
to a Linux location), as you can't make links on a Windoze file system</li>
|
|
|
|
<li>
|
|
Copy the referenced files to your <b>/windoze/squeak3</b> directory:</li>
|
|
|
|
<li>
|
|
<b>cp /usr/lib/squeak/3.0/squeak /windoze/squeak3</b></li>
|
|
|
|
<li>
|
|
<b>cp /usr/lib/squeak/3.0/inisqueak /windoze/squeak3</b></li>
|
|
</ol>
|
|
</ol>
|
|
|
|
<h3>
|
|
<b>Step 4: Start Squeak :-)</b></h3>
|
|
|
|
<ul>
|
|
<li>
|
|
<b>cd /windoze/squeak3</b></li>
|
|
|
|
<li>
|
|
<b>squeak Squeak3.0final.image</b></li>
|
|
</ul>
|
|
...I'll leave starting up Squeak in Windoze as an exercise for the reader
|
|
;-)
|
|
<h2>
|
|
Quick tour</h2>
|
|
When I started up the image for the first time, I was
|
|
pleasently surprised that the default GUI to come up is the newer morphic
|
|
GUI (as opposed to the older MVC GUI that was mentioned in Article 1).
|
|
For the read-along folks, you'll see (click on the below half size images
|
|
for full size images):
|
|
<p>The entry screen. The Squeak logo in the top right is an xeyes
|
|
type of app, where the eyes follow the mouse.
|
|
<br> <a href="misc/steffler/squeak3-screen1.png"><img SRC="misc/steffler/squeak3-screen1-halfSize.png" height=249 width=400></a>
|
|
<p>If you put the mouse curor over the logo, you'll notice the pop-up balloon
|
|
help is enabled.
|
|
<br> <a href="misc/steffler/squeak3-screen2.png"><img SRC="misc/steffler/squeak3-screen2-halfSize.png" height=249 width=400></a>
|
|
<p>If you click on the project at the bottom right of the screen, it'll
|
|
zoom to full screen size as you enter it.
|
|
<br> <a href="misc/steffler/squeak3-screen3.png"><img SRC="misc/steffler/squeak3-screen3-halfSize.png" height=249 width=400></a>
|
|
<p>And finally, lets click on the music project to have a look.
|
|
<br> <a href="misc/steffler/squeak3-screen4.png"><img SRC="misc/steffler/squeak3-screen4-halfSize.png" height=249 width=400></a>
|
|
<br>
|
|
<h2>
|
|
<a NAME="lookingForward"></a>Looking forward</h2>
|
|
Alas, there will be no immediate looking forward due
|
|
to my time constraints. The next series I was planning covers
|
|
some basic programming basics like: unit testing (SUnit), source
|
|
code management (change sets and SCAN), an object tour of commonly used
|
|
objects, control structures, and Squeaklets.
|
|
<p> In the meantime though, I <i>highly recommend</i>
|
|
downloading v3.0 of Squeak (noted below) and trying out the STP goodies
|
|
as your first goodie exploration. They're available from: <a href="http://www.create.ucsb.edu/squeak/STP12.html">http://www.create.ucsb.edu/squeak/STP12.html</a>
|
|
<p> I've enjoyed learning about Squeak over the past
|
|
few months, and I hope you've enjoyed the series.
|
|
<hr WIDTH="100%">
|
|
<h2>
|
|
<a NAME="personSampleCode"></a><b>Smalltalk Code</b></h2>
|
|
Somebody pointed out to me that the ScopedBrowser used in Article 4 doesn't
|
|
work properly in Squeak v3.0, so here's an<b> <a href="misc/steffler/MakingSmalltalk-Article5.st">updated
|
|
version</a></b>.
|
|
<br>Note: I noticed that SUnit is now included as part of the base
|
|
image now, so I've included some programmatic unit tests. After loading
|
|
the code, if you wish to run the unit tests, do: <b>TestModel openAsMorph</b>,
|
|
then click the <b>Run</b> button. You'll notice 8 windows pop up
|
|
and close, and there shouldn't be any errors listed in the error pane.
|
|
|
|
|
|
|
|
|
|
<!-- *** BEGIN copyright *** -->
|
|
<P> <hr> <!-- P -->
|
|
<H5 ALIGN=center>
|
|
|
|
Copyright © 2001, Jason Steffler.<BR>
|
|
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
|
|
Published in Issue 65 of <i>Linux Gazette</i>, April 2001</H5>
|
|
<!-- *** END copyright *** -->
|
|
|
|
<!--startcut ==========================================================-->
|
|
<HR><P>
|
|
<CENTER>
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="puryear.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue65/steffler.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="stumpel.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
</CENTER>
|
|
</BODY></HTML>
|
|
<!--endcut ============================================================-->
|