FW: Constraints and Prototypes in Garnet and Laszlo
Brad Myers <[email protected]> Fri, 19 Nov 2004 10:23:07 -0500
| Newsgroups | gmane.lisp.garnet.user |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format. ------=_NextPart_000_1C8B_01C4CE21.C362C810 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Some nice comments from a former Garnet developer. Brad Myers _____ From: Don Hopkins [mailto:[email protected]] Sent: Thursday, November 18, 2004 6:25 PM To: [email protected] Cc: 'Don Hopkins' Subject: Constraints and Prototypes in Garnet and Laszlo Brad, I posted this discussion of Garnet and Laszlo to Slashdot. -Don http://slashdot.org/comments.pl?sid=129894&cid=10835594 Constraints and Prototypes in Garnet and Laszlo (Score:2) by SimHacker (180785) <http://slashdot.org/~SimHacker> on Tuesday November 16, @01:30PM (#10835594 <http://slashdot.org/comments.pl?sid=129894&cid=10835594> ) (http://www.donhopkins.com/ | Last Journal: Monday February 23, <http://slashdot.org/~SimHacker/journal/> @06:48AM) Garnet <http://www-2.cs.cmu.edu/~garnet/> [cmu.edu] is an advanced user interface development environment written in Common Lisp, developed by Brad Meyers (the author of the article). I worked for Brad on the Garnet project at the CMU CS department back in 1992-3. One thing I like about Brad Meyers is that he's a strong programmer, as well as an excellent researcher, so he had a first-hand understanding of the real-world issues involved in programming languages and user interface architecture, unlike many academics who talk a lot of theory but never get their hands dirty. Brad Meyers understands where the rubber hits the road, and how important it is to have good tires. At the time I worked on it, Garnet didn't have pretty graphics like Flash, but the underlying programming system had some advanced features that are sorely lacking from most modern user interface development environments. Laszlo <http://www.laszlosystems.com/> [laszlosystems.com] is an modern open source GUI programming system, with many of Garnet's advanced "natural programming" features like prototypes <http://osteele.com/archives/2004/03/classes-and-prototypes> [osteele.com] and constraints <http://www.laszlosystems.com/lps-2.2/docs/guide/views-tutorial.html> [laszlosystems.com]. Laszlo currently uses Flash as its virtual machine, but it's a much higher level way to program dynamic interactive web based applications, without using the proprietary Flash authoring tool. Garnet had a true prototype based OOP system (somewhat like Self), which is great for gui programming, because guis have so many objects that look and behave like each other except for a few little customizations (like the layout, graphical style, data source and call-back behavior). Garnet also had an automatic constraint <http://osteele.com/archives/2004/10/constraint-diagrams> [osteele.com] system, which enabled you to simply define any attribute as a formula that depend on other attributes, without needing to worry about how and when the values were calculated. Garnet's constraint system automatically figured out the dependences of each formula, and automatically and efficiently recalculated and cached any values that needed to be updated, but only when necessary. With constraints, you can make a button inside a window, and define its left edge to be ((parent.width - self.width) / 2), and it will automatically remain horizontally centered in the window from then on, without you (the programmer) having to worry about what to do when the parent window's size changes. Without constraints, you have to manually write all the code that changes the button position whenever the window size changes, which results in code scattered all over the place in different classes and handlers and intermediate objects. Constraints are much easier to use and more general purpose than resize handlers, springs and struts, complex MVC <http://osteele.com/archives/2003/08/rethinking-mvc> [osteele.com] updating schemes, and other Rube Goldberg devices. Constraints are especially useful for user interface programming, because they save you from having to write lots of annoying boiler plate and error prone code for handling updates (registering, chasing down dependencies, detecting changes, notifying updates, all happens automatically). Constraints make GUI programming much easier, but they're also useful anywhere in your program where one value is defined in terms of other values that might change at any time. Once you've tasted a programming language with constraints, you will not want to go back. Programming without constraints is like writing in machine language: error prone, low level, tedious, inefficient and mind numbing. Constraints are like structured programming for variables: In the same way that it's better to use loops and conditionals instead of gotos, it's also better to use declarative <http://www.ultrasaurus.com/sarahblog/archives/000140.html> programming [ultrasaurus.com] that says what you mean, instead of imperative peeks and pokes and side effects. Constraints let you write easy to read code, and concentrate on the interesting high level stuff that matters. You can go back later and change the layout of a complex GUI, without rewriting lots of fragile layout and event hanling code. Look at any MFC program to see how bad it can get without constraints. Constraints are natural and close to the way you think, because they let you declare a variable and the formula that defines its value in one place, instead of scattered all around the code. They off-load the tedious task of tracking down and maintaining all the dependencies from the programmer to the computer, which is much better at that kind of stuff. Garbage collection is like constraints: the computer can do a much better job than the human at performing the task perfectly, so spending some cpu time on automatic garbage collection and constraint maintenance is well worth the significant increase in programmer productivity and software reliability. Garnet had a prototype based object system. It was implemented in Lisp with a system called KR (Knowledge Representation, classic AI "frames" with slots and inheritance). KR was extended with an automatic constraint system that parsed the formula expressions (written in Lisp macros), figured out the dependences, wired up and maintained the dependency graph. An expression like "((parent.width - self.width) / 2)" would depend on self's width slot, self's parent slot, and parent's width slot. If any of them changed, then that formula would be automatically invalidated, and only recalculated on demand when it (or something that depended on it) is required. The cool thing was that you can make a prototype object, like a button, which has sub-structures like a label, border, drop shadow, etc. The sub-structures can be constrained to the button's dimensions, the label is centered in the border, and the drop shadow floats below and to the right, so the button's layout is automatically updated when it moves or resizes. The text color and border fill can depend on the button's "state" variable, so they automatically switch between bright and dark when you press the button (the input handler just toggles the "highlight" variable, and the graphics that depend on it are automatically updated). Now that you've composed and constrained a button to look and feel how you want, you can use it as a prototype to make other similar customizable buttons instances. Each instance can itself override the prototype's graphical properties, label text, action, etc. Instances of a prototype all magically inherit (instances of) the sub-structure of the prototype! It all just works the way you'd expect it to (with a lot of plumbing going on automatically behind the scenes). There's no need to make a separate class for each different style of button or action - prototypes let you customize any instance itself! Like Garnet, Laszlo <http://www.laszlosystems.com/> [laszlosystems.com] is an advanced open source user interface development environment that supports prototype based OOP with constraints. Unlike Garnet, Laszlo deeply integrates recent trendy technologies like XML, JavaScript, Flash, data binding, networking, XML/RPC, SOAP, ReST, Java and Tomcat. Laszlo has a class/prototype <http://www.laszlosystems.com/~adam/blog/archives/000016.html> based object system [laszlosystems.com], and it (currently) uses the JavaScript runtime in Flash as its virtual machine. But it's more than just another way to program Flash. Unlike raw Flash, The <http://www.laszlosystems.com/developers/learn/laszloin10minutes.php> Laszlo language is easy to learn [laszlosystems.com] and Laszlo programs are <http://www.laszlosystems.com/lps/tutorials/index.html> easy to read and write [laszlosystems.com] thanks to prototypes <http://www.laszlosystems.com/lps/tutorials/classes.html> [laszlosystems.com], constraints <http://www.laszlosystems.com/lps/tutorials/views.html> [laszlosystems.com], declarative <http://www.laszlosystems.com/~adam/blog/archives/000021.html> programming [laszlosystems.com], and instance-first <http://osteele.com/archives/2004/03/classes-and-prototypes> development [osteele.com]. -Don Take a look and feel free: http://www.PieMenu.com <http://www.piemenu.com/> [piemenu.com] ------=_NextPart_000_1C8B_01C4CE21.C362C810 Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META http-equiv=3DContent-Type content=3D"text/html; = charset=3Dus-ascii"> <META content=3D"MSHTML 6.00.2800.1476" name=3DGENERATOR> <STYLE>@font-face { font-family: SimSun; } @font-face { font-family: @SimSun; } @page Section1 {size: 8.5in 11.0in; margin: 1.0in 1.25in 1.0in 1.25in; } P.MsoNormal { FONT-SIZE: 12pt; MARGIN: 0in 0in 0pt; COLOR: windowtext; FONT-FAMILY: = "Times New Roman" } LI.MsoNormal { FONT-SIZE: 12pt; MARGIN: 0in 0in 0pt; COLOR: windowtext; FONT-FAMILY: = "Times New Roman" } DIV.MsoNormal { FONT-SIZE: 12pt; MARGIN: 0in 0in 0pt; COLOR: windowtext; FONT-FAMILY: = "Times New Roman" } A:link { COLOR: blue; TEXT-DECORATION: underline } SPAN.MsoHyperlink { COLOR: blue; TEXT-DECORATION: underline } A:visited { COLOR: purple; TEXT-DECORATION: underline } SPAN.MsoHyperlinkFollowed { COLOR: purple; TEXT-DECORATION: underline } P { FONT-SIZE: 12pt; MARGIN-LEFT: 0in; COLOR: black; MARGIN-RIGHT: 0in; = FONT-FAMILY: "Times New Roman" } SPAN.EmailStyle17 { COLOR: windowtext; FONT-FAMILY: Arial } DIV.Section1 { page: Section1 } </STYLE> </HEAD> <BODY lang=3DEN-US vLink=3Dpurple link=3Dblue> <DIV dir=3Dltr align=3Dleft><SPAN class=3D632362115-19112004><FONT = face=3DArial=20 color=3D#0000ff size=3D2>Some nice comments from a former Garnet=20 developer.</FONT></SPAN></DIV> <DIV dir=3Dltr align=3Dleft><SPAN class=3D632362115-19112004><FONT = face=3DArial=20 color=3D#0000ff size=3D2>Brad Myers</FONT></SPAN> <HR tabIndex=3D-1> <FONT face=3DTahoma size=3D2><B>From:</B> Don Hopkins=20 [mailto:[email protected]] <BR><B>Sent:</B> Thursday, November 18, = 2004=20 6:25 PM<BR><B>To:</B> [email protected]<BR><B>Cc:</B> 'Don=20 Hopkins'<BR><B>Subject:</B> Constraints and Prototypes in Garnet and=20 Laszlo<BR></FONT><BR></DIV> <DIV></DIV> <DIV class=3DSection1> <P class=3DMsoNormal><A name=3D10835594><FONT face=3DArial = size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt; FONT-FAMILY: Arial">Brad, I posted this = discussion of=20 Garnet and Laszlo to Slashdot. </SPAN></FONT></A></P> <P class=3DMsoNormal><FONT face=3DArial size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt; FONT-FAMILY: Arial"></SPAN></FONT> </P> <P class=3DMsoNormal><FONT face=3DArial size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt; FONT-FAMILY: = Arial"> = =20 -Don</SPAN></FONT></P> <P class=3DMsoNormal><FONT face=3D"Times New Roman" size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt"></SPAN></FONT> </P> <P class=3DMsoNormal><FONT face=3D"Times New Roman" size=3D3><SPAN=20 style=3D"FONT-SIZE: = 12pt">http://slashdot.org/comments.pl?sid=3D129894&cid=3D10835594</SP= AN></FONT></P> <P class=3DMsoNormal><B><FONT face=3D"Times New Roman" size=3D3><SPAN=20 style=3D"FONT-WEIGHT: bold; FONT-SIZE: = 12pt"></SPAN></FONT></B> </P> <P class=3DMsoNormal><B><FONT face=3D"Times New Roman" size=3D3><SPAN=20 style=3D"FONT-WEIGHT: bold; FONT-SIZE: 12pt">Constraints and Prototypes = in Garnet=20 and Laszlo</SPAN></FONT></B> (Score:2) <BR>by <A=20 href=3D"http://slashdot.org/~SimHacker">SimHacker (180785)</A> on = Tuesday November=20 16, @01:30PM (<A=20 href=3D"http://slashdot.org/comments.pl?sid=3D129894&cid=3D10835594">= #10835594</A>)=20 <BR><FONT size=3D2><SPAN style=3D"FONT-SIZE: 10pt">(<A=20 href=3D"http://www.donhopkins.com/">http://www.donhopkins.com/</A> | = Last Journal:=20 <A href=3D"http://slashdot.org/~SimHacker/journal/">Monday February 23,=20 @06:48AM</A>)</SPAN></FONT> </P> <P class=3DMsoNormal><FONT face=3D"Times New Roman" size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt"></SPAN></FONT> </P> <P class=3DMsoNormal><FONT face=3D"Times New Roman" size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt"><A title=3Dcmu.edu=20 href=3D"http://www-2.cs.cmu.edu/~garnet/">Garnet</A> [cmu.edu] is an = advanced user=20 interface development environment written in Common Lisp, developed by = Brad=20 Meyers (the author of the article). I worked for Brad on the Garnet = project at=20 the CMU CS department back in 1992-3. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">One thing I like about Brad Meyers is that = he's a strong=20 programmer, as well as an excellent researcher, so he had a first-hand=20 understanding of the real-world issues involved in programming languages = and=20 user interface architecture, unlike many academics who talk a lot of = theory but=20 never get their hands dirty. Brad Meyers understands where the rubber = hits the=20 road, and how important it is to have good tires. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">At the time I worked on it, Garnet didn't have = pretty=20 graphics like Flash, but the underlying programming system had some = advanced=20 features that are sorely lacking from most modern user interface = development=20 environments. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt"><A title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/">Laszlo</A> [laszlosystems.com] is = an modern=20 open source GUI programming system, with many of Garnet's advanced = "natural=20 programming" features like <A title=3Dosteele.com=20 href=3D"http://osteele.com/archives/2004/03/classes-and-prototypes">proto= types</A>=20 [osteele.com] and <A title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/lps-2.2/docs/guide/views-tutorial.ht= ml">constraints</A>=20 [laszlosystems.com]. Laszlo currently uses Flash as its virtual machine, = but=20 it's a much higher level way to program dynamic interactive web based=20 applications, without using the proprietary Flash authoring tool.=20 </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Garnet had a true prototype based OOP system = (somewhat=20 like Self), which is great for gui programming, because guis have so = many=20 objects that look and behave like each other except for a few little=20 customizations (like the layout, graphical style, data source and = call-back=20 behavior). </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Garnet also had an automatic <A = title=3Dosteele.com=20 href=3D"http://osteele.com/archives/2004/10/constraint-diagrams">constrai= nt</A>=20 [osteele.com] system, which enabled you to simply define any attribute = as a=20 formula that depend on other attributes, without needing to worry about = how and=20 when the values were calculated. Garnet's constraint system = automatically=20 figured out the dependences of each formula, and automatically and = efficiently=20 recalculated and cached any values that needed to be updated, but only = when=20 necessary. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">With constraints, you can make a button inside = a window,=20 and define its left edge to be ((parent.width - self.width) / 2), and it = will=20 automatically remain horizontally centered in the window from then on, = without=20 you (the programmer) having to worry about what to do when the parent = window's=20 size changes. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Without constraints, you have to manually = write all the=20 code that changes the button position whenever the window size changes, = which=20 results in code scattered all over the place in different classes and = handlers=20 and intermediate objects. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Constraints are much easier to use and more = general=20 purpose than resize handlers, springs and struts, complex <A = title=3Dosteele.com=20 href=3D"http://osteele.com/archives/2003/08/rethinking-mvc">MVC</A> = [osteele.com]=20 updating schemes, and other Rube Goldberg devices. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Constraints are especially useful for user = interface=20 programming, because they save you from having to write lots of annoying = boiler=20 plate and error prone code for handling updates (registering, chasing = down=20 dependencies, detecting changes, notifying updates, all happens = automatically).=20 </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Constraints make GUI programming much easier, = but=20 they're also useful anywhere in your program where one value is defined = in terms=20 of other values that might change at any time. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Once you've tasted a programming language with = constraints, you will not want to go back. Programming without = constraints is=20 like writing in machine language: error prone, low level, tedious, = inefficient=20 and mind numbing. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Constraints are like structured programming = for=20 variables: In the same way that it's better to use loops and = conditionals=20 instead of gotos, it's also better to use <A title=3Dultrasaurus.com=20 href=3D"http://www.ultrasaurus.com/sarahblog/archives/000140.html">declar= ative=20 programming</A> [ultrasaurus.com] that says what you mean, instead of = imperative=20 peeks and pokes and side effects. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Constraints let you write easy to read code, = and=20 concentrate on the interesting high level stuff that matters. You can go = back=20 later and change the layout of a complex GUI, without rewriting lots of = fragile=20 layout and event hanling code. Look at any MFC program to see how bad it = can get=20 without constraints. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Constraints are natural and close to the way = you think,=20 because they let you declare a variable and the formula that defines its = value=20 in one place, instead of scattered all around the code. They off-load = the=20 tedious task of tracking down and maintaining all the dependencies from = the=20 programmer to the computer, which is much better at that kind of stuff.=20 </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Garbage collection is like constraints: the = computer can=20 do a much better job than the human at performing the task perfectly, so = spending some cpu time on automatic garbage collection and constraint=20 maintenance is well worth the significant increase in programmer = productivity=20 and software reliability. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Garnet had a prototype based object system. It = was=20 implemented in Lisp with a system called KR (Knowledge Representation, = classic=20 AI "frames" with slots and inheritance). KR was extended with an = automatic=20 constraint system that parsed the formula expressions (written in Lisp = macros),=20 figured out the dependences, wired up and maintained the dependency = graph.=20 </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">An expression like "((parent.width – = self.width) / 2)"=20 would depend on self’s width slot, self’s parent slot, and = parent’s width slot.=20 If any of them changed, then that formula would be automatically = invalidated,=20 and only recalculated on demand when it (or something that depended on = it) is=20 required. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">The cool thing was that you can make a = prototype object,=20 like a button, which has sub-structures like a label, border, drop = shadow, etc.=20 The sub-structures can be constrained to the button’s dimensions, = the label is=20 centered in the border, and the drop shadow floats below and to the = right, so=20 the button's layout is automatically updated when it moves or resizes.=20 </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">The text color and border fill can depend on = the=20 button’s "state" variable, so they automatically switch between = bright and dark=20 when you press the button (the input handler just toggles the = "highlight"=20 variable, and the graphics that depend on it are automatically updated). = </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Now that you've composed and constrained a = button to=20 look and feel how you want, you can use it as a prototype to make other = similar=20 customizable buttons instances. Each instance can itself override the=20 prototype's graphical properties, label text, action, etc. = </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Instances of a prototype all magically inherit = (instances of) the sub-structure of the prototype! It all just works the = way=20 you’d expect it to (with a lot of plumbing going on automatically = behind the=20 scenes). There’s no need to make a separate class for each = different style of=20 button or action – prototypes let you customize any instance = itself!=20 </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Like Garnet, <A title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/">Laszlo</A> [laszlosystems.com] is = an=20 advanced open source user interface development environment that = supports=20 prototype based OOP with constraints. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Unlike Garnet, Laszlo deeply integrates recent = trendy=20 technologies like XML, JavaScript, Flash, data binding, networking, = XML/RPC,=20 SOAP, ReST, Java and Tomcat. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Laszlo has a <A title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/~adam/blog/archives/000016.html">cla= ss/prototype=20 based object system</A> [laszlosystems.com], and it (currently) uses the = JavaScript runtime in Flash as its virtual machine. But it's more than = just=20 another way to program Flash. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">Unlike raw Flash, <A title=3Dlaszlosystems.com = href=3D"http://www.laszlosystems.com/developers/learn/laszloin10minutes.p= hp">The=20 Laszlo language is easy to learn</A> [laszlosystems.com] and <A=20 title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/lps/tutorials/index.html">Laszlo = programs are=20 easy to read and write</A> [laszlosystems.com] thanks to <A=20 title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/lps/tutorials/classes.html">prototyp= es</A>=20 [laszlosystems.com], <A title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/lps/tutorials/views.html">constraint= s</A>=20 [laszlosystems.com], <A title=3Dlaszlosystems.com=20 href=3D"http://www.laszlosystems.com/~adam/blog/archives/000021.html">dec= larative=20 programming</A> [laszlosystems.com], and <A title=3Dosteele.com=20 href=3D"http://osteele.com/archives/2004/03/classes-and-prototypes">insta= nce-first=20 development</A> [osteele.com]. </SPAN></FONT></P> <P><FONT face=3D"Times New Roman" color=3Dblack size=3D3><SPAN=20 style=3D"FONT-SIZE: 12pt">-Don<BR>Take a look and feel free: <A=20 href=3D"http://www.piemenu.com/">http://www.PieMenu.com</A> = [piemenu.com]=20 </SPAN></FONT></P> <P class=3DMsoNormal><FONT face=3DArial size=3D2><SPAN=20 style=3D"FONT-SIZE: 10pt; FONT-FAMILY: = Arial"></SPAN></FONT> </P></DIV></BODY></HTML> ------=_NextPart_000_1C8B_01C4CE21.C362C810--