Click here to Skip to main content
15,881,852 members
Articles / Programming Languages / XSLT

ToDoList's StyleSheets: A Tutorial

Rate me:
Please Sign up or sign in to vote.
4.88/5 (22 votes)
3 Apr 2021CPOL12 min read 82.3K   1.3K   42   30
My learnings and the problems that I encountered while making my very first Stylesheet for ToDoList
In this article, I have put together the things that I found useful in the hope that it will help you to put you on track to make your own StyleSheets for ToDoList.

Introduction

I have just built a custom StyleSheet for TDL, my very first XSLT file, it is not an easy task when you have never touched an XSLT file. It is not a surprise that StyleSheets delivered with TDL are not suited to beginners learning, but it was a surprise to me that all the needed information was spread across so many places.

So, I write this article to put together things that I have found useful in hope it will help you to put you on track to make your own StyleSheets for ToDoList.

Keep in mind that English is still a foreign language for me. Please, feel free to report mistakes.

Background

For beginners, basic knowledge of XML format is preferable, and knowledge of HTML will help too. For advanced StyleSheets, knowledge of XML, HTML and XPath is mandatory.

The XML File Format

A quick introduction to XML file format. ToDoList's TaskLists and StyleSheets are XML files.

The basic structure of an XML file is an Element, an element is made of an opening tag and a closing tag.

<TODOLIST>
</TODOLIST>

The opening tag of an element can contain Attributes, a value is associated with each attribute, the value is always a string, even numeric values.

<TODOLIST PROJECTNAME="My TaskList"; FILEFORMAT="10"> </TODOLIST>

And an element can contain some text or other elements nested between its two tags.

<TODOLIST PROJECTNAME="My TaskList" FILEFORMAT="10">
<TASK TITLE="My first Task">
<TASK TITLE="My sub task">
<COMMENTS>My comments</COMMENTS>
<CATEGORY>MyCat</CATEGORY>
</TASK>
</TASK>
<TASK TITLE="My second Task">
</TASK>
</TODOLIST>

An XML file is made of a single main element (root) containing everything nested inside. By itself, an XML file is organized as a tree, the single main element is the root of the tree.

  • TODOLIST is the Root Element. It contains other elements.
  • TASK is an Element. It contains other elements.
  • COMMENTS is an Element. It contains text.
  • PROJECTNAME is an Attribute of TODOLIST with Value
  • FILEFORMAT is an Attribute of TODOLIST with Value
  • TITLE is an Attribute of TASK with Value

<TODOLIST PROJECTNAME="My TaskList" FILEFORMAT="10">
<TASK TITLE="My first Task">
<TASK TITLE="My sub task">
<COMMENTS>My comments</COMMENTS>
<CATEGORY>MyCat</CATEGORY>
</TASK>
</TASK>
<TASK TITLE="My second Task">
</TASK>
</TODOLIST>

A TaskList contains many more elements and attributes.

For more details on XML, XSLT, HTML or XPath, I recommend w3schools.com.

First, Get a TDL StyleSheet Example

At first, I searched for an example StyleSheet and found that the article XSL Transform for ToDoList contains a StyleSheet for TDL aimed to be an example. My first experiments were rather frustrating until I understood that the example was buggy.

Here are the corrections for the StyleSheet.

Everywhere it is needed, replace:

XML
<xsl:apply-templates />

with:

XML
<xsl:apply-templates select="TASK" />

and, replace:

XML
... "@COMMENTS"

with:

XML
... "COMMENTS"

After correction, the example works far better. The corrected file is bpsToDoListStyler_Rev019.xsl.

Experimenting with the Example StyleSheet

To play with the example, I recommend to start with Tree view and get all attributes. The output is formatted in HTML and can be used to Print, Preview or Transform the TaskList. A lot of options are commented out, just uncomment them to see what happens.

How ToDoList Deals with StyleSheets

TDL can use StyleSheets for operations such as Print, Export or Transform. In every case, TDL generate a specific temporary TaskList that reflect actual settings, and the StyleSheet is applied on that temporary TaskList.

The specific TaskList is built using these criteria:

  • If in Tree view, the temporary list will be a tree, if in List view, the temporary list will be flat.
  • Actual sorting will be used.
  • The dialog box lets you choose which tasks are included and which attributes.

