newObjects Active Label Data,file and command formats

The reasons behind the Active Label's file formats and the command syntax.

(skip this section and go to the formats and syntax descriptions)

The Active Label ActiveX supports a variety of ways to load its design data. They include initialization from <PARAM> tags in the <OBJECT> element in an HTML page (mechanism known for the COM programmers as Property Bag), from URL using the OBJECT's HTML element DATA attribute, using the VisiLabel.Src property, directly by a client side script (usually Javascript) in the WEB page or other language if the object is used in other kind of application and so on. Furthermore the label design data can be saved/obtained from the VisiLabel object - directly by a script in the DHTML page (through the VisiLabel.TextCommands property or through ObjectParams property), or posted to an URL (see the VisiLabel's Dst property, the PostData method and the other properties related to data post operations). Also the Active Label control can be used in non-WEB environments where the standard ActiveX persistence techniques can be fully exploited.

The wide variety of ways to load and save the label data to/from the Active Label control rises the question about a format and syntax that would be compatible and convenient for all of them. To achieve this goal we devised a generic text based syntax and file formats that we will call in this documentation native Active Label file formats and native Active Label command syntax. The future versions of the newObjects Active Label ActiveX control will add more data formats such as formats based on XML, UDS and others, but because of their nature and requirements they will be applicable only for some of the load/save techniques supported by the control.

To illustrate this consider the following HTML code:

<object classid="clsid:09A02CEE-410B-47BA-A837-E62C9C8D70BF" id="VisiLabel" width="100%" height="400">
<PARAM NAME="CMD0" VALUE="VISILABEL:1,0">
<PARAM NAME="CMD1" VALUE="LAYOUT:8000,6000,200,200,200,200:-1,16777215,0,5308416,0,8388608:-1,9141364,0,0,0,8388608,1">
<PARAM NAME="CMD2" VALUE="PAGE:0,0,1000,1000,1000,1000,500,500">
<PARAM NAME="CMD3" VALUE="MISC:0,-1,2,0">
<PARAM NAME="CMD4" VALUE="EDIT:0,0,0,100,0,0">
<PARAM NAME="CMD5" VALUE="TEXTDEFAULTS:1,-1,Arial,1,0,0,0,0,0">
<PARAM NAME="CMD6" VALUE="SHAPE:Element 2:3,375,325,4550,5375,0,15066597,0,0,-1:0,0,0">
<PARAM NAME="CMD7" VALUE="IMAGE:Element 1:5050,325,2600,4800,2:0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1:0,0,0,someimage.jpg,,?,POST">
</object>
  

This is an OBJECT HTML element which uses PARAM tags to pass parameters to the created Active Label control. Alternatively the same initialization data can be put in a text file (or generated dynamically by an ASP, PHP, JSP or other server side script) and passed to the object in much simpler manner:

<object classid="clsid:09A02CEE-410B-47BA-A837-E62C9C8D70BF" id="VisiLabel" width="100%" height="400" DATA="initfile.txt"></object>

or this way (we recommend it)  

<object classid="clsid:09A02CEE-410B-47BA-A837-E62C9C8D70BF" id="VisiLabel" width="100%" height="400">
<PARAM NAME="SRC" VALUE="initfile.txt">
</object>

Where the initfile.txt is the file that contains the data. The file (if we assume a text file for the example purposes) would look like this:

VL01
VISILABEL:1,0
LAYOUT:8000,6000,200,200,200,200:-1,16777215,0,5308416,0,8388608:-1,9141364,0,0,0,8388608,1
PAGE:0,0,1000,1000,1000,1000,500,500
MISC:0,-1,2,0
EDIT:-1,1,-1,100,0,0
TEXTDEFAULTS:1,-1,Arial,1,0,0,0,0,0
SHAPE:Element 2:3,375,325,4550,5375,0,15066597,0,0,-1:0,0,0
IMAGE:Element 1:5050,325,2600,4800,2:0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1:0,0,0,someimage.jpg,,?,POST

If you compare them both you will see that the PARAM tags contain exactly the same values in their VALUE attributes as the lines in the text file.

Why we discussed all this? 

The PARAM tags require the values to be put in quotes, thus we are limited on choices and if we want a single native syntax to fit in there as well in the other initialization scenarios we need a syntax that is compatible with the most restrictive PARAM tag requirements.

