SharePoint, Data View web parts and functions in the ddwrt namespace

THIS BLOG POST TURNED INTO AN MSDN ARTICLE. SEE http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odc_SP2003_ta/html/OfficeSharePointDDWRT.asp FOR THIS ARTICLE. BUT… ALSO CHECK THIS BLOG POST, IT CONTAINS SOME INFO CENSORED IN THE ARTICLE;-)

Summary

Topic: Data View web part, XSLT, XSLT Extension Object, ddwrt namespace, Windows SharePoint Services, SharePoint Portal Server 2003, FrontPage 2003

 

SharePoint has a powerful type of web parts: Data View web part (DVWP) that has the ability to provide an XSLT transformation on XML data retrieved from a data source. FrontPage 2003 has great support for defining the data source to retrieve XML data from, for WYSIWYG creating of XSLT views on this data, and for converting CAML list views (WSS list views) to XSLT.

 

In the XSLT generated by FrontPage an XSLT Extension Object is used to provide functions in the ddwrt namespace to perform often needed functionality like accessing properties of a list or firing events to connected web parts. This article tries to shed some light on these undocumented but much used functions.

Introduction

This is an article I started exactly one year ago, but never finished. I was using one of the most powerful features you get when using FrontPage in combination with Windows SharePoint Services (WSS) and Microsoft Office SharePoint Portal Server 2003 (SPS): the ability to create Data View web parts (DVWP). It is one year later, Christmas again, and in the meantime not much information appeared on the subject of this article: the functions available in the ddwrt namespace as used in the FrontPage generated Data View XSLT code.

 

Many introductory articles have already been written on the topic of DVWPs, so I will not repeat all this useful information. I consider those articles as prerequisite reading and will try to go from there by showing the available functions, and what they do.

 

Disclaimer: I’m on vacation and only have access to Reflector, the Microsoft.SharePoint.dll and Word, so no possibility to check out things. I have to rely on my notes taken in the past, and the disassembled code using Reflector. If you find any untruthful information or if you have any additional information: let me know and I will correct/include it in this article.

 FrontPage and DVWPs