Choose the result you want:

  • Print: The output will be printed on paper.
  • Preview: The output will be shown on screen the same as it would be printed.
  • Transform: The output will be saved on disk and shown on your internet navigator if Text or HTML formats are used. The difference with Print and Preview is that the HTML is not limited to printable features. The other usage of Transform is to generate other XML files.

The temporary TaskList file is stored in directory %temp%, the file name is TaskList name followed by .intermediate.txt. So, the temp file of MyTasks.tdl will be MyTasks.intermediate.txt in the %temp% directory. Open in a text editor to see the structure and which elements and attributes are in the file.

Pitfalls with TDL StyleSheets

Empty Result

The Problem

It is all in the title. The result is empty.

The Answer

First possibility, there is a compilation error. You have to find what is the error and correct it. Unfortunately, TDL does not provide anything that can give even basic clue of what is going wrong. If you don't have any kind of debugger, the best is to start with a generic working example and make incremental changes with a test to validate each change.

Second possibility, there is no match or nothing to output. First make sure your StyleSheet always outputs something when the root matches. The easiest way to do this is by ensuring that something will be put on the result whatever the content of the TaskList. By getting something as a result, you ensure that the StyleSheet compiles OK. If you don't get what you should, something is certainly wrong in the logic of the StyleSheet.

Ignored XML Document with an <xsl:template match="/"> Template

The Problem

Obviously, the XML tree is not walked, and if:

XML
<xsl:template match="/">

is replaced with:

XML
<xsl:template match="/TODOLIST">

everything works.

The Answer

The whole trick is that <xsl:template match="/"> matches the XML document and the child element is TODOLIST when TASK is expected.

If you have a document matching template, you also need a root matching template, because the first has to call the second.

Accents in StyleSheets

The Problem

The file encoding can be a problem when you use accents, the problem is so huge that even if only in a comment, it is enough to fail to compile. You will need to apply the right encoding.

The Answer

To solve the problem, there is two places to check:

  • Declare the encoding in the xml tag:
    XML
    <?xml version="1.0" encoding="utf-8" ?>
  • In your text editor, choose the char encoding that fit your needs: UTF-8, UTF-16, iso-8859-1 ...

UTF-8 is generally a good choice. In any case, make sure both match.

Doing "apply-templates" on Elements that don't have "template"

The Problem

That was the error in the example for TDL. The generic...

XML
<xsl:apply-templates />

...will match any element inside the current element. It is a problem when you encounter a COMMENT (or any element that is not a TASK). Since the COMMENT has no matching template, the default behavior is applied, the text in the COMMENT is simply dump as is to output.

This is the reason of the unformatted text that appears when you run the original buggy example as in file bpsToDoListStyler_Rev018.xsl.

The Answer

Use apply-templates only for nested TASKs.

XML
<xsl:apply-templates select="TASK" />

Note: The same problem also applies to TDL 6.9.6 and earlier StyleSheets: Project-Overview-HTML.xsl, SimpStyler0.2.xsl, TodoListStyler_Firefox.xsl and TodoListStyler_v1.5.xsl.

An alternative is to declare a template that will match everything.

XML
<xsl:template match="*">

Be careful of what you do, it is as powerful as dangerous if not mastered, it easily leads to unwanted results.

XML StyleSheets Snippets

XML files are organized like trees and XSLT are basically about walking the tree while applying the transformation, more sophisticated transformations can be done at the cost of more complicated programming if input tree structure doesn't match the output tree structure.

Some of the examples are using html tags, look at the next chapter for explanations about html tags in a StyleSheet.

XSLT Comments

Advice: Document your xslt StyleSheets with comments everywhere you do something not obvious.

XML
<!-- My Comments anywhere I need -->

Beginners often think that documenting is a waste of time, it is wrong. You will see that it is not a waste of time when you will come back to your code six months or a year later because comments will help you to recall what the code was intended to do.

StyleSheet Organization

xslt is based on a template matching language. It means that there is no explicit entry point and there is no explicit chaining of matching templates, it is data driven. If more than one template matches the current data, it is not an error, the right template is simply chosen at runtime by following some rules.

StyleSheet Launch

A StyleSheet always starts by trying to execute a template that matches the whole document.

XML
<xsl:template match="/">