Active Label natural data format concepts.

newObjects Active Label control is not a monolith object but a set of many objects hosted in the Active Label control. This makes practical to have a native data format that describes the label shown in it as series of commands. Therefore the label load process is in fact a process in which a list of commands is processed by the ActiveX and the save/store process is a process in which the ActiveX generates a list of commands for each of its sub-objects (elements, utility objects and so on) and aspects. One of the benefits of this approach is that you can pass a partial list of commands to the ActiveX (see for instance VisiLabel.MergeSrc) and thus add some elements, import data or change only a part of its settings instead of reloading the entire label.

The data file formats are currently 3 - UNICODE text file, ANSI text file and binary file. However all the 3 formats simply encapsulate Active Label's text commands in different ways. Thus you need to know the text commands and how to put them in the corresponding file format.

The textual values in the text commands are escaped on save/generation and un-escaped on load/init - see the text escaping below (after the list of the commands).

The Active Label text commands syntax.

The commands in this section are listed by the object type/aspect type they represent.

VisiLabel object is represented by the following commands:

VISILABEL:MajorVersion,MinorVersion,Dst,PostParams,PostVerb,Caption

Specifies the version by which the command has been generated and the version for which the commands that follow are prepared.

parameters:
MajorVersion - the Active Label Major version number
MinorVersion - the Active Label Minor version number
Dst - the Upload destination (full URL or relative)
PostParams - Additional parameters for the upload operations
PostVerb - post method
Caption - The label caption
example:
VISILABEL:1,0,http://myserver/repository.asp,,POST,Label 21

remarks:
This command has also a future use. It is intended to help the Active Label ActiveX resolve potential version conflicts in the other command syntax rules if such appear in the future versions. 

Part of the VisiLabel object's features are represented by the LAYOUT command (see below)

Label object is represented by the following commands:

LAYOUT: labelWidth, labelHeight, leftMargin, topMargin, rightMargin, bottomMargin: labelBackStyle,labelBackColor,labelBorderStyle,labelBorderColor,labelBorderWidth,labelForeColor: backStyle,backColor,borderStyle,borderColor,borderWidth,foreColor,borderVisible

Specifies the size and other details about the label. Also specifies the colors and other screen settings for the area outside the label.

parameters:
section 1 (defines the labels format)
labelWidth - the width of the label. Corresponds to the VisiLabel.Label.Width property.
labelHeight - the height of the label. Corresponds to the VisiLabel.Label.Height property.
leftMargin, topMargin, rightMargin, bottomMargin -  the left, top, right and bottom margins of the label respectively. Correspond to the VisiLabel.Label.LeftMargin, VisiLabel.Label.TopMargin, VisiLabel.Label.RightMargin, VisiLabel.Label.BottomMargin properties respectively.
section 2 (defines the labels border and color settings)
labelBackStyle - the label area background style. Corresponds to the VisiLabel.Label.BackStyle property.
labelBackColor - the background color for the label area. Corresponds to the VisiLabel.Label.BackColor property.
labelBorderStyle - the border style of the label area. Corresponds to the VisiLabel.Label.BorderStyle property.
labelBorderColor - the border color of the label area. Corresponds to the VisiLabel.Label.BorderColor property.
labelBorderWidth - the border width of the label area. Corresponds to the VisiLabel.Label.BorderWidth property.
labelForeColor - the default foreground color. Corresponds to the VisiLabel.Label.ForeColor property.
section 3 (defines the ActiveX work area borders and colors)
backStyle - the background style of the ActiveX work area (outside the label). Corresponds to the VisiLabel.BackStyle property.
backColor - the background color of the ActiveX work area (outside the label). Corresponds to the VisiLabel.BackColor property.
borderStyle - the border style of the ActiveX work area (outside the label). Corresponds to the VisiLabel.BorderStyle property.
borderColor - the border color of the ActiveX work area (outside the label). Corresponds to the VisiLabel.BorderColor property.
borderWidth - the border width of the ActiveX work area (outside the label). Corresponds to the VisiLabel.BorderWidth property.
foreColor - the foreground color for the ActiveX work area (outside the label). Corresponds to the VisiLabel.ForeColor property.
borderVisible - the border visibility flag for the ActiveX area (outside the label). Corresponds to the VisiLabel.BorderVisible property.

