Table of Contents
LZX enables the creation of applications that have high design values and fluid, graceful interaction. In this chapter we discuss some basic tools for layout and design. For more advanced topics and exploration of the aesthetics of OpenLaszlo application design, see the Designer's Guide.
By default, all views position themselves at x="0" y="0" in their coordinate space. That means
that two sibling views will sit on top of each other. Aside from explicitly positioning the views so they don't overlap,
the easiest way to separate the siblings is to use a simplelayout
:
Instead of specifying each view's coordinates (either through a
constraint or absolutely), you can declare a layout that decides how
sibling views position themselves relative to one another. The
simplest layout is simplelayout
, which
positions sibling elements beneath (or to the right of) each other:
Example 17.1. simple layout
<canvas height="80">
<view bgcolor="yellow" width="100" height="100">
<simplelayout axis="y" spacing="5"/>
<view bgcolor="red" width="20" height="20"/>
<view bgcolor="blue" width="20" height="20"/>
<view bgcolor="green" width="20" height="20"/>
</view>
</canvas>
Here's an example that shows how to use layouts to resize views in response to user actions:
Example 17.2. Simple Layout
<canvas height="140"> <class name="coloredRect" width="20" height="80" onclick="this.setWidth(this.width+2)"/> <view x="10" y="10" name="container"> <simplelayout axis="x" spacing="10"/> <coloredRect bgcolor="red"/> <coloredRect bgcolor="aqua"/> <coloredRect bgcolor="yellow"/> <coloredRect bgcolor="green"/> <coloredRect bgcolor="blue"/> </view> <button x="10" y="110">Create A New View <handler name="onclick"> var newView = new coloredRect(container, { bgcolor : 0x000000 }); </handler> </button> </canvas>
Like all layouts, simpleLayout
affects how sibling views relate to one another. This remains true even if views are dynamically instantiated. You can set both the axis of a
simplelayout as well as the distance between the elements. Also note layouts update as the dimensions of the affected views
change.
If you need a specific group of views to be affected by a simplelayout, but want them to be isolated from the rest of the application, encase them in a parent view. You can then specify coordinates on the parent view:
Example 17.3. isolating views
<canvas height="120"> <class name="coloredRect" width="20" height="80"/> <view width="50" height="50" bgcolor="yellow"/> <!-- Group of horizontally stacked views, isolated from app --> <view name="container" x="175" y="20"> <simplelayout axis="x" spacing="10"/> <coloredRect bgcolor="red"/> <coloredRect bgcolor="blue"/> <coloredRect bgcolor="teal"/> <coloredRect bgcolor="black"/> </view> </canvas>
In addition to layouts, LZX includes the <hbox>
and <vbox>
tags that allow you to group views horizontally and vertically. Unlike layouts, which are objects that affect the behavior
of their siblings, <hbox>
and <vbox>
are themselves views that constrain the layout of their children. Each <hbox>
or <vbox>
contains a layout, and the tag syntax allows you to set the layout attributes directly on the hbox or vbox.
You can also combine <hbox>
and <vbox>
elements to form tables. The following example illustrates this. (There are more elegant ways to achieve this effect; we
include it here to illustrate the principles.)
Example 17.4. hbox and vbox
<canvas height="50"> <hbox spacing="10"> <vbox spacing="10" name="column1" bgcolor="red"> <handler name="onclick"> this.animate('spacing', this.spacing == 10 ? 0 : 10, 1000); </handler> <text>click</text> <text>to</text> <text>animate</text> <text>spacing</text> </vbox> <vbox spacing="10" name="column2" bgcolor="blue"> <handler name="onclick"> this.animate('spacing', this.spacing == 10 ? 0 : 10, 1000); </handler> <text>click</text> <text>to</text> <text>animate</text> <text>spacing</text> </vbox> <vbox spacing="10" name="column3" bgcolor="yellow"> <handler name="onclick"> this.animate('spacing', this.spacing == 10 ? 0 : 10, 1000); </handler> <text>click</text> <text>to</text> <text>animate</text> <text>spacing</text> </vbox> </hbox> </canvas>
As mentioned previously, layouts act upon sibling elements, but they can control more than just spacing. For example, they can be used to cause views to grow and shrink, as shown below.
A frequent layout problem when designing GUIs is to have an element stretch while its two surrounding siblings maintain a
constant size across the stretch axis. LZX solves this problem with the stableborderlayout
:
Example 17.5. stableborderlayout
<canvas height="140"> <class name="coloredRect" height="80"/> <view x="10" y="10" name="container" width="200"> <stableborderlayout axis="x"/> <coloredRect bgcolor="navy" width="20"/> <coloredRect bgcolor="yellow"/> <coloredRect bgcolor="navy" width="20"/> </view> <button x="205" y="110">Increase width of container <handler name="onclick"> container.setWidth(container.width + 10); </handler> </button> <button x="10" y="110">Decrease width of container <handler name="onclick"> container.setWidth(container.width - 10); </handler> </button> </canvas>
As the name suggests, this layout can be used to create a border with
a stable dimension (width or
height). stableborderlayout
is very useful for
creating borders, frames and windows. In this example,
stableborderlayout
is combined with some
constraints to create a 5 pixel blue border:
Example 17.6. creating a border
<canvas height="200"> <!-- Sliders to control width and height --> <text x="200" y="22">Set the width:</text> <slider id="widthSlider" x="200" y="50" width="100" value="50" minvalue="20" maxvalue="100"/> <text x="200" y="92">Set the height:</text> <slider id="heightSlider" x="200" y="120" width="100" value="50" minvalue="20" maxvalue="100"/> <!-- Blue border --> <view width="${widthSlider.value}" height="${heightSlider.value}" x="20" y="20"> <stableborderlayout axis="y"/> <view bgcolor="blue" height="5" width="${parent.width}"/> <view width="${parent.width}"> <stableborderlayout axis="x"/> <view bgcolor="blue" width="5" height="${parent.height}"/> <view height="${parent.height}"/> <view bgcolor="blue" width="5" height="${parent.height}"/> </view> <view bgcolor="blue" height="5" width="${parent.width}"/> </view> </canvas>
If you wanted to use the above code to frame a particular view irrespective of where it was in the view hierarchy, a good way would be to use a floating view:
Example 17.7. using a floating view
<canvas> <!-- A single colored box --> <class name="coloredBox" width="50" height="50" bgcolor="0xff0000"/> <!-- Blue border; invisible at start --> <view id="floater" width="50" height="50" visible="false"> <!-- Animate to the coordinates of a given view --> <method name="goTo" args="whichBox"> this.setVisible(true); this.bringToFront(); var destX = whichBox.getAttributeRelative("x", canvas); var destY = whichBox.getAttributeRelative("y", canvas); this.animate("x", destX, 1000, false); this.animate("y", destY, 1000, false); </method> <stableborderlayout axis="y"/> <view bgcolor="0xFFFF00" height="5" width="${parent.width}"/> <view width="${parent.width}"> <stableborderlayout axis="x"/> <view bgcolor="0xFFFF00" width="5" height="${parent.height}"/> <view height="${parent.height}"/> <view bgcolor="0xFFFF00" width="5" height="${parent.height}"/> </view> <view bgcolor="0xFFFF00" height="5" width="${parent.width}"/> </view> <!-- Controls --> <view bgcolor="yellow"> <simplelayout axis="y" spacing="10"/> <button onclick="floater.goTo(blueBox)">Go to Blue Box</button> <button onclick="floater.goTo(redBox)">Go to Red Box</button> <button onclick="floater.goTo(greenBox)">Go to Green Box</button> </view> <!-- View hierarchy --> <view x="20" y="15"> <coloredBox id="blueBox" bgcolor="0x0000ff" x="200"/> <view x="5" y="40"> <coloredBox id="greenBox" bgcolor="0x00ff00" y="150" x="13"/> <view x="1" y="90"> <coloredBox id="redBox" bgcolor="0xff0000" y="150"/> </view> </view> </view> </canvas>
The <constantlayout>
tag is a way of defining a margin. For example, if all of the children of a container needed to be
indented 10 pixels from the left hand edge of the container:
Example 17.8. ConstantLayout
<canvas height="140"> <class name="coloredRect" width="60" height="15"/> <view x="10" y="10" name="container" bgcolor="silver" width="80" height="120"> <constantlayout axis="x" value="10"/> <simplelayout axis="y" spacing="10"/> <coloredRect bgcolor="red" width="40"/> <coloredRect bgcolor="aqua" width="50"/> <coloredRect bgcolor="yellow"/> <coloredRect bgcolor="green" width="20"/> </view> </canvas>
Here <constantlayout>
and
<simplelayout>
are combined so that the
<constantlayout>
controls the left, whereas
the<simplelayout>
dictates the vertical spacing between the
siblings.
This section
discusses layouts
, which are constructs that allow you to focus on larger design issues by freeing you from the
tedium of positioning views. Layouts are implemented with constraints
, which are described in
Chapter 27, Constraints.
For more on designing the "look and feel" of OpenLaszlo applications, please see
Chapter 3, OpenLaszlo for Designers.
Views can be nested inside one another, and they can reference other parts of the view hierarchy using dot syntax and/or IDs. The view hierarchy helps you define how the various elements of your application relate to one another. It is helpful to break your application into various elements. Consider a photo-viewing application that has a list of images in a right-hand column, and a main stage area for displaying the images to the left. There is also a trash area that we'll cover later. At a very high level, you might break your application up as follows:
Example 17.9. outline of photo application
<canvas width="800"> <view name="stage" width="400" height="300" x="20" bgcolor="0xeaeaea"> <!-- Area for viewing images --> <text>Stage</text> <!-- ... --> </view> <view name="listOfImages" width="200" height="300" x="500" bgcolor="0xffff00"> <!-- Data-replicated list of images --> <text>List of images</text> <!-- ... --> </view> <view name="trash" width="200" height="75" x="500" y="310" bgcolor="0xff0000"> <!-- Trash for disposing of images --> <text>Trash</text> <!-- ... --> </view> </canvas>
You can use views with background colors when mocking up applications as shown above, to make them easier to prototype.
If you approach the application in this manner, you've effectively broken it up into manageable pieces already. listOfImages
, stage
and trash
could all be developed independently of one another. listOfImages
would contain the text-list of images that are bound to some data with the descriptive text showing. When the user clicks
one of the images, it would call a showImage()
method on stage
with the URL of the image to show as an argument.
The replicated views inside of listOfImages
would best be positioned using a layout.
The view hierarchy could also be a constraint. Imagine that in the above example, you wanted to be able to drag an item from
the list of image names from listOfImages
to trash
.
Frequently in drag-and-drop environments, the original item that was dragged is left in place (although some indication may
be given that it is in a transient state, such as being faded out), while a copy of it is dragged. If each of the image titles
was draggable, then not only might a dragged item disrupt the arrangement of its siblings, but you wouldn't be able to leave
the original intact, in order to obtain the behavior described above.
To get around this problem, you could use a floating view as the draggable view. A floating view is one that floats on top of the rest of your application, and only appears when dragging:
User clicks and holds on a view.
Floating view made visible, and located over clicked view.
Any visual changes applied to clicked view (e.g. color/alpha transform).
As mouse moves around, the floating view follows the mouse.
Onmouseup the floating view disappears, any actions performed, original clicked view restored.
To position the floating view over the clicked view, you can use the getAttributeRelative()
method of view to obtain the x and y coordinates of the view relative to a view other than its parent. For example, consider
the case below:
<canvas width="800" > <!-- An item that will get clicked and dragged --> <class name="imageRow" bgcolor="0x93A5FF" width="$once{parent.width}" height="20"> <attribute name="text" type="text"/> <text name="txt" text="${parent.text}" resize="true"/> <handler name="onmousedown"> this.f = new LzView(canvas, {width: this.width, height: this.height, bgcolor: this.bgcolor, x: this.getAttributeRelative("x", canvas), y: this.getAttributeRelative("y", canvas), clickable: true }); // Make view follow mouse around this.x_offset = this.getMouse("x"); this.y_offset = this.getMouse("y"); this.startDraggingFloater(); </handler> <method name="startDraggingFloater"> this.d = new LzDelegate(this, "adjustFloaterPosition", LzIdle, "onidle"); this.gm = new LzDelegate(this, "cancelFloater", LzGlobalMouse, "onmouseup"); </method> <method name="adjustFloaterPosition"> this.f.setX(canvas.getMouse("x")-this.x_offset); this.f.setY(canvas.getMouse("y")-this.y_offset); </method> <method name="cancelFloater"> this.gm.unregisterAll(); this.d.unregisterAll(); this.f.destroy(); </method> </class> <view name="stage" width="400" height="300" x="20" bgcolor="0xeaeaea"> <!-- Area for viewing images --> <text>Stage</text> <!-- ... --> </view> <view name="listOfImages" width="200" height="300" x="500" bgcolor="0xffff00"> <!-- Data-replicated list of images --> <simplelayout axis="y" spacing="2"/> <imageRow>One</imageRow> <imageRow>Two</imageRow> <imageRow>Three</imageRow> </view> <view name="trash" width="200" height="75" x="500" y="310" bgcolor="0xff0000"> <!-- Trash for disposing of images --> <text>Trash</text> <!-- ... --> </view> </canvas>
To achieve this, you could create a view from script when the mouse goes down over one of the views you want to drag:
This code is not easy to read, although conceptually it's fairly simple —
"create a new view when the mouse button is depressed, and drag it until the mouse button is released".
Note also that you have to listen for the global onmouseup
event instead of the onmouseup
on the dynamically created view. Because it was positioned under the cursor after the mouse was down, the event system does
not get notified when the mouse goes up over it.
This approach is fairly laborious — you have to copy all of the attributes of the original view to the new one. If you wanted to have the text field appear in the dragged view, you would have to create a new text field to match it at run-time. As the dragged view becomes more complex, it will take longer to instantiate when the user depresses the mouse button, since view instantiation is fairly processor-expensive.
A better approach would be to have the floating view ready in advance:
Example 17.10. building a "floating view"
<canvas width="800" > <!-- A draggable floating view --> <class name="floater" height="20" bgcolor="0x93A5FF" visible="false"> <dragstate name="dragger"/> <text name="txt" width="100"/> <method name="showFloater" args="xpos, ypos, itemwidth, itemlabel"> myfloater.bringToFront(); this.setX(xpos); this.setY(ypos); this.setWidth(itemwidth); this.txt.setText(itemlabel); this.setVisible(true) this.gm = new LzDelegate(this, "cancelFloater", LzGlobalMouse, "onmouseup"); this.setVisible(true); this.dragger.apply(); </method> <method name="cancelFloater"> this.dragger.remove(); this.setVisible(false); </method> </class> <!-- An instance of the floater --> <floater id="myfloater"/> <!-- An item that will get clicked and dragged --> <class name="imageRow" bgcolor="0x93A5FF" width="$once{parent.width}" height="20"> <attribute name="text" type="text"/> <text name="txt" text="${parent.text}" resize="true"/> <handler name="onmousedown"> myfloater.showFloater(this.getAttributeRelative("x", canvas), this.getAttributeRelative("y", canvas), this.width, this.txt.getText()); </handler> </class> <view name="stage" width="400" height="300" x="20" bgcolor="0xeaeaea"> <!-- Area for viewing images --> <text>Stage</text> <!-- ... --> </view> <view name="listOfImages" width="200" height="300" x="500" bgcolor="0xffff00"> <!-- Data-replicated list of images --> <simplelayout axis="y" spacing="2"/> <imageRow>One</imageRow> <imageRow>Two</imageRow> <imageRow>Three</imageRow> </view> <view name="trash" width="200" height="75" x="500" y="310" bgcolor="0xff0000"> <!-- Trash for disposing of images --> <text>Trash</text> <!-- ... --> </view> </canvas>
This code is much cleaner, and the floater code is now completely independent of the imagerow
code. Individual properties of the floater can still be set (in this case they're passed as arguments to the showFloater
method).
Taking this a step further, if our list of images were replicated against a dataset an even more elegant approach would be
to pass the data node of the replicated imageRow
instance to the floater, and have the floater do the right thing with the data.
Example 17.11. Using a dataset to drive layouts
<canvas width="800" > <!-- The data that provides the images --> <dataset name="ds_items"> <items> <item description="One" src="one.jpg"/> <item description="Two" src="two.jpg"/> <item description="Three" src="three.jpg"/> </items> </dataset> <!-- A draggable floating view --> <class name="floater" height="20" bgcolor="0x93A5FF" visible="false" datapath=""> <dragstate name="dragger"/> <text name="txt" datapath="@description" resize="true"/> <text name="imgurl" datapath="@src" resize="true" align="right"/> <method name="showFloater" args="xpos, ypos, itemwidth, dataNode"> myfloater.bringToFront(); this.setX(xpos); this.setY(ypos); this.setWidth(itemwidth); this.datapath.setPointer(dataNode); this.setVisible(true) this.gm = new LzDelegate(this, "cancelFloater", LzGlobalMouse, "onmouseup"); this.setVisible(true); this.dragger.apply(); </method> <method name="cancelFloater"> this.dragger.remove(); this.setVisible(false); </method> </class> <!-- An instance of the floater --> <floater id="myfloater"/> <!-- An item that will get clicked and dragged --> <class name="imageRow" bgcolor="0x93A5FF" width="$once{parent.width}" height="20"> <attribute name="text" type="text"/> <text name="txt" datapath="@description" resize="true"/> <handler name="onmousedown"> myfloater.showFloater(this.getAttributeRelative("x", canvas), this.getAttributeRelative("y", canvas), this.width, this.datapath.p); </handler> </class> <view name="stage" width="400" height="300" x="20" bgcolor="0xeaeaea"> <!-- Area for viewing images --> <text>Stage</text> <!-- ... --> </view> <view name="listOfImages" width="200" height="300" x="500" bgcolor="0xffff00" datapath="ds_items:/items"> <!-- Data-replicated list of images --> <simplelayout axis="y" spacing="2"/> <imageRow datapath="item"/> </view> <view name="trash" width="200" height="75" x="500" y="310" bgcolor="0xff0000"> <!-- Trash for disposing of images --> <text>Trash</text> <!-- ... --> </view> </canvas>
See the Reference for an explanation of the LzNode
call.
The floater must have an empty datapath assigned in advance. Notice how since only a pointer to the LzNode
element is passed to the floating view, the floater can access attributes of the data that were not referenced in the imageRow
class (for example,the src
attribute). This can become particularly useful when you want to "drop" the floater somewhere. The drop target may need to
access other data properties (or even delete the XML node in the dataset), and passing a pointer to it saves retracing it.
A floating view is not only for draggable objects. If you wanted to frame a specified view, regardless of where it was in the view hierarchy, you might also find a floating view to be the best option. See the StableBorderLayout section for more.
You should avoid placing views inside of views with a
resource. Instead, to have a background image in a container view, have
a view that attaches the resource be a child of the parent view. Use
options="ignorelayout"
to prevent the background image
from being affected by any layouts that act upon the children of its
container:
Example 17.12. ignorelayout
<view name="container"> <view resource="someimg.jpg" options="ignorelayout"/> <view name="childView"/> </view>
Since a layout extends Node, it can be addressed using dot syntax:
<canvas height="140"> <class name="coloredRect" width="20" height="80"/> <view name="container"> <simplelayout name="slayout" axis="x" spacing="10"/> <coloredRect bgcolor="red"/> <coloredRect bgcolor="aqua"/> <coloredRect bgcolor="yellow"/> </view> </canvas>
In the above example, the layout could be accessed by:
container.slayout
.
You might need to address a layout in script, in order to change
one of its attributes at run-time, to call the layout's
update()
method, or to lock it. A layout can also have
an id, so that it can be accessed globally.
All nodes have a layouts array, which contains pointers to all of the layouts that act upon its children:
Example 17.13. Addressing Layouts
<canvas height="180"> <class name="coloredSquare" width="20" height="20"/> <view name="container" bgcolor="silver" x="10" y="10"> <simplelayout axis="x" spacing="2"/> <simplelayout id="yLayout" axis="y" spacing="2"/> <coloredSquare bgcolor="red"/> <coloredSquare bgcolor="red"/> <coloredSquare bgcolor="red"/> <coloredSquare bgcolor="red"/> <coloredSquare bgcolor="red"/> </view> <button y="150" x="10">Increase spacing of BOTH x and y layouts <handler name="onclick"> <![CDATA[ for (var i=0; i<container.layouts.length; i++) { var lyt = container.layouts[i]; lyt.setAttribute('spacing', lyt.spacing + 2); } ]]> </handler> </button> <button y="150" x="280">Increase spacing of y layout ONLY <handler name="onclick"> yLayout.setAttribute('spacing', yLayout.spacing + 2); </handler> </button> </canvas>
Layouts can be locked and unlocked using the lock()
and unlock()
methods respectively (inherited from the
layout
class). When you lock a layout, you prevent it from
updating. For example, if you click the colored boxes in the following
example to enlarge them, the simplelayout will automatically update,
and the spacing between the boxes will remain consistent. However, if
you lock the layout, then grow the boxes, the simplelayout will not
update, until the unlock()
method is called on the
layout:
Example 17.14. Locking and Unlocking Layouts
<canvas height="140"> <class name="coloredRect" width="20" height="80" onclick="this.setWidth(this.width+2)"/> <view x="10" y="10" name="container"> <simplelayout name="slayout" axis="x" spacing="10"/> <coloredRect bgcolor="red"/> <coloredRect bgcolor="aqua"/> <coloredRect bgcolor="yellow"/> <coloredRect bgcolor="green"/> <coloredRect bgcolor="blue"/> </view> <button x="10" y="110">Lock <handler name="onclick"> container.slayout.lock(); </handler> </button> <button x="70" y="110">Unlock <handler name="onclick"> container.slayout.unlock(); </handler> </button> </canvas>
The lock()
method sets the layout's
locked
attribute to true. The unlock()
method
calls the layout's update()
method, then sets the
locked
attribute to false
.
Layouts can be animated; that is, the properties of the layout can be set to vary over time. For an example and an explanation of how this is done, see Chapter 24, Animation
When none of the default OpenLaszlo layouts do what you need, you can write a custom layout of your own. This section shows the essential aspects of building one.
The update()
method is the most important method in
a layout — it controls what the layout does. For example, here
is a very basic custom layout that spaces views 20px apart. This
is similar to the behavior of the<simplelayout>
, but unlike <simplelayout>
this one spaces
the left hand edge of the views, rather than distributing them
evenly:
Example 17.15. Updating a layout
<canvas height="100"> <class name="col" clickable="true" bgcolor="blue" width="15" height="80"/> <layout> <attribute name="spacing" value="25" type="number"/> <method name="addSubview" args="s"> super.addSubview(s); this.update(); </method> <method name="update"> <![CDATA[ if (this.locked) return; this.locked = true; for (var i = 0; i < subviews.length; i++){ subviews[i].setAttribute('x', i * this.spacing); } this.locked= false; ]]> </method> </layout> <col/> <col/> <col/> <col/> </canvas>
All layouts have a subviews
array, which allows you to cycle through the sibling views and adjust their properties accordingly. The addSubview()
method is automatically called whenever a view is added—at init time, when a view is dynamically generated from script or
via data replication. It ensures that the update()
method gets called so that the layout updates. If the addSubview()
method were not present, the above example would still look fine when the application first started, but any dynamically created
views would appear out of the layout.
Notice both:
The test for the locked
attribute (if (this.locked) return;
) to ensure conformance with normal layout response to the locking and unlocking of layouts.
The use of the locked
attribute in the update()
method (this.locked = true;
and this.locked = false;
) to prevent simultaneous changes to the layout.
Here is a slightly more complicated example. In fact the layout defined below is the same as <simplelayout axis="x" spacing="10"/>
.
Example 17.16. Horizontal Simplelayout
<canvas height="100"> <class name="col" clickable="true" bgcolor="blue" width="20" height="80" onclick="this.setWidth(this.width+2)"/> <layout> <attribute name="spacing" value="10" type="number"/> <method name="addSubview" args="s"> this.updateDelegate.register(s, "onwidth"); super.addSubview(s); this.update(); </method> <method name="update"> <![CDATA[ if (this.locked) return; this.locked = true; var indent = 0; for (var i = 0; i < subviews.length; i++){ var s = subviews[i]; s.setAttribute('x', indent); indent += s.width + this.spacing; } this.locked = false; ]]> </method> </layout> <col/> <col/> <col/> <col/> <col/> <col/> </canvas>
Notice that the update()
method is slightly different
now — it adds up the total widths of the preceding siblings
(adding the spacing) and sets the x to the total. That is the basic
algorithm for simplelayout. Another very important difference is that
the addSubview()
method registers the inherited
updateDelegate()
to listen for changes to that
subview's width. updateDelegate()
is a delegate that
all subclasses of layout have. It calls that layout's
update()
method. In this example, the layout needs to
update when the width of any of the sibling views changes, so the call
to register it happens in the addSubview()
method.
Copyright © 2002-2007 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.