If it fails, the interpreter looks for a template that matches the root of the XML file. Like...

XML
<xsl:template match="/TODOLIST">

...which is a template that matches only a root element named TODOLIST. Or...

XML
<xsl:template match="TODOLIST">

...which is a template that match only an element named TODOLIST, not necessary a root.

Matching Templates

Note that matching templates are not linked anywhere in the XSLT code.

XML
<xsl:apply-templates />

will decide dynamically which matching template to call and in which order. In order to keep some control over the StyleSheet execution, it is preferable to use the syntax...

XML
<xsl:apply-templates select="TASK"/>

...where you specify which element you want to match.

Hello World

The classical one. See file HelloWord.xsl for the complete example.

XML
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    
    <xsl:template match="/">
        <xsl:text>Hello Word</xsl:text>
    </xsl:template>
</xsl:stylesheet>

The <xsl:output method="text"/> tells that the output is raw text, no formatting, no nothing, simply text.

The <xsl:template match="/"> is matching the root element of any document.

The element <xsl:text> surrounds whatever text you want to output

Hello ToDoList

See file TDLSS 1.xsl for the complete example.

XML
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html" indent="yes" 
                doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" />
    
    <xsl:template match="/TODOLIST">
        <xsl:element name="html">
            <xsl:element name="body">
                <xsl:text>Hello ToDoList</xsl:text>
            </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

The <xsl:output method="html" ... tells that the output is an html page, with all usual formatting, at the cost of a little complication.
The <xsl:template match="/TODOLIST"> will match only a root element named TODOLIST, this is the name of the root element of a tasklist.

Reading Attributes Values

See file TDLSS 2.xsl for the complete example.

XML
<xsl:template match="TODOLIST">
    <xsl:element name="html">
        <xsl:element name="head">
            <xsl:element name="title">
                <xsl:value-of select="@PROJECTNAME" />
            </xsl:element>
        </xsl:element>
        <xsl:element name="body">
            <xsl:value-of select="@PROJECTNAME" />
            <xsl:element name="br" />
            <xsl:value-of select="@FILENAME" />
            <xsl:element name="br" />
        </xsl:element>
    </xsl:element>
</xsl:template>

The <xsl:value-of select="@PROJECTNAME" /> output the value of the PROJECTNAME attribute.

Walking the Tree

See file TDLSS 3.xsl for the complete example.

XML
<xsl:template match="TODOLIST">
    <xsl:element name="html">
        <xsl:element name="head">
            <xsl:element name="title">
                <xsl:value-of select="@PROJECTNAME" />
            </xsl:element>
        </xsl:element>
        <xsl:element name="body">
            <xsl:value-of select="@PROJECTNAME" />
            <xsl:element name="br" />
            <xsl:value-of select="@FILENAME" />
            <xsl:element name="br" />
            <xsl:element name="br" />
            <xsl:apply-templates select="TASK" />
        </xsl:element>
    </xsl:element>
</xsl:template>

<xsl:template match="TASK">
    <xsl:value-of select="@TITLE" />
    <xsl:element name="br" />
</xsl:template>

The <xsl:apply-templates select="TASK" /> is looking for any element named TASK which is a child of element TODOLIST and will apply the template <xsl:template match="TASK"> to each occurrence.

Walking the Tree Recursively

See file TDLSS 4.xsl for the complete example.

XML
<xsl:template match="TASK">
    <xsl:value-of select="@TITLE" />
    <xsl:element name="br" />
    <xsl:apply-templates select="TASK" />
</xsl:template>

The <xsl:apply-templates select="TASK" /> is what makes the tree walking recursive.

Reading Text Elements Values

See file TDLSS 5.xsl for the complete example.

XML
<xsl:template match="TASK">
    <xsl:value-of select="@TITLE" />
    <xsl:element name="br" />
    <xsl:text>CATEGORY: </xsl:text>
    <xsl:value-of select="CATEGORY" />
    <xsl:element name="br" />
    <xsl:text>COMMENTS: </xsl:text>
    <xsl:value-of select="COMMENTS" />
    <xsl:element name="br" />
    <xsl:element name="br" />
    <xsl:apply-templates select="TASK" />
</xsl:template>

The <xsl:value-of select="COMMENTS" /> output the value of the COMMENTS text element.