Page object is represented by the following text commands:

PAGE:pageWidth, pageHeight, leftMargin, topMargin, rightMargin, bottomMargin, HorizontalLabelSpacing, VerticalLabelSpacing

Specifies the size and the other details about the paper format.

parameters:
section 1 (the only section at this time)
pageWidth - the width of the page, corresponds to VisiLabel.Page.Width.
pageHeight - the height of the page, corresponds to VisiLabel.Page.Height.
leftMargin - the left margin of the page, corresponds to VisiLabel.Page.LeftMargin.
topMargin - the top margin of the page, corresponds to VisiLabel.Page.TopMargin.
rightMargin - the right margin of the page, corresponds to VisiLabel.Page.RightMargin.
bottomMargin - the bottom margin of the page, corresponds to VisiLabel.Page.BottomMargin.
HorizontalLabelSpacing - the horizontal spacing between the labels on the page, corresponds to VisiLabel.Page.LabelSpacingHorz.
VerticalLabelSpacing - the vertical spacing between the labels on the page, corresponds to VisiLabel.Page.LabelSpacingVert.

Misc object is represented by the following text commands:

MISC:Units,UseDataSource,SaveFormat,FailPrintOnTimeout,labelFlags

 Specifies miscellaneous important general setting of the control

parameters:
section 1 (the only section at this time)
Units - 
UseDataSource - 
SaveFormat - 
FailPrintOnTimeout - 
labelFlags - 

Edit object is represented by the following text commands:

EDIT:EditMode,ShowRulers,ShowScrollBars,Zoom,ProtectLockedElements,AddElementsForbidden

 Specifies some visual appearance settings and settings about the interactive editing mode.

parameters:
section 1 (the only section for now)
EditMode
ShowRulers
ShowScrollBars
Zoom
ProtectLockedElements
AddElementsForbidden

TextDefaults object is represented by the following text commands:

TEXTDEFAULTS:Transparent,Alignment,FontFace,Charset,Bold,Itallic,Underline,Orientation,CodePage

Specifies the text defaults for new elements created interactively or programmatically

parameters:
section 1 (the only section at this time)
Transparent
Alignment
FontFace
Charset
Bold
Itallic
Underline
Orientation
CodePage
 

Variables object (internal data source) is represented by the following text commands:

DATASOURCE:CacheMode,IgnoreErrors,SaveCache:ExternalDSType,ConnectString,Query,Username,Password

Specifies the settings about the data source.

parameters:
section 1 (general parameters)
CacheMode
IgnoreErrors
SaveCache
section 2 (external data source settings - has effect if CacheMode is 0)
ExternalDSType
ConnectString
Query
Username
Password

Each Field in the Variables collection (each field in the internal data source) is represented by this command:

DATAFIELD:FieldName:FieldType,FieldSize,Exclude,LinkedElement,LinkedElementProperty

Defines/adds a field to the internal data source

parameters:
section 1 (The field name)
FieldName
section 2 (the field settings)
FieldType
FieldSize
Exclude
LinkedElement
LinkedElementProperty

