    <JSB>
        <JSB_DESCRIPTOR NAME="netscape.peas.JSBufferedCursor" DISPLAYNAME="Buffered Cursor" ENV="both"
            ISHIDDEN SHORTDESCRIPTION="JavaScript-Buffered Database Cursor" CLASS="" CUSTOMIZER="">

        <JSB_PROPERTY NAME="dbpool" DISPLAYNAME="DBPool" PROPTYPE="JS" TYPE="string" ENV="server"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="Name of DBPool to use">

        <JSB_PROPERTY NAME="SQL" DISPLAYNAME="SQL Query" ISRUNTIME PROPTYPE="JS-expr" TYPE="SQLQuery" ENV="server"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="SQL query that defines cursor">

        <JSB_PROPERTY NAME="filterCol" DISPLAYNAME="Filter Column" ISRUNTIME PROPTYPE="JS-expr" TYPE="string" ENV="server"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="Name of column to filter on by value passed in request object">

        <JSB_PROPERTY NAME="sortCol" DISPLAYNAME="Sort Column" ISRUNTIME PROPTYPE="JS-expr" TYPE="string" ENV="server"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="Column to sort data on">

        <JSB_PROPERTY NAME="sortAscending" DISPLAYNAME="Sort direction" ISRUNTIME PROPTYPE="JS-expr" TYPE="boolean" ENV="server"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="Sort direction: TRUE = Ascending; FALSE = Descending">

        <JSB_PROPERTY NAME="maxRows" DISPLAYNAME="Max. Rows" ISRUNTIME PROPTYPE="JS" TYPE="number" ENV="server"
            VALUESET="1:32767"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="Maximum number of rows to fetch">

        <JSB_PROPERTY NAME="numRows" DISPLAYNAME="Number Rows" ISRUNTIME PROPTYPE="JS" TYPE="number" ENV="both"
            VALUESET="1:32767"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="Number of rows actually fetched">

        <JSB_PROPERTY NAME="currentRowNumber" DISPLAYNAME="Current Row Number" ISRUNTIME PROPTYPE="JS" TYPE="number" ENV="client"
            VALUESET="1:32767"
            READMETHOD="" WRITEMETHOD="setCurrentRowNumber"
            SHORTDESCRIPTION="Current Row Number (run time)">

        <JSB_PROPERTY NAME="updatable" DISPLAYNAME="Updatable" PROPTYPE="JS" TYPE="boolean" ENV="both"
            READMETHOD="" WRITEMETHOD=""
            SHORTDESCRIPTION="Is Cursor Updatable">

        <JSB_PROPERTY NAME="release" DISPLAYNAME="Release Connection" PROPTYPE="JS" TYPE="boolean" ENV="server"
            READMETHOD="" WRITEMETHOD="" DEFAULT_VALUE="true"
            SHORTDESCRIPTION="Whether to release the database connection when finished processing">

        <JSB_METHOD NAME="nextRow" TYPE="boolean" ENV="client"> </JSB_METHOD>

        <JSB_METHOD NAME="previousRow" TYPE="boolean" ENV="client"> </JSB_METHOD>

        <JSB_METHOD NAME="updateCurrentRow" TYPE="void" ENV="client"> </JSB_METHOD>

        <JSB_METHOD NAME="addRow" TYPE="void" ENV="client"> </JSB_METHOD>

        <JSB_METHOD NAME="deleteRow" TYPE="void" ENV="client"> </JSB_METHOD>

        <JSB_METHOD NAME="setCurrentRowNumber" TYPE="void" ENV="client">
            <JSB_PARAMETER NAME="newRowNumber" TYPE="number">
        </JSB_METHOD>

        <JSB_METHOD NAME="getCurrentRowNumber" TYPE="number" ENV="client"> </JSB_METHOD>

        <JSB_METHOD NAME="getNumRowsFetched" TYPE="number" ENV="client"> </JSB_METHOD>

        <JSB_METHOD NAME="executeQuery" TYPE="void" ENV="client"> </JSB_METHOD>

        <JSB_EVENT NAME="onChange" LISTENERMETHODS="onChange" LISTENERTYPE="onChangeListener" EVENTMODEL="JS">

        <JSB_EVENT NAME="netscape.peas.RowChange" LISTENERMETHODS="rowChange" LISTENERTYPE="netscape.peas.RowChangeListener" EVENTMODEL="AWT11" ISDEFAULT>

        <JSB_CONSTRUCTOR>
    function writeln(str) {
      write(str + "\n")
    }

    function lit(original) {
        input = "" + original
        output = '"';
        for(x=0; x<input.length; x++) {
            ch = input.charAt(x);
            if (ch == '"') {
                output += "\\\"";
            } else if (ch == '\\') {
                output += "\\\\";
            } else {
                output += ch
            }
            if (x % 80 == 79)
                output += "\"+\n\""
        }
        output += '"';
        return output;
    }

    function _typeOf( val ) {
        //----- ES Server 3.0
        if (server.httpdlwVersion.indexOf("3.0") != -1) {
    	    return( typeof( val ) )
    	}
        //----- ES Server 2.0
    	else {
    	    if ( val == null )  return ("number");
    	    if ( val.charAt != null )  return ("string");
    	    var valStr = "" + val
    	    var intValue = parseInt( valStr )
    	    var floatValue = parseFloat( valStr )
    	    if ( isNaN(intValue) && isNaN(floatValue) )
    	        return("object")
    	    else
    	        return("number")
    	}
    }

    // Client-side constructor functions and methods
    	writeln("\n<SCRIPT>")

        writeln("function fireChangeEvent( prop, oldValue, newValue, bJSOnly ) {")
        writeln("   if (null!=this.__oRowSupport&&(!bJSOnly)) {")
        writeln("       this.__oRowSupport.firePropertyChange(prop,oldValue,newValue)")
        writeln("       this.__oRowSupport.fireRowChange(2,prop,oldValue,newValue,this.__oRowSupport,null)")
        writeln("   }")

        writeln("   if (null!=this.onChange) {")
        writeln("       this.onChange(prop,oldValue,newValue)")
        writeln("   }")
        writeln("}")

        writeln("function executeQuery() {")
        writeln("   if (null!=this.__oRowSupport) {")      // tell our helper object about our data...
        writeln("      this.__oRowSupport.setNumColumns(this.getNumColumns())")
        writeln("      for( i = 0; i < c.columns(); i++)")
        writeln("         this.__oRowSupport.setColumnName(i, this.getColumnName(i))")
        writeln("      this.__currentRowNumber = -1")       // tell our listeners about our data
        writeln("      this.__oRowSupport.fireRowChange(1,null,null,null,oRowSupport,null)")
        writeln("   }")
        writeln("}")

    	writeln("function updateCurrentRow() {")
        writeln("    if (this.__currentRowNumber<0 || this.__currentRowNumber>=this.__numRows) {")
     	writeln("        alert('Attempt to update row number out of range!')")
    	writeln("        return")
     	writeln("    }")
     	writeln("    RowInfo = this.__oRowInfo")
    	writeln("    if (RowInfo[this.__currentRowNumber].isDbRow == false)")
    	writeln("        this._insertRow(this)")
    	writeln("    else")
    	writeln("        this._updateRow(this)")
    	writeln("    RowInfo[this.__currentRowNumber].isDbRow = true")
    	writeln("    if (this.__oRowBuffer != null) {")
    	writeln("        this.__currentRow[prop] = this.__oRowBuffer.getValueByName( prop )")
    	writeln("    } else {")
    	writeln("        this.__currentRow[prop] = this[prop]")
     	writeln("    }")
    	writeln("} // updateCurrentRow")

    	writeln("function _updateRow() {")
    	writeln("    currRowInfo = this.__oRowInfo[this.__currentRowNumber]")
    	writeln("    if ( currRowInfo.oldRowValue == null) {")
    	writeln("        alert('Row has not been modified.  No update performed.')")
    	writeln("        return")
    	writeln("    }")
    	writeln("    tableName = getSelectTableName(this.__SQL)")
    	writeln("    updSql = 'UPDATE ' + tableName + ' SET '")
      	writeln("    currRow = this.__currentRow")
    	writeln("    firstCol = true")
    	writeln("    colProps = eval(this.__name + 'ColProps')")
    	writeln("    for( prop in currRow ) { ")
    	writeln("        if (this.__oRowBuffer != null) {")
    	writeln("            currColValue = this.__oRowBuffer.getValueByName(prop)")
    	writeln("        } else {")
    	writeln("            currColValue = this[prop]")
    	writeln("        }")
    	writeln("        if ( currColValue == currRowInfo.oldRowValue[prop] ) continue")
    	writeln("        if ( !firstCol ) { updSql += ', '}")
    	writeln("        else { firstCol = false }")
    	writeln("        strQuote = colTypeLiteralQuote( colProps, prop )")
    	writeln("        updSql += (prop + '=' + strQuote + currColValue + strQuote)")
    	writeln("    }")
    	writeln("    updSql += ' WHERE '")
    	writeln("    firstCol = true")
    	writeln("    for( prop in currRow ) { ")
    	writeln("        if ( !firstCol ) { updSql += ' AND '}")
    	writeln("        else { firstCol = false }")
    	writeln("        strQuote = colTypeLiteralQuote( colProps, prop )")
            writeln("        rowVal = currRowInfo.oldRowValue[prop]")
            writeln("        if (rowVal != null)")
    	writeln("            updSql += (prop + '=' + strQuote + rowVal + strQuote )")
            writeln("        else")
    	writeln("            updSql += (prop + ' IS NULL')")
    	writeln("    }")
    	writeln("    performSqlUpdate(updSql, this._enableSqlResultWindow)")
    	writeln("} // _updateRow")

    	writeln("function _insertRow() {")
    	writeln("    tableName = getSelectTableName(this.__SQL)")
      	writeln("    currRow = this.__currentRow")
    	writeln("    insertSql = 'INSERT INTO ' + tableName + ' ('")
    	writeln("    firstCol = true")
    	writeln("    for( prop in currRow ) { ")
    	writeln("        if ( !firstCol ) { insertSql += ', '}")
    	writeln("        else { firstCol = false }")
    	writeln("        insertSql += prop")
    	writeln("    }")
    	writeln("    insertSql += ') VALUES ('")
    	writeln("    firstCol = true")
    	writeln("    colProps = eval(this.__name + 'ColProps')")
    	writeln("    for( prop in currRow ) { ")
    	writeln("        if ( !firstCol ) { insertSql += ', '}")
    	writeln("        else { firstCol = false }")
    	writeln("        strQuote = colTypeLiteralQuote( colProps, prop )")
    	writeln("        if (this.__oRowBuffer != null) {")
    	writeln("            insertSql += (strQuote + this.__oRowBuffer.getValueByName(prop) + strQuote )")
    	writeln("        } else {")
    	writeln("            insertSql += (strQuote + this[prop] + strQuote )")
    	writeln("        }")
    	writeln("    }")
    	writeln("    insertSql += ' )'")
    	writeln("    performSqlUpdate(insertSql, this._enableSqlResultWindow)")
    	writeln("} // _insertRow")

    	writeln("function deleteRow() {")
    	writeln("    tableName = getSelectTableName(this.__SQL)")
            writeln("    if (this.__currentRowNumber<0 || this.__currentRowNumber>=this.__numRows) {")
     	writeln("        alert('Attempt to delete row number out of range!')")
    	writeln("        return")
     	writeln("    }")
    	writeln("    deleteSql = 'DELETE FROM ' + tableName + ' WHERE '")
      	writeln("    currRow = this.__currentRow")
    	writeln("    firstCol = true")
    	writeln("    colProps = eval(this.__name + 'ColProps')")
    	writeln("    for( prop in currRow ) { ")
    	writeln("        if ( !firstCol ) { deleteSql += ' AND '}")
    	writeln("        else { firstCol = false }")
    	writeln("        strQuote = colTypeLiteralQuote( colProps, prop )")
            writeln("        if ( currRow[prop] != null)")
    	writeln("            deleteSql += (prop + '=' + strQuote + currRow[prop] + strQuote)")
            writeln("        else")
    	writeln("            deleteSql += (prop + ' IS NULL')")
    	writeln("    }")
    	writeln("    performSqlUpdate(deleteSql, this._enableSqlResultWindow)")
    	writeln("} // deleteRow")

    	writeln("function addRow() {")
    	writeln("    Rows = eval(this.__name + 'Rows')")
    	writeln("    newRow = new Row()")
    	writeln("    colProps = eval(this.__name + 'ColProps')")
    	writeln("    for( col in this.__currentRow ) { ")
    	writeln("        strQuote = colTypeLiteralQuote( colProps, prop )")
    	writeln("        eval('newRow.' + col + '=' + strQuote + '0' + strQuote)")
    	writeln("    }")
    	writeln("    Rows[this.__numRows] = newRow")
    	writeln("    this.__numRows += 1")
    	writeln("    this.setCurrentRowNumber(this.__numRows - 1)")
    	writeln("} // addRow")

    	writeln("function performSqlUpdate(sql, showResult) {")
    	writeln("    cscUrl = '_CSCursor.html?update=' + urlEncode(sql)")
    	writeln("    if ( showResult == true ) {")
    	writeln("        sqlWindow = window.open(cscUrl, '', 'scrollbars=yes,resizable=yes,width=300,height=300')")
    	writeln("    }")
    	writeln("    else {")
    	writeln("        cscUrl += ('&redirect=' + urlEncode(window.document.URL))")
    //	writeln("        sqlWindow = window.open(cscUrl, '', 'scrollbars=yes,resizable=yes,width=0,height=0')")
    //	writeln("        sqlWindow.close()")
    	writeln("        window.location.replace( cscUrl )")
    	writeln("    }")
    	writeln("} // performSqlUpdate")

        writeln("function next() {")
        writeln("return this.setCurrentRowNumber(this.__currentRowNumber+1)")
        writeln("}")

        writeln("function previous() {")
        writeln("    return this.setCurrentRowNumber(this.__currentRowNumber-1)")
        writeln("}")

     	writeln("function setCurrentRowNumber(newRowNumber) {")
     	writeln("    if (newRowNumber <0 || newRowNumber >= this.__numRows) {")
     	writeln("        alert('Attempt to set row number out of range!')")
     	writeln("        return false")
     	writeln("    } else {")
     	writeln("        oldRowNumber = this.__currentRowNumber")
     	writeln("        if ( oldRowNumber != newRowNumber ) {")
     	writeln("            this.__currentRowNumber = newRowNumber")
    	writeln("            Rows = eval(this.__name + 'Rows')")
      	writeln("            this.__currentRow = Rows[this.__currentRowNumber]")
     	writeln("            for (prop in this.__currentRow) {")
     	writeln("                if (oldRowNumber == -1) {")
     	writeln("                   oldValue = null")
     	writeln("                } else {")
     	writeln("                   oldValue = Rows[oldRowNumber][prop] // if we allow writes, get value from RowSupport's buffer")
    //	writeln("                    if (this.__oRowSupport != null) {")
    //	writeln("                        Rows[oldRowNumber][prop] = this.__oRowSupport.getValueByName( prop )  // update our table from what rowsupport holds")
    //	writeln("                    } else {")
    //	writeln("                        Rows[oldRowNumber][prop] = this[prop]")
    //	writeln("                    }")
    	writeln("                    if (this.__oRowBuffer != null) {")
    	writeln("                        Rows[oldRowNumber][prop] = this.__oRowBuffer.getValueByName( prop )  // update our table from what rowsupport holds")
    	writeln("                    } else {")
    	writeln("                        Rows[oldRowNumber][prop] = this[prop]")
     	writeln("                    }")
     	writeln("                }")
     	writeln("                this.fireChangeEvent(prop, oldValue, Rows[newRowNumber][prop], true )")
    // 	writeln("                if (this.__oRowSupport!=null) {")
    // 	writeln("                    this.__oRowSupport.setValueByName( prop, Rows[newRowNumber][prop], null )")
    // 	writeln("                }")
     	writeln("                if (this.__oRowBuffer!=null) {")
     	writeln("                    this.__oRowBuffer.setValueByName( prop, Rows[newRowNumber][prop] )")
     	writeln("                } else {")
    	writeln("                    this[prop] = Rows[newRowNumber][prop]")
     	writeln("                }")
     	writeln("            } // for")
     	writeln("            this.fireChangeEvent( 'currentRowNumber', oldRowNumber, newRowNumber, false)")
     	writeln("        } // if")
     	writeln("        return true    ")
     	writeln("    } // else")
     	writeln("} // setRowNumber")

    	writeln("function saveOldRowValue( bc ) {")
    	writeln("    rowInfo = bc.__oRowInfo[bc.__currentRowNumber]")
    	writeln("    if ( rowInfo.oldRowValue != null ) return")
    	writeln("    rowInfo.oldRowValue = new Object()")
    	writeln("    currentRow = bc.__currentRow")
    	writeln("    for ( c in currentRow ) {")
    	writeln("        eval( 'rowInfo.oldRowValue.' + c + '=currentRow[c]' )")
    	writeln("    }")
     	writeln("} // saveOldRowValue")

    	writeln("function getSelectTableName( sql ) {")
    	writeln("    lowerSQL = sql.toLowerCase()")
    	writeln("    sqlLength = sql.length")
    	writeln("    startIndex = lowerSQL.indexOf(' from ')")
    	writeln("    startIndex += 6")
    	writeln("    while( lowerSQL.charAt(startIndex) == ' ' )  startIndex++")
    	writeln("    endIndex = startIndex")
    	writeln("    while( (lowerSQL.charAt(endIndex) != ' ') && endIndex<sqlLength )  endIndex++")
    	writeln("    return sql.substring(startIndex, endIndex)")
    	writeln("    ")
    	writeln("} // getSelectTableName")

    	writeln("function colTypeLiteralQuote( colProps, colName ) {")
    	writeln("    colType = colProps[colName]._dataType")
    	writeln("    if (colType != 'number') return '\\''")
    	writeln("    else return ''")
    	writeln("} // colTypeLiteralQuote")

    	writeln("function urlEncode( url ) {")
    	writeln("    return escape(url)")
    	writeln("} // urlEncode")

    	writeln("function getValueByNameRB(propName) {")
    	writeln("    return( this.properties[propName] )")
    	writeln("} // getValueByNameRB")

    	writeln("function setValueByNameRB(propName, propValue) {")
    	writeln("    this.properties[propName] = propValue")
    	writeln("} // setValueByNameRB")

    	writeln("function RowBuffer() {")
    	writeln("   this.getValueByName = getValueByNameRB")
    	writeln("   this.setValueByName = setValueByNameRB")
    	writeln("   argCount = arguments[0]")
    	writeln("   argList = '\"' + arguments[1] + '\"'")
    	writeln("   for( i=2; i<=argCount; i++) {")
    	writeln("       argList = argList + ',' + '\"' + arguments[i] + '\"'")
    	writeln("   }")
    	writeln("   this.properties = new Array( argList )")
    	writeln("} // RowBuffer")

    	writeln("</SCRIPT>")

    // Generates client-side RowBuffer constructor function

        function createClientSideRowBuffer(c) {
    	writeln("<SCRIPT>")
    	writeln("   function gotoRowByColValue(colName, colValue) {")
    	writeln("      i = 0;")
    	writeln("      while ( ("+ c.cursorName +"Rows[i][colName] != colValue) && (i <= this.getNumRowsFetched()) )")
    	writeln("         i++;")
    	writeln("      this.setCurrentRowNumber(i)")
    	writeln("   }")

    	colNameList = ""
    	for( col in c ) {
    	    if ( colNameList != "" ) colNameList += ","
    	    colNameList += ('"' + col + '"')
    	}
    	writeln( c.cursorName + "RowBuffer = new RowBuffer(" + c.columns() + "," + colNameList + ")" )
    	writeln('</SCRIPT>')
        } // createClientSideJSCursor

    // Generates client-side Column Property array
        function createClientSideColumnProperty(c) {
            writeln('function ColProp() {')
            writeln('    this._dataType = arguments[0]')
            writeln('    this._updateKey = arguments[1]')
            writeln('}')
            write(c.cursorName + 'ColProps = new Array(')
            firstCol = true
            for( col in c) {
                if ( !firstCol ) write( ',' )
                write( '"' + col +'"' )
                firstCol = false
            }
            writeln( ')' )

    	for (col in c) {
                writeln(c.cursorName + 'ColProps["' + col + '"] = new ColProp("' + _typeOf(c[col]) + '", true)')
    	}
        }

    // Generates client-side Row constructor function, instantiates Row objects on client
    // and calls client-side constructor (csjsCursor)
    // Client-side Cursor Constructor Function

        function createClientSideJSCursor(c,sql) {
            writeln("<SCRIPT>")

            writeln('function RowInfo() {')
            writeln('    this.isDbRow = false')
    	  writeln('    this.oldRowValue = null')
            writeln('}')

            writeln(c.cursorName + 'RowInfo = new Array(' + c.maxRows + ')')
            writeln('for (row=0; row <' + c.maxRows + '; row++ ) {')
            writeln('    ' + c.cursorName + 'RowInfo[row] = new RowInfo()')
            writeln('}')

            writeln('function Row() {')
            for (i = 0; i < c.columns(); i++)
                writeln('   this.' + c.columnName(i) + ' = arguments[' + i +']')
            writeln('}')

            writeln(c.cursorName + 'Rows = new Array(' + c.maxRows + ')')
            row = 0
            numRows = 0
            while (row < c.maxRows && c.next() ) {
                if ( numRows == 0 ) createClientSideColumnProperty(cursorObj)
                numRows++
                write(c.cursorName + 'Rows[' + row + '] = new Row(\n')
                for( i = 0; i < c.columns(); i++) {
                    if ( c[i] == null ) {
                        if ((server.httpdlwVersion.indexOf("3.0") == -1) && _typeOf(c[i])=="number")
                            write( lit(c[i]) )
                        else
                            write('null')
                    }
                    else if ( _typeOf(c[i]) == "object" ) {
                        if ( c[i].toLocaleString != null )
                            write( lit(c[i].toLocaleString().substring(0,8)) ) // DATE type
                        else
                            write( lit(c[i].toString()) )
                    }
                    else {
                        write( lit(c[i]) )
                    }

                    if ( i < (c.columns()-1) )
                        writeln(",")
                    else
                        writeln(")")
                }
                writeln(c.cursorName + 'RowInfo[' + row + '].isDbRow = true')
                row++
            } //while

            writeln("function getNumColumns() {")
            writeln("   return " + c.columns() + "}")

    	writeln("function setValueByName(colName, colVal) {")
    	writeln("    if (this.__oRowBuffer != null) {")
    	writeln("        this.__oRowBuffer.setValueByName(colName, colVal)")
    	writeln("    } else {")
    	writeln("        this[colName] = colVal")
    	writeln("    }")
    	writeln("    saveOldRowValue( this )")
    	writeln("}")

        writeln("function getValueByName(colName) {")
        writeln("   return this.__currentRow[colName]")
        writeln("}")

        writeln("function getValueByNumber(colNum) {")
        for (i = 0; i < c.columns(); i++) {
           writeln("if (colNum == " + i + ")")
           writeln("   return this.__currentRow[" + lit(c.columnName(i)) + "]")
        }//for
        writeln("else return null }\n")

        writeln("function getNumRowsFetched() {")
        writeln("    return this.__numRows")
        writeln("}")

        writeln("function getCurrentRowNumber() {")
        writeln("   return this.__currentRowNumber")
        writeln("}")

        writeln("function getColumnName(colNum) {")
        for (i = 0; i < c.columns(); i++) {
            writeln("if (colNum == " + i + ")")
            writeln("   return " + lit(c.columnName(i)))
            }
        writeln("}")

    	for ( col in c) {
            firstChar = col.substring(0,1).toUpperCase()
            setterName = "set" + firstChar + col.substring(1,col.length)
    	    writeln("function " + setterName + "(val) {")
    	    writeln("    this.__oRowBuffer.setValueByName('" + col + "', val)")
    	    writeln("    saveOldRowValue( this )")
    	    writeln("}")
    	}

        writeln("function csjsCursor() {")
        writeln("   this.__name = " + lit(c.cursorName))
        writeln("   this.__numRows = " + numRows) // numRows may be less than maxRows
    //  writeln("   this.__oRowSupport = " + c.cursorName + "RowSupport")
        writeln("   this.__oRowBuffer = " + c.cursorName + "RowBuffer")
        writeln("   this.__oRowInfo = " + c.cursorName + "RowInfo")
    //  writeln("   this.__SQL = '" + sql + "'") fails if qry has 's
        writeln("   this.__SQL = " + lit( sql ))
        writeln("   this.__currentRowNumber = -1")
        writeln("   this.__currentRow = new Object()")
        writeln("   this.fireChangeEvent = fireChangeEvent")
        writeln("   this.executeQuery = executeQuery")
        writeln("   this.nextRow = next")
        writeln("   this.previousRow = previous ")
        writeln("   this.updateCurrentRow = updateCurrentRow ")
        writeln("   this.deleteRow = deleteRow ")
        writeln("   this.addRow = addRow ")
        writeln("   this.getCurrentRowNumber = getCurrentRowNumber")
        writeln("   this.setCurrentRowNumber = setCurrentRowNumber")
        writeln("   this.setValueByName = setValueByName")
        writeln("   this.getValueByName = getValueByName")
        writeln("   this.getValueByNumber = getValueByNumber")
        writeln("   this.getNumRowsFetched = getNumRowsFetched")
        writeln("   this.getNumColumns = getNumColumns")
        writeln("   this.getColumnName = getColumnName")
        writeln("   this._updateRow = _updateRow ")
        writeln("   this._insertRow = _insertRow ")
        writeln("   this._enableSqlResultWindow = true")
        writeln("   this.gotoRowByColValue = gotoRowByColValue")

    //  Dynamic Column Property Setters
        for ( col in c ) {
            firstChar = col.substring(0,1).toUpperCase()
            setterName = "set" + firstChar + col.substring(1,col.length)
            writeln("    this." + setterName + " = " + setterName)
        }
        writeln("}//csjsCursor\n")

        writeln(c.cursorName + " = new csjsCursor()")
        writeln('</SCRIPT>')
    } // createClientSideJSCursor

    function addWhereCondition( sSQL, sCondition ) {
        sTempSQL = sSQL.toUpperCase()
        var sInsert
        i = sTempSQL.indexOf( "WHERE" )
        if ( i != -1  ) {
            // where clause exists
            sInsert = sCondition + " AND";
            i = i + 6;
        } else {
            // no where... need to add it also
            sInsert = "WHERE " + sCondition;
            i = sTempSQL.indexOf( "GROUP BY" );
            if ( i == -1 ) {
                i = sTempSQL.indexOf( "HAVING" );
                if ( i == -1 ) {
                    i = sTempSQL.indexOf( "ORDER BY" );
                }
            }
            if ( i == -1 ) {
                // it goes at end
                return sSQL + " " + sInsert;
            }
        }
        return sSQL.substring( 0, i ) + sInsert + " " + sSQL.substring( i, sSQL.length );
    }

    function addOrdering( sSQL, sOrdering ) {
        sTempSQL = sSQL.toUpperCase()
        var sInsert
        i = sTempSQL.indexOf( "ORDER BY" )
        if ( i != -1  ) {
            // order by clause exists
            sInsert = sOrdering + ",";
            i = i + 9;
        } else {
            // need to add order by.  Isert at end.
            sInsert = "ORDER BY " + sOrdering;
            return sSQL + " " + sInsert;
        }
        return sSQL.substring( 0, i ) + sInsert + " " + sSQL.substring( i, sSQL.length );
    }

    // Server-side Cursor Constructor Function
    function netscape_peas_JSBufferedCursor(params) {
    	if ( (params.updatable == null) || (params.updatable == "") ) {
    	   params.updatable = false
        }
        if ( (params.filterCol != null) && (params.filterCol != "") ) {
            if ( null != request[params.filterCol] ) {
                sWhereCondition = params.filterCol + " = '" + unescape(request[params.filterCol]) + "'";
            } else {
                sWhereCondition = "1=0"
            }
            params.SQL = addWhereCondition( params.SQL, sWhereCondition );
        }

       if ( (params.sortCol != null) && (params.sortCol != "") ) {
          sOrdering =  params.sortCol;
          if ( false == params.sortAscending )
             sOrdering += " DESC";
          params.SQL = addOrdering( params.SQL, sOrdering );
       }

    	if (server.httpdlwVersion.indexOf("3.0") != -1) {  //--- Server 3.0 ---
             if (params.dbpool == null) {
                debug("Cursor's DBPool property is null - using generic database object.")
                //cursorObj = database.cursor(params.SQL, params.updatable)
                cursorObj = database.cursor(params.SQL, false)
             } else {
                 pool = project[params.dbpool]
                 if (request.connection == null)
                    request.connection = pool.connection(pool.id, pool.timeout)
                 //cursorObj = request.connection.cursor(params.SQL, params.updatable)
                 cursorObj = request.connection.cursor(params.SQL, false)
             }

    	} else  //---Server 2.0---
             cursorObj = database.cursor(params.SQL, params.updatable)

    	// Prop assignments common to both server versions
          cursorObj.cursorName = params.id
          cursorObj.maxRows = params.maxRows
          createClientSideRowBuffer(cursorObj)
          createClientSideJSCursor(cursorObj, params.SQL)
    	cursorObj.close()
        if ( (params.release) && (server.httpdlwVersion.indexOf("1.0") == -1) )
    		request.connection.release()
          return cursorObj
    } // netscape_peas_JSBufferedCursor
        </JSB_CONSTRUCTOR>
    </JSB>

    <JSB_LISTENER NAME="onChangeListener">
        <JSB_METHOD NAME="onChange" TYPE="void">
            <JSB_PARAMETER NAME="propertyName" TYPE="string">
            <JSB_PARAMETER NAME="oldValue" TYPE="undefined">
            <JSB_PARAMETER NAME="newValue" TYPE="undefined">
        </JSB_METHOD>
    </JSB_LISTENER>