Single Condition: if

See file TDLSS 6.xsl for the complete example.

XML
<xsl:if test="COMMENTS">
    <xsl:text>COMMENTS: </xsl:text>
    <xsl:value-of select="COMMENTS" />
    <xsl:element name="br" />
</xsl:if>

The xsl:if is a do something when test is true and do nothing when test is false.

Multiple Condition: choose

See file TDLSS 7.xsl for the complete example.

XML
<xsl:choose>
    <xsl:when test="COMMENTS">
        <xsl:text>COMMENTS: </xsl:text>
        <xsl:value-of select="COMMENTS" />
        <xsl:element name="br" />
    </xsl:when>
    <xsl:otherwise>
        <xsl:text>No COMMENT</xsl:text>
    </xsl:otherwise>
</xsl:choose>

The xsl:choose is a multiple condition structure. The first when structure, which is true, is executed, if no test is true, the otherwise structure is executed.

Calling a template

See file TDLSS 8.xsl for the complete example.

XML
    <xsl:call-template name="fix-breaks">
        <xsl:with-param name="text">
            <xsl:value-of select="COMMENTS" />
        </xsl:with-param>
    </xsl:call-template>
    . . .
<xsl:template name="fix-breaks">
    <xsl:param name="text" />
    . . .
</xsl:template>

Named templates <xsl:template name="fix-breaks"> are nothing else that subprograms in other languages. They are called by <xsl:call-template name="fix-breaks">.

Fixing Breaks

See file TDLSS 8.xsl for the complete example.

XML
<xsl:template name="fix-breaks">
    <xsl:param name="text" />
    <xsl:choose>
        <xsl:when test="contains($text,'&#13;&#10;')">
            <xsl:value-of select="substring-before($text,'&#13;&#10;')" />
            <xsl:element name="br"/>
            <xsl:call-template name="fix-breaks">
                <xsl:with-param name="text">
                    <xsl:value-of select="substring-after($text,'&#13;&#10;')" />
                </xsl:with-param>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Multi lines text need to be fixed for html output because CRLF is not understood and must be replaced with <br/>.

Getting Tasks Path from a Tree View

See file TDLSS 9.xsl for the complete example.

XML
<xsl:template name="get_Task_Ancestors">
    <xsl:if test="count(ancestor::TASK)>0">
        <xsl:for-each select="(ancestor::TASK)">
            <xsl:value-of select="@TITLE"/>
            <xsl:text> - </xsl:text>
        </xsl:for-each>
    </xsl:if>
</xsl:template>

This template works only if tasks are nested (tree view). It list the TITLE of parents starting from the root.

Getting Tasks Path from a List View

See file TDLSS13.xsl for the complete example.

XML
<xsl:template name="get_Task_Path">
    <xsl:param name="ref" />
    <xsl:choose>
        <xsl:when test="$ref='0'">
            <xsl:for-each select="../TASK[@ID=$ref]">
                <xsl:value-of select="@TITLE"/>
            </xsl:for-each>
        </xsl:when>
        <xsl:otherwise>
            <xsl:for-each select="../TASK[@ID=$ref]">
                <xsl:if test="@PARENTID!='0'">
                    <xsl:call-template name="get_Task_Path">
                        <xsl:with-param name="ref">
                            <xsl:value-of select="@PARENTID" />
                        </xsl:with-param>
                    </xsl:call-template>
                    <xsl:text> - </xsl:text>
                </xsl:if>
                <xsl:value-of select="@TITLE"/>
            </xsl:for-each>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

This template works only if tasks are nor nested (list view). It lists the TITLE of parents starting from the root. Check that the parents are included in the list.

Showing Tasks Nesting

See file TDLSS10.xsl for the complete example.

In html, lists are the natural way to show indenting by simply nesting lists.

XML
<xsl:template match="/TODOLIST">
    <xsl:element name="html">
        <xsl:element name="head">
            <xsl:element name="title">
                <xsl:value-of select="@PROJECTNAME" />
            </xsl:element>
        </xsl:element>
        <xsl:element name="body">
            . . .
            <xsl:element name="ul">
                <xsl:apply-templates select="TASK" />
            </xsl:element>
        </xsl:element>
    </xsl:element>
</xsl:template>