Data records in the internal cache maintained by the internal data source (see the Variables object's comments for more information).

CACHEDATA:<comma separated value list>
FIRSTCACHEDATA:<comma separated value list>

Specifies a record of values for the fields configured into the data source. The number of the values must match the number of the fields (see DATAFIELD above) configured into the data source. Typically these entries are put after all the other entries or are passed separately using VisiLabel.MergeSrc for example.

Example:
If we have 3 fields - a text field, a numeric field and a Boolean field we may have entries like these:
CACHEDATA:text value1,100,0
CACHEDATA:text value 2,101,-1
CACHEDATA:text value 3,102,1
The Boolean values are passed as numbers - 0 is false non-0 is true.

The FIRSTCACHEDATA has the same syntax but it also causes the cache to be cleared first. It can be useful for applications that want to be able to clear the contents of the cache when passing new data to the label, but want to do this not using direct method call (such as VisiLabel.Variables.ResetCache).

Drawing objects (elements) on the label

TextLabel element is represented by this command:

LABEL:Name:X, Y, Color, BkColor, Transparent, Alignment, FontFace, FontSize, Charset, Bold, Itallic, Underline, Orientetion: Text: Locked, Hidden, CodePage, Href

Specifies the parameters of a text label element on the label.

parameters:
section 1 (the name of the element)
Name
section 2 (position and visual settings)
X
Y
Color
BkColor
Transparent
Alignment
FontFace
FontSize
Charset
Bold
Itallic
Underline
Orientetion
section 3 (specifies the text displayed by the text label element)
Text
section 4 (standard element settings)
Locked
Hidden
CodePage
Href

Text element (text box) is represented by this command:

TEXT:Name: X, Y, Width, Height, Color, BkColor, Transparent, HAlignment, VAlignment, FontFace, FontSize, Charset, Bold, Itallic, Underline, Orientation:Text: Locked, Hidden, CodePage, Href, Src, Dst, PostParams, PostVerb

Specifies the parameters of a text box element on the label.

parameters:
section 1 (the name of the element)
Name
section 2 (position and visual settings)
X
Y
Width
Height
Color
BkColor
Transparent
HAlignment
VAlignment
FontFace
FontSize
Charset
Bold
Itallic
Underline
Orientation
section 3 (the text displayed in the element)
Text
section 4 (the standard element properties and post/upload parameters)
Locked
Hidden
CodePage
Href
Src
Dst
PostParams
PostVerb

Simple Shape object is represented by this command:

SHAPE:Name: Shape, X, Y, Width, Height, Color, FillColor, LineWidth, LineStyle, FillStyle: Locked, Hidden, CodePage, Href

Specifies the parameters of a simple shape element on the label.

parameters:
section 1 (the name of the element)
Name
section 2 (the shape settings)
Shape
X
Y
Width
Height
Color
FillColor
LineWidth
LineStyle
FillStyle
section 3 (the standard element parameters)
Locked
Hidden
CodePage
Href 

Symbol object is represented by this command:

SYMBOL:Name: X, Y, Color, BkColor, Transparent, Alignment, FontFace, FontSize, Charset, Bold, Itallic, Underline, Orientation: Symbol: Locked, Hidden, CodePage, Href

Specifies the parameters of a symbol element on the label

parameters:
section 1 (the name of the element)
Name
section 2 (the position and the visual settings)
X
Y
Color
BkColor
Transparent
Alignment
FontFace
FontSize
Charset
Bold
Itallic
Underline
Orientation
section 3 (the character code of the displayed symbol)
Symbol
section 4 (the standard element settings)
Locked
Hidden
CodePage
Href 

Image object is represented by this command:

IMAGE: Name: X, Y, Width, Height, SizeAdjust: TransResizeWidth, TransResizeHeight, TransMirror, TransFlip, TransRotate, TransNegative, TransGamma, TransNoise, TransBrightness, TransContrast, TransColorizeEffect, TransColorizeHue, TransColorizeSat, TransRedAdjust, TransGreenAdjust, TransBlueAdjust, TransGray, TransDither, TransThreshold: Locked, Hidden, CodePage, Href, Src, Dst, PostParams, PostVerb

Specifies the settings of an image element on the label

parameters:
section 1 (the name of the element)
Name:
section 2 (the position and size parameters of the elemnt)
X
Y
Width
Height
SizeAdjust
section 3 (image transformations)
TransResizeWidth
TransResizeHeight
TransMirror
TransFlip
TransRotate
TransNegative
TransGamma
TransNoise
TransBrightness
TransContrast
TransColorizeEffect
TransColorizeHue
TransColorizeSat
TransRedAdjust
TransGreenAdjust
TransBlueAdjust
TransGray
TransDither
TransThreshold
section 4 (standard element parameters and upload/post parameters)
Locked
Hidden
CodePage
Href
Src
Dst
PostParams
PostVerb 

Barcode object is represented by this command:

BARCODE: Name: X, Y, Color, Height, HeightLong, Narrow, Wide, DeviceMode, AppendChecksumToText, Orientation: HumanReadable, TextSpacing, FontFace, FontSize, Charset, Bold, Itallic, Underline: Code, Value, AlternateValue, StartCharacter, StopCharacter, AddCheckSum, ShowAlternate, SupplementDistance: Locked, Hidden, CodePage, Href

Specifies the parameters of a barcode element on the label

parameters:
section 1 (the name of the element)
Name
section 2 (position and visual settings)
X
Y
Color
Height
HeightLong
Narrow
Wide
DeviceMode
AppendChecksumToText
Orientation
section 3 (human readable text settings)
HumanReadable
TextSpacing
FontFace
FontSize
Charset
Bold
Itallic
Underline
section 4 (the barcode symbology, value and other settings)
Code
Value
AlternateValue
StartCharacter
StopCharacter
AddCheckSum
ShowAlternate
SupplementDistance
section 5 (the standard element parameters)
Locked
Hidden
CodePage
Href

The file (data stream) formats.

As we mentioned above the 3 natural file formats are simply encapsulations of the text commands. In order to make possible the Active Label to recognize the file format without need of additional instructions each format includes a short (few bytes) prefix that identifies it. The data composed this way is, of course, not for files only. It can be saved to a database, loaded from an URL and so on. Each file format gives some specific benefits to the application and has certain set backs. If your application will not deal with the Active Label data format in-depth this is not something to worry about - you can change the save/upload format as needed at any time. However, if the application needs to do a bit more with the data, for example generate it (just like the HTML content is generated), then it is recommended to evaluate the potential needs of the application (even in remote future) and choose the format that will best suit you from the very beginning. The fact that the ActiveX recognizes the data format automatically by the prefix bytes enables you to use more than one format when initializing/loading the ActiveX. This is particularly useful for WEB applications that generate some of the labels dynamically by generating text commands over certain data. Thus you can use the easiest format wherever it is good enough for the particular tasks and thus save some coding work here and there.

Note that in each of the formats the strings must be escaped! See the next section for the rules.

The formats:

TEXT format. This is a regular text file in which the text commands are put each on a separate line. The prefix bytes are such that they would not change the nature of the file. The file contains ANSI text (i.e. multibyte characters) as all the text files. 

Prefix - the first 4 bytes in the file. Byte 0 and byte 1 contain the ASCII characters 'V' and 'L'. The next 2 bytes (3-d and 4-th) contain the ASCII characters of digits. The 2 bytes together form a 2-digint number which is the format version. Thus a prefix for the current version 1 of the format is VL01
As you can see these are just ASCII characters in the beginning of the file that do not require byte level operations (can be typed in any text editor, or generated by text generating script/module). The version helps the ActiveX determine if it can read the data or not. Thus if future versions of the control begin to support extended structural features the older controls will be able to inform the user about the problem and the newer versions will be able to save old format data for wider compatibility.

Example. In the sample data below we will put just a few commands to illustrate the format usage and we will mark the non-printable characters.

VL01<CR><LF>
VISILABEL:1,0:,LabelUID={F6E51BE6-C0FD-47EB-9E6D-2390269B3FD8},POST:New label 89838265<CR><LF>
LAYOUT:16000,10000,0,0,0,0:-1,15594483,5,0,0,8388608:-1,16777215,0,0,0,8388608,1<CR><LF>
PAGE:0,0,1000,1000,1000,1000,500,500<CR><LF>
MISC:0,1,2,0,0<CR><LF>
.......

The new line is optional after the data prefix - i.e. the first command can start immediately after the prefix. Furthermore the empty lines are ignored, thus if human readability is required the commands can be arranged accordingly.

UNICODE TEXT format. Like the TEXT format this is a regular UNICODE text file which can be opened in any text editor supporting UNICODE text files. The prefix is also such that the nature of the file is not changed by it.

Prefix -  10 bytes. The first two bytes contain the standard prefix for UNICODE text files byte[0] = 0xFF, byte[1] = 0xFE. The text editor applications that support UNICODE text files use and generate that prefix to recognize/indicate that the text file is an UNICODE text file. bytes 2 through 5 contain 2 UNICODE characters 'V' and 'L". The last 4 bytes (6 through 9) contain the UNICODE codes of two digits which like in the other formats form a version number. Thus a prefix for UNICODE format will look like this:

FF FE 56 00 4C 00 30 00 31 00           ..V.L.0.1

In other words in a text editor you just need to type VL01 in the beginning of the file and then save it as UNICODE text file.

The text commands after that are put just like in the TEXT format - each on separate line (see above) but as UNICODE text, of course.

BINARY format. The binary format like the others contains just set of text commands.  The text commands are saved as null terminated UNICODE strings with length saved before each of them (BTW this is the standard technique for saving BSTR values). Thus the data consist of prefix and a number of strings saved this way.

Prefix.- 5 bytes. The first 4 bytes contain byte[0] = 0, byte[1] = 0, byte[2] = 0x56, byte[3] = 0x4C, byte[4] is the version number of the format. As you may have noticed byte 2 and 3 contain the ASCII codes of the letters V and L. Thus the prefix looks like:

00 00 56 4C 01

After the prefix the strings are saved.

text command. Each text command is saved as separate entry. The entry has the following structure:
4 bytes: unsigned integer - length of the string including the null terminator.
(n + 1)*2 bytes - the N UNICODE characters representing the command and 2 bytes of zeros in the end.

Apparently this format is not convenient for applications that work mostly on a text level (most of the WEB applications are such). However, applications that work on a lower level (such as C++ applications) may find it more convenient because it may fit their other needs better. 

String escaping

No matter how you feed label data into the control (through PARAM tags, from an URL or through IPersistStreamInit) the text commands packed in one of the above formats must also be escaped. The escapement rule is the same for all the formats and scenarios and is devised to fit the limitations posed by the most restraining case which is initialization with PARAM elements in the OBJECT tag. This may sound a bit too much, but it has it positive side too. The text commands once escaped can be put in any label data format or initialization code without further processing. This means that an application can use the same escaped string in a file or in PARAM elements in a HTML page which saves the need to devise different behavior for each case.

What is escaped? Not the entire command - only the values in it that contain strings. As an example for this explanation we will use a text command that represents a text label:

LABEL:Element name:9525,1525,0,15594483,-1,-1,Arial,400,1,-1,0,0,0:text label\qs value:0,0,0,http\C//www.server.com/label.activelabel

This command represents a simple text label displayed on the label. It has a name "Element name" by which it can be found or referenced for data binding, specifies a font, text to be displayed in it and a Href URL that can be used by some applications to allow the user click on it to initiate navigation.

The values in bold are textual values and all they must be escaped. Take a look at the display text which is "text label's value" in it we have a quote character which is escaped as \q. The reason for this is the restrictions posed by the places in which we want to be able to put these commands. For instance a PARAM element in an OBJECT tag in a HTML page is like this:
<PARAM NAME="ParameterName" VALUE="the value">
As the command must be specified in the VALUE attribute it is specified between double quotes, but HTML also supports single quotes as string delimiters thus both must be escaped to allow any form allowed by HTML. Furthermore the comma ',' character, the ';' colon and the ';' semicolon characters are used as delimiters in the text commands syntax (';' semicolon is currently unused, but it is reserved for future use). Thus they need escaping as well. The rest of the characters that need escaping are the '\' which is used to mark escape sequence and the <CR>, <LF> and <TAB>. The last 3 characters wont cause problems with HTML, but still there is the possibility that a HTML editor or another application that deals with HTML may delete them or otherwise corrupt the value because of one or more of them. To ensure that this will not happen under any circumstances we need to escape them as well. 

Does it require a lot of code to deal with that? Of course not, usually even the applications that generate the label data use a pre-generated label and simply generate a few of the values of some commands. For example an ASP application puts a <%= someVariable %> to generate one of the values of a command.

The escapement table:
character escaped as
<LF> - line feed \n
<CR> - carriage return \r
<TAB> - tabulation \t
\ - back slash \\
' - quote \q
" - double quote \Q
, - comma \c
; - semicolon \s
: - colon \C
all other characters are put without escaping

For example in ASP you can use a function like this:

Function EscapeString(s)
  Dim str
  str = s
  str = Replace(str,"\","\\")
  str = Replace(str,vbCr,"\r")
  str = Replace(str,vbLf,"\n")
  str = Replace(str,vbTab,"\t")
  str = Replace(str,"'","\q")
  str = Replace(str,"""","\Q")
  str = Replace(str,",","\c")
  str = Replace(str,";","\s")
  str = Replace(str,":","\C")
  EscapeString = str
End Function

In other languages this will look as simple as the above and may be even simpler depending on the language capabilities. If you use a replace function like the Replace in VBScript be sure to escape the '\' backslash first.

Unescape is typically not needed by the applications that use the control, but it is straightforward and can be implemented easily if needed.

 

 

newObjects Copyright 2001-2006 newObjects [ ]