<% '============================================================================= ' FILE: db_helpers.asp ' PURPOSE: Database helper functions for parameterized queries ' CREATED: 2025-10-10 ' VERSION: 2.0 - Fixed rs variable conflicts (2025-10-13) '============================================================================= '----------------------------------------------------------------------------- ' FUNCTION: ExecuteParameterizedQuery ' PURPOSE: Executes a SELECT query with parameters (prevents SQL injection) ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' sql (String) - SQL query with ? placeholders ' params (Array) - Array of parameter values ' RETURNS: ADODB.Recordset - Result recordset ' EXAMPLE: ' Set rs = ExecuteParameterizedQuery(objConn, "SELECT * FROM machines WHERE machineid = ?", Array(machineId)) '----------------------------------------------------------------------------- Function ExecuteParameterizedQuery(conn, sql, params) On Error Resume Next Dim cmd, param, i Set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = conn cmd.CommandText = sql cmd.CommandType = 1 ' adCmdText ' Add parameters If IsArray(params) Then For i = 0 To UBound(params) Set param = cmd.CreateParameter("param" & i, GetADOType(params(i)), 1, Len(CStr(params(i))), params(i)) cmd.Parameters.Append param Next End If ' Execute and return recordset Set ExecuteParameterizedQuery = cmd.Execute() ' Check for errors If Err.Number <> 0 Then Call CheckForErrors() End If Set cmd = Nothing End Function '----------------------------------------------------------------------------- ' FUNCTION: ExecuteParameterizedUpdate ' PURPOSE: Executes an UPDATE query with parameters ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' sql (String) - SQL UPDATE statement with ? placeholders ' params (Array) - Array of parameter values ' RETURNS: Integer - Number of records affected '----------------------------------------------------------------------------- Function ExecuteParameterizedUpdate(conn, sql, params) On Error Resume Next Dim cmd, param, i, recordsAffected Set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = conn cmd.CommandText = sql cmd.CommandType = 1 ' adCmdText ' Add parameters If IsArray(params) Then For i = 0 To UBound(params) Set param = cmd.CreateParameter("param" & i, GetADOType(params(i)), 1, Len(CStr(params(i))), params(i)) cmd.Parameters.Append param Next End If ' Execute cmd.Execute recordsAffected ' Check for errors If Err.Number <> 0 Then Call CheckForErrors() End If ExecuteParameterizedUpdate = recordsAffected Set cmd = Nothing End Function '----------------------------------------------------------------------------- ' FUNCTION: ExecuteParameterizedInsert ' PURPOSE: Executes an INSERT query with parameters ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' sql (String) - SQL INSERT statement with ? placeholders ' params (Array) - Array of parameter values ' RETURNS: Integer - Number of records affected '----------------------------------------------------------------------------- Function ExecuteParameterizedInsert(conn, sql, params) On Error Resume Next Dim cmd, param, i, recordsAffected Set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = conn cmd.CommandText = sql cmd.CommandType = 1 ' adCmdText ' Add parameters If IsArray(params) Then For i = 0 To UBound(params) Set param = cmd.CreateParameter("param" & i, GetADOType(params(i)), 1, Len(CStr(params(i))), params(i)) cmd.Parameters.Append param Next End If ' Execute cmd.Execute recordsAffected ' Check for errors If Err.Number <> 0 Then Call CheckForErrors() End If ExecuteParameterizedInsert = recordsAffected Set cmd = Nothing End Function '----------------------------------------------------------------------------- ' FUNCTION: GetADOType ' PURPOSE: Determines ADO data type for a parameter value ' PARAMETERS: ' value (Variant) - Value to check ' RETURNS: Integer - ADO data type constant '----------------------------------------------------------------------------- Function GetADOType(value) ' ADO Type Constants: ' 2 = adSmallInt, 3 = adInteger, 4 = adSingle, 5 = adDouble ' 6 = adCurrency, 7 = adDate, 11 = adBoolean ' 200 = adVarChar, 201 = adLongVarChar If IsNull(value) Then GetADOType = 200 ' adVarChar ElseIf IsNumeric(value) Then If InStr(CStr(value), ".") > 0 Then GetADOType = 5 ' adDouble Else GetADOType = 3 ' adInteger End If ElseIf IsDate(value) Then GetADOType = 7 ' adDate ElseIf VarType(value) = 11 Then ' vbBoolean GetADOType = 11 ' adBoolean Else GetADOType = 200 ' adVarChar (default for strings) End If End Function '----------------------------------------------------------------------------- ' FUNCTION: GetLastInsertId ' PURPOSE: Gets the last auto-increment ID inserted (MySQL specific) ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' RETURNS: Integer - Last insert ID '----------------------------------------------------------------------------- Function GetLastInsertId(conn) On Error Resume Next Dim rsLocal Set rsLocal = conn.Execute("SELECT LAST_INSERT_ID() AS id") If Err.Number <> 0 Then GetLastInsertId = 0 Exit Function End If If Not rsLocal.EOF Then GetLastInsertId = CLng(rsLocal("id")) Else GetLastInsertId = 0 End If rsLocal.Close Set rsLocal = Nothing If Err.Number <> 0 Then GetLastInsertId = 0 End If End Function '----------------------------------------------------------------------------- ' FUNCTION: RecordExists ' PURPOSE: Checks if a record exists based on criteria ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' tableName (String) - Table to check ' fieldName (String) - Field to check ' fieldValue (Variant) - Value to look for ' RETURNS: Boolean - True if record exists '----------------------------------------------------------------------------- Function RecordExists(conn, tableName, fieldName, fieldValue) On Error Resume Next Dim sql, rsLocal sql = "SELECT COUNT(*) AS cnt FROM " & tableName & " WHERE " & fieldName & " = ?" Set rsLocal = ExecuteParameterizedQuery(conn, sql, Array(fieldValue)) If Err.Number <> 0 Then RecordExists = False Exit Function End If If Not rsLocal.EOF Then RecordExists = (CLng(rsLocal("cnt")) > 0) Else RecordExists = False End If rsLocal.Close Set rsLocal = Nothing If Err.Number <> 0 Then RecordExists = False End If End Function '----------------------------------------------------------------------------- ' FUNCTION: GetRecordCount ' PURPOSE: Gets count of records matching criteria ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' tableName (String) - Table to query ' whereClause (String) - WHERE clause (without WHERE keyword) - use ? for params ' params (Array) - Array of parameter values for WHERE clause ' RETURNS: Integer - Count of matching records '----------------------------------------------------------------------------- Function GetRecordCount(conn, tableName, whereClause, params) On Error Resume Next Dim sql, rsLocal If whereClause <> "" Then sql = "SELECT COUNT(*) AS cnt FROM " & tableName & " WHERE " & whereClause Else sql = "SELECT COUNT(*) AS cnt FROM " & tableName End If Set rsLocal = ExecuteParameterizedQuery(conn, sql, params) If Err.Number <> 0 Then GetRecordCount = 0 Exit Function End If If Not rsLocal.EOF Then GetRecordCount = CLng(rsLocal("cnt")) Else GetRecordCount = 0 End If rsLocal.Close Set rsLocal = Nothing If Err.Number <> 0 Then GetRecordCount = 0 End If End Function '----------------------------------------------------------------------------- ' FUNCTION: PropagateControllerToDualpathMachines ' PURPOSE: When a PC controls a machine, also assign it to dualpath'd machines ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' equipmentMachineid (Integer) - The equipment machine being controlled ' pcMachineid (Integer) - The PC that controls the equipment ' RETURNS: Integer - Number of relationships created ' USAGE: Call after creating a "Controls" relationship '----------------------------------------------------------------------------- Function PropagateControllerToDualpathMachines(conn, equipmentMachineid, pcMachineid) On Error Resume Next Dim rsDP, rsDPCheck, controlsTypeID, dualpathMachineId, cnt cnt = 0 ' Get Controls relationship type ID Set rsDP = conn.Execute("SELECT relationshiptypeid FROM relationshiptypes WHERE relationshiptype = 'Controls'") If rsDP.EOF Then PropagateControllerToDualpathMachines = 0 rsDP.Close Set rsDP = Nothing Exit Function End If controlsTypeID = CLng(rsDP("relationshiptypeid")) rsDP.Close Set rsDP = Nothing ' Find all machines with dualpath relationship to this equipment Set rsDP = conn.Execute("SELECT related_machineid FROM machinerelationships mr " & _ "JOIN relationshiptypes rt ON mr.relationshiptypeid = rt.relationshiptypeid " & _ "WHERE mr.machineid = " & CLng(equipmentMachineid) & " " & _ "AND rt.relationshiptype = 'Dualpath' AND mr.isactive = 1") Do While Not rsDP.EOF dualpathMachineId = CLng(rsDP("related_machineid")) ' Check if this dualpath machine already has a Controls relationship with this PC Set rsDPCheck = conn.Execute("SELECT relationshipid FROM machinerelationships " & _ "WHERE machineid = " & CLng(pcMachineid) & " " & _ "AND related_machineid = " & dualpathMachineId & " " & _ "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") If rsDPCheck.EOF Then ' Create Controls relationship: PC -> Dualpath Machine Dim cmdDP Set cmdDP = Server.CreateObject("ADODB.Command") cmdDP.ActiveConnection = conn cmdDP.CommandText = "INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) VALUES (?, ?, ?, 1)" cmdDP.Parameters.Append cmdDP.CreateParameter("@pcid", 3, 1, , CLng(pcMachineid)) cmdDP.Parameters.Append cmdDP.CreateParameter("@equipid", 3, 1, , dualpathMachineId) cmdDP.Parameters.Append cmdDP.CreateParameter("@reltypeid", 3, 1, , controlsTypeID) cmdDP.Execute Set cmdDP = Nothing cnt = cnt + 1 End If rsDPCheck.Close Set rsDPCheck = Nothing rsDP.MoveNext Loop rsDP.Close Set rsDP = Nothing PropagateControllerToDualpathMachines = cnt End Function '----------------------------------------------------------------------------- ' FUNCTION: PropagateControllerFromDualpathMachine ' PURPOSE: When creating a dualpath relationship, copy controller from partner ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' machineId1 (Integer) - First machine in dualpath ' machineId2 (Integer) - Second machine in dualpath ' RETURNS: Integer - Number of relationships created ' USAGE: Call after creating a dualpath relationship '----------------------------------------------------------------------------- Function PropagateControllerFromDualpathMachine(conn, machineId1, machineId2) On Error Resume Next Dim rsCtrl, rsCheck, controlsTypeID, pcMachineid, cnt cnt = 0 ' Get Controls relationship type ID Set rsCtrl = conn.Execute("SELECT relationshiptypeid FROM relationshiptypes WHERE relationshiptype = 'Controls'") If rsCtrl.EOF Then PropagateControllerFromDualpathMachine = 0 rsCtrl.Close Set rsCtrl = Nothing Exit Function End If controlsTypeID = CLng(rsCtrl("relationshiptypeid")) rsCtrl.Close Set rsCtrl = Nothing ' Check if machine1 has a controller, copy to machine2 if machine2 doesn't have one Set rsCtrl = conn.Execute("SELECT machineid FROM machinerelationships " & _ "WHERE related_machineid = " & CLng(machineId1) & " " & _ "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") If Not rsCtrl.EOF Then pcMachineid = CLng(rsCtrl("machineid")) rsCtrl.Close Set rsCtrl = Nothing ' Check if machine2 already has this controller Set rsCheck = conn.Execute("SELECT relationshipid FROM machinerelationships " & _ "WHERE machineid = " & pcMachineid & " AND related_machineid = " & CLng(machineId2) & " " & _ "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") If rsCheck.EOF Then ' Create: PC -> Controls -> machine2 Dim cmdCtrl Set cmdCtrl = Server.CreateObject("ADODB.Command") cmdCtrl.ActiveConnection = conn cmdCtrl.CommandText = "INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) VALUES (?, ?, ?, 1)" cmdCtrl.Parameters.Append cmdCtrl.CreateParameter("@pcid", 3, 1, , pcMachineid) cmdCtrl.Parameters.Append cmdCtrl.CreateParameter("@equipid", 3, 1, , CLng(machineId2)) cmdCtrl.Parameters.Append cmdCtrl.CreateParameter("@reltypeid", 3, 1, , controlsTypeID) cmdCtrl.Execute Set cmdCtrl = Nothing cnt = cnt + 1 End If rsCheck.Close Set rsCheck = Nothing Else rsCtrl.Close Set rsCtrl = Nothing End If ' Now check if machine2 has a controller, copy to machine1 if machine1 doesn't have one Set rsCtrl = conn.Execute("SELECT machineid FROM machinerelationships " & _ "WHERE related_machineid = " & CLng(machineId2) & " " & _ "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") If Not rsCtrl.EOF Then pcMachineid = CLng(rsCtrl("machineid")) rsCtrl.Close Set rsCtrl = Nothing ' Check if machine1 already has this controller Set rsCheck = conn.Execute("SELECT relationshipid FROM machinerelationships " & _ "WHERE machineid = " & pcMachineid & " AND related_machineid = " & CLng(machineId1) & " " & _ "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") If rsCheck.EOF Then ' Create: PC -> Controls -> machine1 Dim cmdCtrl2 Set cmdCtrl2 = Server.CreateObject("ADODB.Command") cmdCtrl2.ActiveConnection = conn cmdCtrl2.CommandText = "INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) VALUES (?, ?, ?, 1)" cmdCtrl2.Parameters.Append cmdCtrl2.CreateParameter("@pcid", 3, 1, , pcMachineid) cmdCtrl2.Parameters.Append cmdCtrl2.CreateParameter("@equipid", 3, 1, , CLng(machineId1)) cmdCtrl2.Parameters.Append cmdCtrl2.CreateParameter("@reltypeid", 3, 1, , controlsTypeID) cmdCtrl2.Execute Set cmdCtrl2 = Nothing cnt = cnt + 1 End If rsCheck.Close Set rsCheck = Nothing Else rsCtrl.Close Set rsCtrl = Nothing End If PropagateControllerFromDualpathMachine = cnt End Function '----------------------------------------------------------------------------- ' FUNCTION: CopyEquipmentDataToDualpathPartner ' PURPOSE: Copy equipment settings from source to dualpath partner ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' sourceMachineId (Integer) - Machine ID with the data to copy FROM ' targetMachineId (Integer) - Machine ID to copy data TO ' COPIES: controllertypeid, controllerosid, modelnumberid, serialnumber ' DOES NOT COPY: mapleft, maptop (location data), machinenumber, hostname ' RETURNS: Boolean - True if successful '----------------------------------------------------------------------------- Function CopyEquipmentDataToDualpathPartner(conn, sourceMachineId, targetMachineId) On Error Resume Next Dim rsSource, cmdUpdate Dim srcControllertypeid, srcControllerosid, srcModelnumberid, srcSerialnumber ' Get source machine data Set rsSource = conn.Execute("SELECT controllertypeid, controllerosid, modelnumberid, serialnumber " & _ "FROM machines WHERE machineid = " & CLng(sourceMachineId)) If rsSource.EOF Then CopyEquipmentDataToDualpathPartner = False rsSource.Close Set rsSource = Nothing Exit Function End If ' Store values (handle NULLs) If Not IsNull(rsSource("controllertypeid")) Then srcControllertypeid = CLng(rsSource("controllertypeid")) Else srcControllertypeid = Null End If If Not IsNull(rsSource("controllerosid")) Then srcControllerosid = CLng(rsSource("controllerosid")) Else srcControllerosid = Null End If If Not IsNull(rsSource("modelnumberid")) Then srcModelnumberid = CLng(rsSource("modelnumberid")) Else srcModelnumberid = Null End If If Not IsNull(rsSource("serialnumber")) Then srcSerialnumber = rsSource("serialnumber") & "" Else srcSerialnumber = Null End If rsSource.Close Set rsSource = Nothing ' Update target machine with source data Set cmdUpdate = Server.CreateObject("ADODB.Command") cmdUpdate.ActiveConnection = conn cmdUpdate.CommandText = "UPDATE machines SET " & _ "controllertypeid = ?, controllerosid = ?, modelnumberid = ?, serialnumber = ? " & _ "WHERE machineid = ?" cmdUpdate.CommandType = 1 ' Add parameters If IsNull(srcControllertypeid) Then cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@ctrl", 3, 1, , Null) Else cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@ctrl", 3, 1, , srcControllertypeid) End If If IsNull(srcControllerosid) Then cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@ctrlOS", 3, 1, , Null) Else cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@ctrlOS", 3, 1, , srcControllerosid) End If If IsNull(srcModelnumberid) Then cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@model", 3, 1, , Null) Else cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@model", 3, 1, , srcModelnumberid) End If If IsNull(srcSerialnumber) Then cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@serial", 200, 1, 100, Null) Else cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@serial", 200, 1, 100, srcSerialnumber) End If cmdUpdate.Parameters.Append cmdUpdate.CreateParameter("@targetId", 3, 1, , CLng(targetMachineId)) cmdUpdate.Execute Set cmdUpdate = Nothing If Err.Number <> 0 Then CopyEquipmentDataToDualpathPartner = False Else CopyEquipmentDataToDualpathPartner = True End If End Function '----------------------------------------------------------------------------- ' FUNCTION: CopyCommConfigToDualpathPartner ' PURPOSE: Copy communication settings (IP, Serial) from source to dualpath partner ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' sourceMachineId (Integer) - Machine ID with the comm config to copy FROM ' targetMachineId (Integer) - Machine ID to copy comm config TO ' COPIES: IP address/port, Serial settings (baud, databits, stopbits, parity) ' RETURNS: Integer - Number of comm records created '----------------------------------------------------------------------------- Function CopyCommConfigToDualpathPartner(conn, sourceMachineId, targetMachineId) On Error Resume Next Dim rsComm, rsCheck, cmdInsert, cnt cnt = 0 ' Get source communication settings (IP and Serial types only) Set rsComm = conn.Execute("SELECT comstypeid, address, port, baud, databits, stopbits, parity " & _ "FROM communications WHERE machineid = " & CLng(sourceMachineId) & " " & _ "AND comstypeid IN (SELECT comstypeid FROM comstypes WHERE typename IN ('IP', 'Serial')) " & _ "AND isactive = 1") Do While Not rsComm.EOF ' Check if target already has this comm type Set rsCheck = conn.Execute("SELECT comid FROM communications " & _ "WHERE machineid = " & CLng(targetMachineId) & " " & _ "AND comstypeid = " & CLng(rsComm("comstypeid")) & " AND isactive = 1") If rsCheck.EOF Then ' Create the comm config for target Set cmdInsert = Server.CreateObject("ADODB.Command") cmdInsert.ActiveConnection = conn cmdInsert.CommandText = "INSERT INTO communications " & _ "(machineid, comstypeid, address, port, baud, databits, stopbits, parity, isactive) " & _ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, 1)" cmdInsert.CommandType = 1 cmdInsert.Parameters.Append cmdInsert.CreateParameter("@machid", 3, 1, , CLng(targetMachineId)) cmdInsert.Parameters.Append cmdInsert.CreateParameter("@comtype", 3, 1, , CLng(rsComm("comstypeid"))) If IsNull(rsComm("address")) Then cmdInsert.Parameters.Append cmdInsert.CreateParameter("@addr", 200, 1, 50, Null) Else cmdInsert.Parameters.Append cmdInsert.CreateParameter("@addr", 200, 1, 50, rsComm("address") & "") End If If IsNull(rsComm("port")) Then cmdInsert.Parameters.Append cmdInsert.CreateParameter("@port", 3, 1, , Null) Else cmdInsert.Parameters.Append cmdInsert.CreateParameter("@port", 3, 1, , CLng(rsComm("port"))) End If If IsNull(rsComm("baud")) Then cmdInsert.Parameters.Append cmdInsert.CreateParameter("@baud", 3, 1, , Null) Else cmdInsert.Parameters.Append cmdInsert.CreateParameter("@baud", 3, 1, , CLng(rsComm("baud"))) End If If IsNull(rsComm("databits")) Then cmdInsert.Parameters.Append cmdInsert.CreateParameter("@databits", 3, 1, , Null) Else cmdInsert.Parameters.Append cmdInsert.CreateParameter("@databits", 3, 1, , CLng(rsComm("databits"))) End If If IsNull(rsComm("stopbits")) Then cmdInsert.Parameters.Append cmdInsert.CreateParameter("@stopbits", 3, 1, , Null) Else cmdInsert.Parameters.Append cmdInsert.CreateParameter("@stopbits", 3, 1, , CLng(rsComm("stopbits"))) End If If IsNull(rsComm("parity")) Then cmdInsert.Parameters.Append cmdInsert.CreateParameter("@parity", 200, 1, 10, Null) Else cmdInsert.Parameters.Append cmdInsert.CreateParameter("@parity", 200, 1, 10, rsComm("parity") & "") End If cmdInsert.Execute Set cmdInsert = Nothing cnt = cnt + 1 End If rsCheck.Close Set rsCheck = Nothing rsComm.MoveNext Loop rsComm.Close Set rsComm = Nothing CopyCommConfigToDualpathPartner = cnt End Function '----------------------------------------------------------------------------- ' FUNCTION: SyncDualpathPartnerData ' PURPOSE: Sync all relevant data between dualpath partners (bidirectional) ' PARAMETERS: ' conn (ADODB.Connection) - Database connection object ' machineId1 (Integer) - First machine in dualpath ' machineId2 (Integer) - Second machine in dualpath ' BEHAVIOR: Copies data from whichever machine has data to the one missing it ' RETURNS: Boolean - True if any data was synced '----------------------------------------------------------------------------- Function SyncDualpathPartnerData(conn, machineId1, machineId2) On Error Resume Next Dim rsM1, rsM2, hasData1, hasData2 ' Check which machine has controller data Set rsM1 = conn.Execute("SELECT controllertypeid FROM machines WHERE machineid = " & CLng(machineId1)) Set rsM2 = conn.Execute("SELECT controllertypeid FROM machines WHERE machineid = " & CLng(machineId2)) hasData1 = False hasData2 = False If Not rsM1.EOF Then hasData1 = Not IsNull(rsM1("controllertypeid")) End If If Not rsM2.EOF Then hasData2 = Not IsNull(rsM2("controllertypeid")) End If rsM1.Close rsM2.Close Set rsM1 = Nothing Set rsM2 = Nothing ' Copy from machine with data to machine without If hasData1 And Not hasData2 Then Call CopyEquipmentDataToDualpathPartner(conn, machineId1, machineId2) Call CopyCommConfigToDualpathPartner(conn, machineId1, machineId2) SyncDualpathPartnerData = True ElseIf hasData2 And Not hasData1 Then Call CopyEquipmentDataToDualpathPartner(conn, machineId2, machineId1) Call CopyCommConfigToDualpathPartner(conn, machineId2, machineId1) SyncDualpathPartnerData = True Else SyncDualpathPartnerData = False End If End Function %>