<xsl:template match="TASK">
    <xsl:element name="li">
        <xsl:text>Title: </xsl:text>
        <xsl:value-of select="@TITLE" />
        <xsl:element name="br" />
    </xsl:element>
    <xsl:element name="ul">
        <xsl:apply-templates select="TASK" />
    </xsl:element>
</xsl:template>

Simply add <ul> and <li> at the right place in the code walking the tree.

Using a XML Document Matching Template

See files TDLSS11.xsl and TDLSS12.xsl for complete examples.

Usually, we start with the root matching template, like in example file TDLSS11.xsl.

XML
<xsl:template match="/TODOLIST">
    <xsl:element name="html">
        <xsl:element name="head">
            <xsl:element name="title">
                <xsl:value-of select="@PROJECTNAME" />
            </xsl:element>
        </xsl:element>
        <xsl:element name="body">
            <xsl:text>Root matching template</xsl:text>
            <xsl:element name="br" />
            <xsl:element name="ul">
                <xsl:apply-templates select="TASK" />
            </xsl:element>
        </xsl:element>
    </xsl:element>
</xsl:template>

But sometimes, it is needed to start with a document matching template, like in example file TDLSS12.xsl which does mostly the same thing.

XML
<xsl:template match="/">
    <xsl:element name="html">
        <xsl:element name="head">
            <xsl:element name="title">
                <xsl:value-of select="@PROJECTNAME" />
            </xsl:element>
        </xsl:element>
        <xsl:element name="body">
            <xsl:text>Document matching template</xsl:text>
            <xsl:element name="br" />
            <xsl:apply-templates />
        </xsl:element>
    </xsl:element>
</xsl:template>

<xsl:template match="/TODOLIST">
    <xsl:text>Root matching template</xsl:text>
    <xsl:element name="br" />
    <xsl:element name="ul">
        <xsl:apply-templates select="TASK" />
    </xsl:element>
</xsl:template>

You can see that the HTML document stuff is always in the first called template, and the document matching template calls the root as a child element.

Including HTML Tags in a StyleSheet

When you want to format the output, the best is to use html tags.

HTML Root

The root structure of an html page is something like:

HTML
<html>
	<head>
	. . .
	</head>
	<body>
	. . .
	</body>
</html>

As it appear only once in the output, it must be in the template that matches the root.

XML
    <xsl:template match="/TODOLIST">
        <xsl:element name="html">
            <xsl:element name="head">
                . . .
            </xsl:element>
            <xsl:element name="body">
                . . .
		        <xsl:apply-templates select="TASK" />
                . . .
		    </xsl:element>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

See file TDLSS 3.xsl for the complete example.

CRLF in HTML

CRLF is only used in html source code and doesn't do anything in the rendering of the page, the <br /> tag must be used instead.

XML
<xsl:element name="br" />

and results in:

XML
<br />

List

An html list is a simple way to show tasks nesting by indenting the tasks in output. It is easy because the nesting of tasks match the nesting of lists.

An html list is made of 2 parts:

  • a List delimiter <ul>
  • a ListLine delimiter <li>

The List delimiter surrounds a list and appears once per list. Its natural place is in the template that treats a parent task.

XML
<xsl:element name="ul">
    <xsl:apply-templates select="TASK" />
</xsl:element>

The ListLine delimiter appears once per list item. Its natural place is in the template that treats a child task.

XML
<xsl:element name="li">
    <xsl:text>Title: </xsl:text>
    <xsl:value-of select="@TITLE" />
    <xsl:element name="br" />
</xsl:element>

Download

The zip contains the examples files:

  • File bpsToDoListStyler_Rev018.xsl is the example file from article XSL Transform for ToDoList.
  • File bpsToDoListStyler_Rev019.xsl is the corrected file as described there after.
  • File HelloWord.xsl, example file, see snippet
  • File HelloTDL99.xsl, examples files, see snippet

Links

History

  • 1st May, 2015: First draft
  • 19th May, 2015: Added some stuff, updated download and corrections
  • 1st June, 2015: Typos
  • 15th June, 2015: Added more stuff and updated download
  • 27th November, 2015: Added more stuff and updated download

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Database Developer
France France
I am a professional programmer.
Problem analyse is certainly what I am best at.
My main programming expertise is in the xBase languages (dBase, Clipper, FoxPro, Harbour, xHarbour), then VBA for Excel and advanced Excel WorkBooks.

