    /**
     * Creates a news ticker.
     */
    function Newsticker()
    {
        this.m_News = new Array();
        this.m_Timer = null;
        this.m_StepWidth = 2;
        this.m_Speed = 40;
        this.m_PauseAfterNews = 1000;

        this.m_NewsContainer = null;
        this.m_NewsLink = null;
        this.m_NewsText = null;

        this.m_CurrentNews = null;
        this.m_CurrentNewsIndex = -1;

        this.m_Width = 0;
        this.m_CurrentLeft = 0;
        this.m_CurrentWidth = 0;

        this.setStepWidth = Newsticker_setStepWidth;
        this.getStepWidth = Newsticker_getStepWidth;
        this.setSpeed = Newsticker_setSpeed;
        this.getSpeed = Newsticker_getSpeed;
        this.setPauseAfterNews = Newsticker_setPauseAfterNews;
        this.getPauseAfterNews = Newsticker_getPauseAfterNews;
        this.addNews = Newsticker_addNews;
        this.start = Newsticker_start;
        this.next = Newsticker_next;
        this.step = Newsticker_step;
    }

    /**
     * Set the step width.
     * @param the step width
     */
    function Newsticker_setStepWidth( stepWidth )
    {
        this.m_StepWidth = stepWidth;
    }

    /**
     * Returns the step width.
     * @return the step width
     */
    function Newsticker_getStepWidth()
    {
        return this.m_StepWidth;
    }

    /**
     * Sets the speed of the news ticker.
     * @param speed the speed in milli seconds. less is faster.
     */
    function Newsticker_setSpeed( speed )
    {
        this.m_Speed = speed;
    }

    /**
     * Returns the speed of the news ticker.
     * @return the speed
     */
    function Newsticker_getSpeed()
    {
        return this.m_Speed;
    }

    /**
     * Sets the pause after one news.
     * @param the pause
     */
    function Newsticker_setPauseAfterNews( pause )
    {
        this.m_PauseAfterNews = pause;
    }

    /**
     * Returns the pause after one news.
     * @return the pause after one news
     */
    function Newsticker_getPauseAfterNews()
    {
        return this.m_PauseAfterNews;
    }

    /**
     * Add a news line to the news ticker.
     * @param news the news line
     */
    function Newsticker_addNews( news )
    {
        this.m_News[this.m_News.length] = news;
    }

    /**
     * Start the ticker.
     */
    function Newsticker_start()
    {
        this.next();
    }

    /**
     * Show the next news line.
     */
    function Newsticker_next()
    {
        if ( this.m_Timer != null)
        {
            window.clearInterval( this.m_Timer );
        }

        this.m_CurrentNewsIndex++;
        if ( this.m_CurrentNewsIndex == this.m_News.length )
        {
            this.m_CurrentNewsIndex = 0;
        }

        this.m_CurrentNews = this.m_News[this.m_CurrentNewsIndex];

        var line = document.getElementById( 'Newsticker' );

        if ( this.m_NewsContainer == null )
        {
            this.m_Width = line.offsetWidth;
            this.m_NewsContainer = document.createElement( 'NOBR' );
            this.m_NewsContainer.className = 'Newsline';

            this.m_NewsContainer.style.position = 'absolute';

            this.m_NewsLink = document.createElement( 'A' );
            this.m_NewsLink.className = 'Newsline';
            this.m_NewsText = document.createTextNode( ' ' );
            this.m_NewsLink.appendChild( this.m_NewsText );
            this.m_NewsContainer.appendChild( this.m_NewsLink );

            document.body.appendChild( this.m_NewsContainer );
        }

        this.m_NewsLink.href = this.m_CurrentNews.getUrl();
        this.m_NewsLink.target = this.m_CurrentNews.getTarget();
        this.m_NewsText.data = this.m_CurrentNews.getText();

        this.m_CurrentLeft = getAbsoluteLeft( line ) + line.offsetWidth - 5;
        this.m_CurrentWidth = 0;

        this.m_NewsContainer.style.left = this.m_CurrentLeft + 'px';
        this.m_NewsContainer.style.top = getAbsoluteTop( line ) + 'px';
        this.m_NewsContainer.style.clip = 'rect(0px 0px 50px 0px)';

        this.m_Timer = window.setInterval( 'window.newsticker.step()', this.getSpeed() );
    }

    /**
     * Move the ticker.
     */
    function Newsticker_step()
    {
        this.m_CurrentLeft -= this.getStepWidth();
        this.m_CurrentWidth += this.getStepWidth();

        this.m_NewsContainer.style.left = this.m_CurrentLeft + 'px';
        this.m_NewsContainer.style.clip = 'rect(0px ' + this.m_CurrentWidth + 'px 50px 0px)';

        if ( this.m_CurrentWidth >= this.m_Width )
        {
            window.clearInterval( this.m_Timer );
            this.m_Timer = window.setInterval( 'window.newsticker.next()', this.getPauseAfterNews() );
        }
    }

    /**
     * Create a news for the news ticker.
     */
    function News()
    {
        this.m_Url = '';
        this.m_Target = '_blank';
        this.m_Text = '';

        this.setUrl = News_setUrl;
        this.getUrl = News_getUrl;
        this.setTarget = News_setTarget;
        this.getTarget = News_getTarget;
        this.setText = News_setText;
        this.getText = News_getText;
    }

    /**
     * Sets the url.
     * @param url the url
     */
    function News_setUrl( url )
    {
        this.m_Url = url;
    }

    /**
     * Returns the url.
     * @return the url
     */
    function News_getUrl()
    {
        return this.m_Url;
    }

    /**
     * Sets the target frame.
     * @param target the target frame
     */
    function News_setTarget( target )
    {
        this.m_Target = target;
    }

    /**
     * Returns the target frame.
     * @return the target frame
     */
    function News_getTarget()
    {
        return this.m_Target;
    }

    /**
     * Sets the text.
     * @param text the text
     */
    function News_setText( text )
    {
        this.m_Text = text;
    }

    /**
     * Returns the text.
     * @return the text
     */
    function News_getText()
    {
        return this.m_Text;
    }
    
    /**
     * Creates an arrow for the defined size and color.
     * @param image if a image should be used else <code>null</code>
     * @param zIndex the zIndex
     * @param size the size of the arrow (width and height)
     * @param color the color of the arrow
     */
    function createArrow( image, zIndex, size, color )
    {
        if ( image )
        {
            var img = document.createElement( 'IMG' );
            img.src = image;
            img.style.position = 'absolute';
            img.style.zIndex = zIndex;

            return img;
        }

        var i, j, row, cell, img;
        var maxcols = Math.ceil( size / 2 );
        var table = document.createElement( 'TABLE' );
        table.style.position = 'absolute';
        table.style.zIndex = zIndex;
        table.cellSpacing = '0';
        table.cellPadding = '0';

        for ( i=0; i < maxcols; i++ )
        {
            createRowForArrow( table, i+1, size, color );
        }

        for ( i=maxcols; i > 0; i-- )
        {
            createRowForArrow( table, i, size, color );
        }

        return table;
    }

    /**
     * Creates a row for the arrow.
     * @param table the table
     * @param cols the number of first columns
     * @param size the size of the arrow
     * @param color the color of the arrow
     */
    function createRowForArrow( table, cols, size, color )
    {
        var row, cell;
        var maxcols = Math.ceil( size / 2 );
        row = table.insertRow( this.currentRow++ );

        if ( navigator.appName == 'Microsoft Internet Explorer' )
        {
            cell = row.insertCell( 0 );
            cell.colSpan = cols;
            cell.bgColor = color;
            cell.appendChild( createSpacer( 1, 1 ) );

            if ( maxcols - cols > 0 )
            {
                cell = row.insertCell( 1 );
                cell.colSpan = maxcols - cols;
                cell.appendChild( createSpacer( 1, 1 ) );
            }
        }
        else
        {
            var i;
            for ( i=0; i < maxcols; i++ )
            {
                cell = row.insertCell( i );
                if ( i < cols )
                {
                    cell.bgColor = color;
                }
                cell.appendChild( createSpacer( 1, 1 ) );
            }
        }
    }

   /**
    * Creates a color tone with the given start color to the end color.
    * @param startColor the start color
    * @param endColor the end color
    * @param steps the number of steps
    * @return a list of colors
    */
   function createColorTone( startColor, endColor, steps )
   {
        var ret = new Array();
        var i, currentRed, currentGreen, currentBlue, currentColor, tmp;
        var startRed = fromHex( startColor.substring( 1, 3 ) );
        var startGreen = fromHex( startColor.substring( 3, 5 ) );
        var startBlue = fromHex( startColor.substring( 5, 7 ) );
        var endRed = fromHex( endColor.substring( 1, 3 ) );
        var endGreen = fromHex( endColor.substring( 3, 5 ) );
        var endBlue = fromHex( endColor.substring( 5, 7 ) );

        var stepRed = ( endRed - startRed ) / ( steps - 1 );
        var stepGreen = ( endGreen - startGreen ) / ( steps - 1 );
        var stepBlue = ( endBlue - startBlue ) / ( steps - 1 );

        ret[0] = startColor;

        for ( i=1; i < steps; i++ )
        {
            currentRed = Math.round( startRed + stepRed * i );
            currentGreen = Math.round( startGreen + stepGreen * i );
            currentBlue = Math.round( startBlue + stepBlue * i );

            currentColor = '#' + toHex( currentRed ) + toHex( currentGreen ) + toHex( currentBlue );
            ret[i] = currentColor;
        }

        return ret;
    }

    /**
     * Creates a document element for an spacer image.
     * @param width the width
     * @param height the height
     * @return the document element
     */
    function createSpacer( width, height )
    {
        var img = document.createElement( 'IMG' );
        img.src = 'spacer.gif';
        img.width = width;
        img.height = height;
        img.border = '0';

        return img;
    }

    /**
     * Creates a table at the given position and zIndex.
     * @param x the x coordinate
     * @param y the y coordinate
     * @return the table
     **/
    function createTableAt( x, y, zIndex )
    {
        var table = document.createElement( 'TABLE' );
        table.border = '0';
        table.cellSpacing = '0';
        table.cellPadding = '0';
        table.style.position = 'absolute';
        table.style.left = x;
        table.style.top = y;
        table.style.zIndex = zIndex;

        return table;
    }

    /**
     * Converts a hexadecimal string to a decimal number.
     * @param string the hexadecimal string
     */
    function fromHex( string )
    {
        return parseInt( string, 16 );
    }

    /**
     * Returns the absolute left position of an element.
     * @param element the element
     * @return the absolute left position
     */
    function getAbsoluteLeft( element )
    {
        if ( element.offsetParent )
        {
            return element.offsetLeft + getAbsoluteLeft( element.offsetParent );
        }
        return element.offsetLeft;
    }

    /**
    * Returns the absolute top position of an element.
    * @param the element
    * @return the absolute top position
    */
    function getAbsoluteTop( element )
    {
        if ( element.offsetParent )
        {
            return element.offsetTop + getAbsoluteTop( element.offsetParent );
        }
        return element.offsetTop;
    }

    /**
     * Returns the selection start of an element.
     * @param element the element
     * @return the selection start
     */
    function getSelectionStart( element )
    {
        if ( typeof( element.selectionStart ) != 'undefined' )
        {
            return element.selectionStart;
        }
    }

    /**
     * Returns the selection end of an element.
     * @param the element
     * @return the selection end
     */
    function getSelectionEnd( element )
    {
        if ( typeof( element.selectionEnd ) != 'undefined' )
        {
            return element.selectionEnd;
        }
    }

    /**
     * Surrounds the selection with a start and a end value.
     * @param element the element
     * @param start the start value
     * @param end the end value
     */
    function surroundSelection( element, start, end )
    {
        if ( element.range )
        {
            if ( element.range.text )
            {
                element.range.text = start.replace( /\{0\}/, element.range.text ) + element.range.text + end.replace( /\{0\}/, element.range.text );
            }
            else
            {
                element.value = start.replace( /\{0\}/, element.value ) + element.value + end.replace( /\{0\}/, element.value );
            }
            element.focus();
            return;
        }
        var selection = element.value.substring( getSelectionStart( element ), getSelectionEnd( element ) );
        var text = element.value.substring( 0, getSelectionStart( element ) );
        text = text + start.replace( /\{0\}/, selection );
        text = text + selection;
        text = text + end.replace( /\{0\}/, selection );
        text = text + element.value.substring( getSelectionEnd( element ) );
        element.value = text;
        element.focus();
    }

    /**
     * Converts a decimal number to a hexadecimal.
     * @param decimal the decimal number
     * @return the hexadecimal number
     */
    function toHex( decimal )
    {
        var hex = decimal.toString( 16 ).toUpperCase();
        if ( hex.length < 2 )
        {
            hex = '0' + hex;
        }
        return hex;
    }