One of the first things to mention is that although FrontPage is a great tool to create a DVWP, all the logic is already available in SharePoint (WSS) itself (see also http://weblogs.asp.net/soever/archive/2004/05/14/131698.aspx). This logic consists of the following parts:

 

  • Microsoft.SharePoint.WebPartPages.DataViewWebPart, a class available in the Microsoft.SharePoint.dll assembly that implements the DVWP functionality.
  • Microsoft.SharePoint.WebPartPages.DdwRuntime, an internal class available in the Microsoft.SharePoint.dll assembly that is made available as a XSLT Extension Object that provides a set of functions in the ddwrt namespace. The set of functions this article is about!!
  • Data view web part definition, a .dwp file describing the assembly implementing the web part and the configuration parameters for the web part.

 

It is possible to create data DVWPs without using FrontPage. It is difficult, but it is possible. A DVWP is just a .dwp file which is an XML file that contains information for the data query and the XSLT transformation.

 

One thing FrontPage does really good is the conversion of a SharePoint list view (defined in Collaborative Aplication Markup Language, or CAML for short) to an XSLT transformation that transforms the data retrieved using the list web service to the same view as defined in CAML. In the past I wrote a weblog entry (http://weblogs.asp.net/soever/archive/2004/03/10/87295.aspx) about how FrontPage accomplishes this wizardry using an XSLT transformation that is available in your office directory.

 

Besides the CAML transformation, FrontPage provides WYSIWYG functionality to create a nice view on data. It does this by interactively defining an XSLT transformation on XML data retrieved from multiple types of data sources.

DataViewWebPart, Vars and the ddwrt namespace

It is the Data View web part implemented in the class Microsoft.SharePoint.WebPartPages.DataViewWebPart that utilizes the internal class Microsoft.SharePoint.WebPartPages.DdwRuntime to provide utility functions. John Janssen stated in a usenet discussion: “They were created to maintain parity between data views and list views (so that in the convert case the data view behaves just the same as the list view).” But the problem is that we want to give our own twist to how the result works, otherwise we didn’t have to convert them in the first place! The utility functions are made available by creating an XSLT Extension Object. To take a peek in the kitchen have a look at the obfuscated function Microsoft.SharePoint.WebPartPages.DataViewWebPart.q(). In this functions three important things happen:

  1. The DdwRuntime class is added as an Extension Object
  2. The Vars name-value collection as available in the XSLT transformation through ddwrt:Vars[“name”], filled with all kind of interesting information
  3. A large set of XSLT parameters is defined.

 

The powerful thing of the Vars collection is that this collection is persisted over page request in the ASP.NET viewstate, so it can be used to persist information from the XSLT transformation of the current page request to the XSLT transformation of the next page request.

 

The Vars name-value pairs that I could find:

Name

Value

Filter

Empty string

View

{GUID}, the “StorageKey”of the web part. Don’t know yet what this means.

FreeForm

FALSE

WPQ

WPQ1

 

XSLT parameters I could find (no namespace):

Parameter

Value

HttpHost

URL of the top level site of the current web

Language

LCID of the language used on the site, for example 1033 for an English site

ImagesPath

Url of the images path, in the context of the current web, so for example http://server/sites/test/_layouts/images/

HttpPath

Url of the path to the appropriate OWSSVR.DLL file in the context of the web we are in. For example http://server/sites/test/_vti_bin/owssvr.dll?CS=109, where CS=109 means that the UTF-8 character set is used for all communication to owssvr.dll.

HttpVDir

Root directory of the current subsite, so for the page http://server/sites/test/default.aspx, the value is http://server/sites/test/.

PageUrl

The directory of the currently requested page. For example http://server/sites/test/default.aspx.

Project

The root folder of a list, if the current page request is in the context of a list. This is the name of the folder that contains all the files used in working with the list. In most cases this is the Forms folder.

View

{GUID}, the “StorageKey”of the web part. Don’t know yet what this means.

ListProperty_TemplateUrl

When the current page request is in the context of a list, and the list is a Document Library:

Url of the template document for this document library.

ListUrlDir_FALSE

When the current page request is in the context of a list: Complete Url to the root folder of the list(see Project).

ListUrlDir_TRUE

When the current page request is in the context of a list: Name of the root folder, same as Project (see Project).

URL_New,URL_NEW

When the current page request is in the context of a list: Url to the page for creating a new item in the list (newform).

URL_Edit, URL_EDIT

When the current page request is in the context of a list: Url to the page for editing an existing item in the list (editform).

URL_Display, URL_DISPLAY

When the current page request is in the context of a list: Url to the page containing the default view of the list (displayform).

 

If you look at the XSLT code generated by FrontPage you will find a large set of additional XSLT parameters. To have a look at the values of a lot of these parameters you could include the following XSLT code that writes out their values to the HTML code generated for the DVWP:

 

<!-- Dump parameters -->

PageUrl: <xsl:value-of select="$PageUrl"/><br/>

HttpHost: <xsl:value-of select="$HttpHost"/><br/>

List: <xsl:value-of select="$List"/><br/>

URL_Display: <xsl:value-of select="$URL_Display"/><br/>

HttpVDir: <xsl:value-of select="$HttpVDir"/><br/>

View: <xsl:value-of select="$View"/><br/>

FilterLink: <xsl:value-of select="$FilterLink"/><br/>

Language: <xsl:value-of select="$Language"/><br/>

dvt_adhocmode: <xsl:value-of select="$dvt_adhocmode"/><br/>

dvt_adhocfiltermode: <xsl:value-of select="$dvt_adhocfiltermode"/><br/>

dvt_fieldsort: <xsl:value-of select="$dvt_fieldsort"/><br/>

dvt_sortfield: <xsl:value-of select="$dvt_sortfield"/><br/>

dvt_groupfield: <xsl:value-of select="$dvt_groupfield"/><br/>

dvt_groupdisplay: <xsl:value-of select="$dvt_groupdisplay"/><br/>

dvt_sortdir: <xsl:value-of select="$dvt_sortdir"/><br/>

dvt_groupdir: <xsl:value-of select="$dvt_groupdir"/><br/>

dvt_filterfield: <xsl:value-of select="$dvt_filterfield"/><br/>

dvt_filterval: <xsl:value-of select="$dvt_filterval"/><br/>

dvt_filtertype: <xsl:value-of select="$dvt_filtertype"/><br/>

dvt_firstrow: <xsl:value-of select="$dvt_firstrow"/><br/>

dvt_p2plinkfields: <xsl:value-of select="$dvt_p2plinkfields"/><br/>

dvt_nextpagedata: <xsl:value-of select="$dvt_nextpagedata"/><br/>

dvt_grouptype: <xsl:value-of select="$dvt_grouptype"/><br/>

dvt_sorttype: <xsl:value-of select="$dvt_sorttype"/><br/>

dvt_groupsorttype: <xsl:value-of select="$dvt_groupsorttype"/><br/>

dvt_apos: <xsl:value-of select="$dvt_apos"/><br/>

filterParam: <xsl:value-of select="$filterParam"/><br/>

ImagesPath: <xsl:value-of select="$ImagesPath"/><br/>

ListUrlDir: <xsl:value-of select="$ListUrlDir"/><br/>

EMail: <xsl:value-of select="$EMail"/><br/>

ListUrlDir_TRUE: <xsl:value-of select="$ListUrlDir_TRUE"/><br/>

URL_DISPLAY: <xsl:value-of select="$URL_DISPLAY"/><br/>

URL_EDIT: <xsl:value-of select="$URL_EDIT"/><br/>

URL_New: <xsl:value-of select="$URL_New"/><br/>

WebQueryInfo: <xsl:value-of select="$WebQueryInfo"/><br/>

URL_Edit: <xsl:value-of select="$URL_Edit"/><br/>

URL_Lookup: <xsl:value-of select="$URL_Lookup"/><br/>

<!-- Dump parameters -->

 

The ddwrt namespace, a reference

And now we come to the meat of this article. A reference guide to the set of functions implemented in the ddwrt namespace. Have a look at the XSLT code generated by FrontPage, and you know what I’m talking about: those functions starting with ddwrt:.

 

What follows is an overview of all public functions in the internal class DdwRuntime that is automatically available in the XSLT code in a DVWP.

 

public DdwRuntime();

Nothing really interesting is happening here, and you don’t call the constructor yourself. This function is automatically called on instantiating the DdwRuntime class as an XSLT Extesion Object. Don’t bother about it.

 

public string AutoHyperLink(string szStr, bool preserveWhitespace);

This function returns the passed szStr string parameter. The preserveWhiteSpace parameter is ignored.

 

public string AutoNewLine(string szStr);

This function goes through the string szStr and does the following replacements:

From

To

&

&amp;

\

&#39;

< 

&lt;

> 

&gt;

\n

<br/>

<space>

If not the first space in a row, translated to &nbsp;

So: “a b” à “a b”, but “a  b” -> “a &nbsp;b”

&quot;

\x00a0

&nbsp;

So the function converts a plain text string containing special characters (in the HTML sense) and newlines to a string that can be inserted into HTML and remains formatted in the same way.

 

public string ConnEncode(string szData);

This function goes through the string szData and does the following replacements:

From

To

#

&23

&

&26

&27

*

&2A

;

&3B

\

&5C

So the function converts a string to a format that can be passed as a parameter in the URL string. If you look at the name of the function, this function is used to encode the connection information that is communicated between connected web parts. Web part connection information is probably encoded because connection information between web parts on separate web part pages are passed on the URL. Creating web part connections between web parts on different web part pages is not available through the web interface for defining web part connections, but FrontPage 2003 does provide functionality to make web part connections between web parts on different pages.

 

public string Counter();

The Counter() function returns an incremental number. The number even increases over pages refreshes so you are ensured of a new number on each call, even over page requests.

 

public string FieldFilterImageUrl(string szFieldName);

If the parameter szFieldName equals the name of the currently selected filter field (assumable the internal name of the field), this function returns the text /_layouts/images/filter.gif , otherwise it returns the text /_layouts/images/blank.gif.

 

public string FieldFilterOptions(string szName);
This function always returns an empty string.

 

public string FieldPrefix();

This function always returns the text urn:schemas-microsoft-com:office:office#, this is the namespace used for all fields defined in for example a SharePoint list.

 

public string FieldSortImageUrl(string szName);

If the parameter szName equals Desc,  the text /_layouts/images/rsort.gif is returned, otherwise the text /_layouts/images/sort.gif is returned,

 

public string FieldSortParameters(string szName);

This function always returns an empty string.

 

public string FilterLink();

This function always returns an empty string.

 

public string FormatDate(string szDate, long lcid, long formatFlag);

The parameter szDate is converted to a DateTime. Based on the formatFlag parameter which can have a value from 0..15, a new DateTime string is constructed in the given locale lcid. This result is returned by the function.

Flag

Formatting string

Result

1 (0001)

“d”

 todo, see standard .net docs

3 (0011)

“D”

 todo, see standard .net docs

4 (0100)

“t”

 todo, see standard .net docs

5 (0101)

“g”

 todo, see standard .net docs

7 (0111)

“f”

 todo, see standard .net docs

12 (1100)

“T”

 todo, see standard .net docs

13 (1101)

“G”

 todo, see standard .net docs

15 (1111)

“F”

 todo, see standard .net docs

 

public string FormatDateTime(string szDate, long lcid, string szFormat);

The parameter szDate is converted to a DateTime. Based on the szFormat parameter which is a standard DateTime formatting flag, a new DateTime string is constructed in the given locale lcid using GetDateTime(szDate).ToString(szFormat, lcid).

 

public string GenDisplayName(string szValue);

The parameter szValue is converted to a DateTime, and returned in the format “d” using GetDateTime(szValue).ToString(“d”, CultureInfo.InvariantCulture). If the conversion to a DateTime fails, the value of the szValue parameter itself is returned.

 

public string GenFireConnection(string szConnectStr, string szOtherPostback);

Fire a connected web part event with a call to __dopostback(), which is the function called in ASP.NET to do a post back to the server. This function uses the GenFireServerEvent() function to do the actual firing of the event. The following event text is “fired”: __connect={szConnectStr};szOtherPostback. See http://www.kbalertz.com/kb_838685.aspx for an example of firing a connection event from XSLT code.

 

public string GenFireServerEvent(string szEventStr);

Fire a server event with a call to __dopostback()(), which is the function called in ASP.NET to do a post back to the server. The szEventStr is the actual event text to “fire”.

 

protected DateTime GetDateTime(string szDate);

This function returns DateTime.Parse(szDate).ToUniversalTime().ToLocalTime().

The current coordinated universal time (UTC) is converted to local time, adjusting to the local time zone and daylight saving time.

 

public string GetFileExtension(string szUrl);

This function returns the file extension of the give URL parameter szUrl.

 

public static string GetStringBeforeSeparator(string szval);

Given the string parameter szval, this function returns the part before the first “;” or “#” character. So for example for the string “abaca;dabra”, the string “abaca” is returned.

 

public string GetVar(string szName);

There is a name-value collection available in the called Vars. This function retrieves the value for the entry with the name szName from the collection.

 

public bool IfNew(string szCreatedTime);

This function returns true if the parameter szCreatedTime is “younger” than 2 days, otherwise false is returned.

 

public bool IsPrivilegedUser();

This function returns true if the current user doing the page request is a privileged user (administrator) in the current web, and false if the user is not an administrator. False is returned if the page request is not in the context of a SharePoint web. This function returns the result of a call to SPWeb.IsPriviledgedUser on the current web.

 

public string Limit(string szInputText, int len, string szMoreText);

Given the string parameter szInputString, this function returns the first len characters, with the string szMoreText appended. Note: This function makes a mess of HTML strings, because the string is just cut off, without taking HTML formatting tags into account.

 

public string ListProperty(string szPropName);

This function returns the value of the given property szPropName when the page request is in the context of a list. There are some special properties defined that don’t really have to map to properties directly available on the list.

Field name

Information

 title

The displayed title for the list.

 description

The description for the list.

 direction

Direction of the reading order for the list. This property contains the string ltr if the reading order is left-to-right,  rtl if the reading order is right-to-left, or it contains none.

 basetype

Number with the base type of the list. Dive into list templates for more information on this topic. SharePoint contains the following base types:

Name

Description

DiscussionBoard

Discussion board.

DocumentLibrary

Document library.

GenericList

Generic type of list template used for most lists.

Issue

Issue-tracking list.

Survey

Survey list.

UnspecifiedBaseType

No base type specified.

Unused

Unused.

 servertemplate

String with the name of the template the list is based on.

 defaultviewurl

Url of the page providing the default view for the list.

 url

Url of the list.

 rootfolderurl

Url of the root folder of the list. The rootfolder is the folder that contains all the files used in working with the list. In most cases this is the Forms folder.

 version

The version number of the list.

 name

The internal name of the list.

moderatedlist

“1” if content approval is enabled, “0” if content approval is disabled.

attachmentsdisabled

“1”if attachements can be added to items in the list, “0”if attachements can not be added to items in the list.

multiplemtgdatalist

“1” if the list in a Meeting Workspace site can contain data for multiple meeting instances within the site, “0”if not.

templateurl

Url of the template document used to create a new document in a document library.

webimagewidth

If a picture library, the webimagewidth is the width value used to display images in a picture library (in pixels), otherwise an empty string.

webimageheight

If a picture library, the webimageheight is the height value used to display images in a picture library (in pixels), otherwise an empty string.

thumbnailsize

If a picture library, the thumbnailsize is the size in pixels of the height or width, whichever is longest, to use for thumbnails in the picture library, otherwise an empty string.

itemcount

Number of items in the list. Note that the value of the itemcount does not include folders in a document library but does include files within subfolders in a document library.

 

public string MapToAll(string szProgID, string szExt);

This function returns a concatenation of Icon|ProgID|Control, as defined in the “docicon.xml” file. If the specified parameter szProgID is not found in “docicon.xml”, the ProgID is determined by the extension specified in the szExt parameter. This function uses the function MapToControl() to determine the value of Control, and the function MapToIcon() to determine the value of Icon.

 

public string MapToControl(string szProgID, string szExt);

This function returns the value of Control for the given ProgID (szProgID) or extension (szExt). A Control is the control to open the document with, like SharePoint.OpenDocuments.

 

public string MapToIcon(string szProgID, string szExt);

This function returns the Icon for the for the given ProgID (szProgID) or extension (szExt). The Icon is the name of the gif file, without the complete path to the file.

 

public string NameChanged(string szName, long id);

I have no idea. Something happens with NameChangedCounters…

 

public string PresenceEnabled();

This function returns “true”/“false” if the current page request is in the context of a SharePoint web, and there is presence enabled/disabled for the web. If the current page request is not in the context of a SharePoint web, an empty string is returned.

 

public string SelectOptions(string szName);

Returns an empty string.

public string SetVar(string szName, string szValue);

There is a name-value collection available called Vars. This function sets the value szValue for the name szName in the collection.

 

public string ThreadStamp();

This function returns the current time (Now) in the format: yyyyMMddHHmmss

 

public string Today();

This function returns DateTime.Now.ToString("G", CultureInfo.InvariantCulture);

 

public string TodayIso();

This function returns DateTime.Now.ToString("s", CultureInfo.InvariantCulture);

 

public string UrlBaseName(string szUrl);

This function returns the basename of the given url szUrl. So for example for: /a/b/basename.ext, the value basename is returned.

 

public string UrlDirName(string szUrl);

This function returns the directory name of the given url szUrl.So for example for: /a/b/basename.ext, the value /a/b/ is returned.

 

public string UrlEncode(string szUrl);

This function returns HttpUtility.UrlEncode(szUrl). The string parameter szUrl is encoded so it can be safely used on the url.

 

public string URLLookup(string ListName, string FieldAttributeName, string FieldPosition);

It is not completely clear to me what you can do with this function. Especially the possible values for the parameters FieldAttributeName and FieldPosition are a bit unclear. The thing that puzzles me is the name of the function: UrlLookup(). So it dies not lookup a value of a property in the list, it returns an Url. The only real usage I could find is for looking up information in the special SPWeb list UserInfo, which contains information about all users that ever visited the web, if the current page request is in the context of a SharePoint web. If this function is called with the parameter ListName set to UserInfo, the following url is returned:

/_layouts/<LCID>/userdisp.aspx?Force=True&ID=<ID of user>. Note that the Force=True parameter forces the redirection to a a page that displays the information as stored in the UserInfo table, instead of redirection to the public MySite page of a user when available (only for SharePoint Portal Server). Remove the “Force=True&” string from the result string in case of a SharePoint Portal Server environment.

 

public string UserLookup(string UserName, string FieldName);

The Fieldname parameter can be either Email, ID, or Login. The UserName parameter is in the format as defined by FieldName. This function always returns the specified user in login format: DOMAIN\User.

public string Ascending { get; }

Gets the string “Asc”.

 

public string BlankGif { get; }

Gets the string images/blank.gif.

 

public string DefaultUrl { get; }

Accessing this property triggers the caching of the XML file docicon.xml. This file contains the mapping from file extension to icons, and to the progid of the application to open a file with a given file extension with. I don’t know what exactly is returned.

 

public string Descending { get; }

Gets the string Desc.

 

public NameValueCollection ExtensionCtrlMap { get; }

Get a NameValue collection as defined in the XML file mapicon.xml, needs further investigation.

 

public NameValueCollection ExtensionMap { get; }

Get a NameValue collection as defined in the XML file mapicon.xml, needs further investigation.

 

public NameValueCollection ExtensionTextMap { get; }

Get a NameValue collection as defined in the XML file mapicon.xml, needs further investigation.

 

public string Filter { get; }

Gets the string Filter.

 

public string FilterGif { get; }

Gets the string images/filter.gif.

 

public string FormFieldDecoration { get; }

Gets the string urn:schemas-microsoft-com:office:office#.

 

public string FreeForm { get; }

Gets the string FreeForm.

 

public string GetGuid { get; }

Gets a GUID using new Guid().ToString("D", CultureInfo.InvariantCulture).

 

public string GetProgID { get; }

Gets an empty string.

 

public string ListParameter { get; }

Gets the string ListParam.

public string MapString { get; set; }

Get the contents of the complete XML file docicon.xml as a string. This string is cached on first access. The Set functionality overrides the information read from docicon.xml.

 

public NameValueCollection ProgIDCtrlMap { get; }

Get a NameValue collection as defined in the XML file mapicon.xml, needs further investigation.

 

public NameValueCollection ProgIDMap { get; }

Get a NameValue collection as defined in the XML file mapicon.xml, needs further investigation.

 

public NameValueCollection ProgIDTextMap { get; }

Get a NameValue collection as defined in the XML file mapicon.xml, needs further investigation.

 

public string RootFolder { get; }

Gets the string RootFolder.

 

public string RSortGif { get; }

Gets the string images/rsort.gif.

 

public string SearchString { get; }

Gets the string SearchString.

 

public string SortDir { get; }

Gets the string SortDir.

 

public string SortField { get; }

Gets the string SortField.

 

public string SortGif { get; }

Gets the string images/sort.gif.

 

public string ThreadStampFormat { get; }

Gets the string yyyyMMddHHmmss.

 

public NameValueCollection Vars { get; set; }

The Vars name-value collection is filled with all kind of interesting information. See the section DataViewWebPart, Vars and the ddwrt namespace for more information. This collection is persisted over page request in the ASP.NET viewstate, so it can be used to persist information from the XSLT transformation of the current page request to the XSLT transformation of the next page request.

 

public string View { get; }

Gets the string View.

 

public DataViewWebPart Wp { get; set; }

Gets or set the DataViewWebPart object we are currently working on.

public string WPQ { get; }

Gets the string WPQ.

 

Conclusion

I only touched on a small part of the magic world of Data View web parts. A lot more information is there to explore to grasp the complete power of the possibilities of this web part.

 

Although the possibilities of DVWPs is almost unlimited, be aware of the following downsides of using them:

 

  • You need an experienced XSLT coder to do more advanced modifications beyond the standard possibilities of FrontPage, and you end up there pretty soon!
  • DVWPs are difficult to reuse from one situation to another situation, because certain information is hard coded in the DVWP. This makes is hard to maintain modifications made to DVWPs over multiple instances of DVWPs.
  • It is difficult to deploy DVWPs due to the way certain information is hard coded in the DVWP

 

One last point I wanted to mention is that it is not possible to create JScript code in your XSLT code, due to security reasons. So all extension code available in your XSLT must either come from standard XSLT code, or from the functions as described in this article.

References

Have a look at the following links for more information on Data View web parts:

 

Working With the Data View Web Part: http://www.sharepointcustomization.com/resources/whitepapers/webpartdocs/dataview_wp.doc

 

SharePoint: The power of the DataView Web Part

http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx? EventID=1032256050

 

One of the guys from the Microsoft Team who does a lot of newsgroup work is John Janssen. Look him up in relation to DVWPs with the following queries:

 

 

Published Monday, January 3, 2005 1:29 AM by svdoever
Filed under:

Comments

No Comments