I also have knowledge on C/C++, d language, HTML, SVG, XML, XSLT, Javascript, PHP, BASICs, Python, COBOL, Assembly.
My personal interests goes to algorithm optimization and puzzles.

Comments and Discussions

 
QuestionOutput error Pin
Pttigui30-Nov-20 19:41
Pttigui30-Nov-20 19:41 
AnswerRe: Output error Pin
Patrice T1-Dec-20 11:47
mvePatrice T1-Dec-20 11:47 
SuggestionRe: Output error Pin
Patrice T1-Dec-20 16:50
mvePatrice T1-Dec-20 16:50 
QuestionCan't view the article revisions... Pin
.dan.g.29-Nov-20 23:28
professional.dan.g.29-Nov-20 23:28 
AnswerRe: Can't view the article revisions... Pin
Patrice T1-Dec-20 11:36
mvePatrice T1-Dec-20 11:36 
QuestionThis article helped me build a transform quickly Pin
aschatte22-Feb-19 7:51
aschatte22-Feb-19 7:51 
AnswerRe: This article helped me build a transform quickly Pin
Patrice T5-Mar-19 1:12
mvePatrice T5-Mar-19 1:12 
QuestionCustom columns in Stylesheet Pin
Member 955678826-Aug-15 23:45
Member 955678826-Aug-15 23:45 
AnswerRe: Custom columns in Stylesheet Pin
Patrice T27-Aug-15 0:18
mvePatrice T27-Aug-15 0:18 
Questionadd "media-type" Pin
Pierre de la Verre28-May-15 12:16
Pierre de la Verre28-May-15 12:16 
AnswerRe: add "media-type" Pin
Patrice T28-May-15 14:41
mvePatrice T28-May-15 14:41 
GeneralRe: add "media-type" Pin
Pierre de la Verre29-May-15 22:24
Pierre de la Verre29-May-15 22:24 
SuggestionTo Readers: Your feedback is appreciated Pin
Patrice T15-May-15 15:14
mvePatrice T15-May-15 15:14 
GeneralRe: To Readers: Your feedback is appreciated Pin
EtherealMonkey19-May-15 15:10
EtherealMonkey19-May-15 15:10 
GeneralRe: To Readers: Your feedback is appreciated Pin
Patrice T19-May-15 16:47
mvePatrice T19-May-15 16:47 
GeneralRe: To Readers: Your feedback is appreciated Pin
EtherealMonkey19-May-15 18:38
EtherealMonkey19-May-15 18:38 
QuestionMy ah ha moment Pin
zajchapp11-May-15 15:21
zajchapp11-May-15 15:21 
AnswerRe: My ah ha moment Pin
Patrice T11-May-15 15:42
mvePatrice T11-May-15 15:42 
zajchapp wrote:
First up, great effort.
Thanks
zajchapp wrote:
The below might seem blindingly obvious to a programmer, but I had been modifying the supplied stylesheets for some time before I worked out what they actually did. It clearly wasn't obvious to me at the time.
...
It's exactly why most of the code snipsets don't use html formatting, I wanted to keep focussed on the xslt logic.
And when you master how to retrieve what you want, then it is time to learn how to format it with css and html stuff.
Patrice

“Everything should be made as simple as possible, but no simpler.” Albert Einstein

GeneralRe: My ah ha moment Pin
zajchapp11-May-15 19:40
zajchapp11-May-15 19:40 
AnswerRe: My ah ha moment Pin
Patrice T11-May-15 21:54
mvePatrice T11-May-15 21:54 
GeneralRe: My ah ha moment Pin
zajchapp12-May-15 11:05
zajchapp12-May-15 11:05 
GeneralRe: My ah ha moment Pin
Patrice T12-May-15 11:21
mvePatrice T12-May-15 11:21 
GeneralRe: My ah ha moment Pin
zajchapp12-May-15 14:22
zajchapp12-May-15 14:22 
QuestionI've added a link to the wiki Pin
.dan.g.11-May-15 14:45
professional.dan.g.11-May-15 14:45 
AnswerRe: I've added a link to the wiki Pin
Patrice T11-May-15 15:18
mvePatrice T11-May-15 15:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.