<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Utils" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM ===			The ScriptForge library and its associated libraries are part of the LibreOffice project.				===
REM ===					Full documentation is available on https://help.libreoffice.org/								===
REM =======================================================================================================================

Option Explicit
Option Private Module

&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos;	SF_Utils
&apos;&apos;&apos;	========
&apos;&apos;&apos;		FOR INTERNAL USE ONLY
&apos;&apos;&apos;		Groups all private functions used by the official modules
&apos;&apos;&apos;		Declares the Global variable _SF_
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;

REM ===================================================================== GLOBALS

Global _SF_		As Variant		&apos;	SF_Root (Basic) object)

&apos;&apos;&apos;	ScriptForge version
Const SF_Version = &quot;26.2&quot;

&apos;&apos;&apos;	Standard symbolic names for VarTypes
&apos;				V_EMPTY			= 0
&apos;				V_NULL			= 1
&apos;				V_INTEGER		= 2
&apos;				V_LONG			= 3
&apos;				V_SINGLE		= 4
&apos;				V_DOUBLE		= 5
&apos;				V_CURRENCY		= 6
&apos;				V_DATE			= 7
&apos;				V_STRING		= 8
&apos;&apos;&apos;	Additional symbolic names for VarTypes
Global Const	V_OBJECT		= 9
Global Const	V_BOOLEAN		= 11
Global Const	V_VARIANT		= 12
Global Const	V_BYTE			= 17
Global Const	V_USHORT		= 18
Global Const	V_ULONG			= 19
Global Const	V_BIGINT		= 35
Global Const	V_DECIMAL		= 37
Global Const	V_ARRAY			= 8192
&apos;&apos;&apos;	Fictive VarTypes
Global Const	V_NUMERIC		= 99	&apos; Synonym of any numeric value [returned by _VarTypeExt()]
Global Const	V_NOTHING		= 101	&apos; Object categories [returned by _VarTypeObj()]		Null object
Global Const	V_UNOOBJECT		= 102	&apos;													Uno object or Uno structure
Global Const	V_SFOBJECT		= 103	&apos;													ScriptForge object: has ObjectType and ServiceName properties
Global Const	V_BASICOBJECT	= 104	&apos;													User Basic object

Type _ObjectDescriptor					&apos; Returned by the _VarTypeObj() method
	iVarType		As Integer			&apos; One of the V_NOTHING, V_xxxOBJECT constants
	sObjectType		As String			&apos; Either &quot;&quot; or &quot;com.sun.star...&quot; or a ScriptForge object type (ex. &quot;SF_SESSION&quot; or &quot;DICTIONARY&quot;)
	sServiceName	As String			&apos; Either &quot;&quot; or the service name of a ScriptForge object type (ex. &quot;ScriptForge.Exception&quot;-
End Type

REM ================================================================== EXCEPTIONS

Const MISSINGARGERROR			=	&quot;MISSINGARGERROR&quot;	&apos;	A mandatory argument is missing
Const ARGUMENTERROR				=	&quot;ARGUMENTERROR&quot;		&apos;	An argument does not pass the _Validate() validation
Const ARRAYERROR				=	&quot;ARRAYERROR&quot;		&apos;	An argument does not pass the _ValidateArray() validation
Const FILEERROR					=	&quot;FILEERROR&quot;			&apos;	An argument does not pass the _ValidateFile() validation

REM =========================================pvA==================== PRIVATE METHODS

REM -----------------------------------------------------------------------------
Public Function _CDateToIso(pvDate As Variant) As Variant
&apos;&apos;&apos;	Returns a string representation of the given Basic date
&apos;&apos;&apos;	Dates as strings are essential in property values, where Basic dates are evil

Dim sIsoDate As Variant			&apos;	Return value

	If VarType(pvDate) = V_DATE Then
		If Year(pvDate) &lt; 1900 Then		&apos;	Time only
			sIsoDate = Right(&quot;0&quot; &amp; Hour(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Minute(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Second(pvDate), 2)
		ElseIf Hour(pvDate) + Minute(pvDate) + Second(pvDate) = 0 Then		&apos;	Date only
			sIsoDate = Year(pvDate) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Month(pvDate), 2) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Day(pvDate), 2)
		Else
			sIsoDate = Year(pvDate) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Month(pvDate), 2) &amp; &quot;-&quot; &amp; Right(&quot;0&quot; &amp; Day(pvDate), 2) _
							&amp; &quot; &quot; &amp; Right(&quot;0&quot; &amp; Hour(pvDate), 2) &amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Minute(pvDate), 2) _
							&amp; &quot;:&quot; &amp; Right(&quot;0&quot; &amp; Second(pvDate), 2)
		End If
	Else
		sIsoDate = pvDate
	End If

	_CDateToIso = sIsoDate

End Function	&apos;	ScriptForge.SF_Utils._CDateToIso

REM -----------------------------------------------------------------------------
Public Function _CDateToUnoDate(pvDate As Variant) As Variant
&apos;&apos;&apos;	Returns a UNO com.sun.star.util.DateTime/Date/Time object depending on the given date
&apos;&apos;&apos;	by using the appropriate CDateToUnoDateXxx builtin function
&apos;&apos;&apos;	UNO dates are essential in property values, where Basic dates are evil

Dim vUnoDate As Variant			&apos;	Return value

	If VarType(pvDate) = V_DATE Then
		If Year(pvDate) &lt; 1900 Then
			vUnoDate = CDateToUnoTime(pvDate)
		ElseIf Hour(pvDate) + Minute(pvDate) + Second(pvDate) = 0 Then
			vUnoDate = CDateToUnoDate(pvDate)
		Else
			vUnoDate = CDateToUnoDateTime(pvDate)
		End If
	Else
		vUnoDate = pvDate
	End If

	_CDateToUnoDate = vUnoDate

End Function	&apos;	ScriptForge.SF_Utils._CDateToUnoDate

REM -----------------------------------------------------------------------------
Public Function _CPropertyValue(ByRef pvValue As Variant) As Variant
&apos;&apos;&apos;	Set a value of a correct type in a com.sun.star.beans.PropertyValue
&apos;&apos;&apos;		Date BASIC variables give error. Change them to UNO types
&apos;&apos;&apos;		Empty arrays should be replaced by Null

Dim vValue As Variant		&apos;	Return value

	If VarType(pvValue) = V_DATE Then
		vValue = SF_Utils._CDateToUnoDate(pvValue)
	ElseIf IsArray(pvValue) Then
		If UBound(pvValue, 1) &lt; LBound(pvValue, 1) Then vValue = Null Else vValue = pvValue
	Else
		vValue = pvValue
	End If
	_CPropertyValue() = vValue
	
End Function	&apos;	ScriptForge.SF_Utils._CPropertyValue

REM -----------------------------------------------------------------------------
Public Function _CStrToDate(ByRef pvStr As String) As Date
&apos;&apos;&apos;	Attempt to convert the input string to a Date variable with the CDate builtin function
&apos;&apos;&apos;	If not successful, returns conventionally -1 (29/12/1899)
&apos;&apos;&apos;	Date patterns: YYYY-MM-DD, HH:MM:DD and YYYY-MM-DD HH:MM:DD

Dim dDate As Date			&apos;	Return value 
Const cstNoDate = -1

	dDate = cstNoDate
Try:
	On Local Error Resume Next
	dDate = CDate(pvStr)

Finally:
	_CStrToDate = dDate
	Exit Function
End Function	&apos;	ScriptForge.SF_Utils._CStrToDate

REM -----------------------------------------------------------------------------
Public Function _EnterFunction(ByVal psSub As String _
								, Optional ByVal psArgs As String _
								, Optional ByVal pbReinitRC As Variant _
								) As Boolean
&apos;&apos;&apos;	Called on top of each public function
&apos;&apos;&apos;	Used to trace routine in/outs (debug mode)
&apos;&apos;&apos;		and to allow the explicit mention of the user call which caused an error
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psSub = the called Sub/Function/Property, usually something like &quot;service.sub&quot;
&apos;&apos;&apos;	Return: True when psSub is called from a user script
&apos;&apos;&apos;		Used to bypass the validation of the arguments when unnecessary

		If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot()	&apos;	First use of ScriptForge during current LibO session
		If IsMissing(psArgs) Then psArgs = &quot;&quot;
		If IsMissing(pbReinitRC) Then pbReinitRC = True
		With _SF_
			If .StackLevel = 0 Then
				.MainFunction = psSub
				.MainFunctionArgs = psArgs
				_EnterFunction = True
				If pbReinitRC Then
					&apos;	Reinitialize return code status
					.ReturnCode = &quot;&quot;
					.ReturnCodeDescription = &quot;&quot;
				End If
			Else
				_EnterFunction = False
			End If
			.StackLevel = .StackLevel + 1
			If .DebugMode Then ._AddToConsole(&quot;==&gt; &quot; &amp; psSub &amp; &quot;(&quot; &amp; .StackLevel &amp; &quot;)&quot;)
		End With

End Function		&apos;	ScriptForge.SF_Utils._EnterFunction

REM -----------------------------------------------------------------------------
Public Function _ErrorHandling(Optional ByVal pbErrorHandler As Boolean) As Boolean
&apos;&apos;&apos;	Error handling is normally ON and can be set OFF for debugging purposes
&apos;&apos;&apos;	Each user visible routine starts with a call to this function to enable/disable
&apos;&apos;&apos;		standard handling of internal errors
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pbErrorHandler = if present, set its value
&apos;&apos;&apos;	Return: the current value of the error handler

	If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot()	&apos;	First use of ScriptForge during current LibO session
	If Not IsMissing(pbErrorHandler) Then _SF_.ErrorHandler = pbErrorHandler
	_ErrorHandling = _SF_.ErrorHandler

End Function	&apos;	ScriptForge.SF_Utils._ErrorHandling

REM -----------------------------------------------------------------------------
Public Sub _ExitFunction(ByVal psSub As String)
&apos;&apos;&apos;	Called in the Finally block of each public function
&apos;&apos;&apos; Manage ScriptForge internal aborts
&apos;&apos;&apos; Resets MainFunction (root) when exiting the method called by a user script
&apos;&apos;&apos;	Used to trace routine in/outs (debug mode)
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psSub = the called Sub/Function/Property, usually something like &quot;service.sub&quot;

		If IsEmpty(_SF_) Or IsNull(_SF_) Then SF_Utils._InitializeRoot()	&apos;	Useful only when current module has been recompiled
		With _SF_
			If Err &gt; 0 Then
				SF_Exception.RaiseAbort(psSub)
			End If
			If .StackLevel = 1 Then
				.MainFunction = &quot;&quot;
				.MainFunctionArgs = &quot;&quot;
			End If
			If .DebugMode Then ._AddToConsole(&quot;&lt;== &quot; &amp; psSub &amp; &quot;(&quot; &amp; .StackLevel &amp; &quot;)&quot;)
			If .StackLevel &gt; 0 Then .StackLevel = .StackLevel - 1
		End With
	
End Sub			&apos;	ScriptForge.SF_Utils._ExitFunction

REM -----------------------------------------------------------------------------
Public Sub _ExportScriptForgePOTFile(ByVal FileName As String)
&apos;&apos;&apos;	Export the ScriptForge POT file related to its own user interface
&apos;&apos;&apos;	Should be called only before issuing new ScriptForge releases only
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		FileName: the resulting file. If it exists, is overwritten without warning

Dim sHeader As String			&apos;	The specific header to insert

	sHeader = &quot;&quot; _
				&amp; &quot;*********************************************************************\n&quot; _
				&amp; &quot;*** The ScriptForge library and its associated libraries          ***\n&quot; _
				&amp; &quot;*** are part of the LibreOffice project.                          ***\n&quot; _
				&amp; &quot;*********************************************************************\n&quot; _
				&amp; &quot;\n&quot; _
				&amp; &quot;ScriptForge Release &quot; &amp; SF_Version &amp; &quot;\n&quot; _
				&amp; &quot;-----------------------&quot;

Try:
	With _SF_
		If Not IsNull(.LocalizedInterface) Then .LocalizedInterface.Dispose()
		._LoadLocalizedInterface(psMode := &quot;ADDTEXT&quot;)	&apos;	Force reload of labels from the code
		.LocalizedInterface.ExportToPOTFile(FileName, Header := sHeader)
	End With

Finally:
	Exit Sub
End Sub			&apos;	ScriptForge.SF_Utils._ExportScriptForgePOTFile

REM -----------------------------------------------------------------------------
Public Function _GetPropertyValue(ByRef pvArgs As Variant, ByVal psName As String) As Variant
&apos;&apos;&apos;	Returns the Value corresponding to the given name
&apos;&apos;&apos;	Args
&apos;&apos;&apos;		pvArgs: a zero_based array of PropertyValues
&apos;&apos;&apos;		psName: the comparison is not case-sensitive
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		Zero-length string if not found

Dim vValue As Variant			&apos;	Return value
Dim i As Long

	vValue = &quot;&quot;
	If IsArray(pvArgs) Then
		For i = LBound(pvArgs) To UBound(pvArgs)
			If UCase(psName) = UCase(pvArgs(i).Name) Then
				vValue = pvArgs(i).Value
				Exit For
			End If
		Next i
	End If
	_GetPropertyValue = vValue

End Function	&apos;	ScriptForge.SF_Utils._GetPropertyValue

REM -----------------------------------------------------------------------------
Public Function _GetRegistryKeyContent(ByVal psKeyName as string _
										, Optional pbForUpdate as Boolean _
										) As Variant
&apos;&apos;&apos;	Implement a ConfigurationProvider service
&apos;&apos;&apos;	Derived from the Tools library
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psKeyName: the name of the node in the configuration tree
&apos;&apos;&apos;		pbForUpdate: default = False

Dim oConfigProvider as Object		&apos;	com.sun.star.configuration.ConfigurationProvider
Dim vNodePath(0) as New com.sun.star.beans.PropertyValue
Dim sConfig As String				&apos;	One of next 2 constants
Const cstConfig			= &quot;com.sun.star.configuration.ConfigurationAccess&quot;
Const cstConfigUpdate	= &quot;com.sun.star.configuration.ConfigurationUpdateAccess&quot;

	Set oConfigProvider = _GetUNOService(&quot;ConfigurationProvider&quot;)
	vNodePath(0).Name = &quot;nodepath&quot;
	vNodePath(0).Value = psKeyName

	If IsMissing(pbForUpdate) Then pbForUpdate = False
	If pbForUpdate Then sConfig = cstConfigUpdate Else sConfig = cstConfig

	Set _GetRegistryKeyContent = oConfigProvider.createInstanceWithArguments(sConfig, vNodePath())

End Function	&apos;	ScriptForge.SF_Utils._GetRegistryKeyContent

REM -----------------------------------------------------------------------------
Private Function _GetSetting(ByVal psPreference As String, psProperty As String) As Variant
&apos;&apos;&apos;	Find in the configuration a specific setting based on its location in the
&apos;&apos;&apos;	settings registry

Dim oConfigProvider As Object		&apos;	com.sun.star.configuration.ConfigurationProvider
Dim vNodePath As Variant			&apos;	Array of com.sun.star.beans.PropertyValue

	&apos;	Derived from the Tools library
	Set oConfigProvider = createUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
	vNodePath = Array(SF_Utils._MakePropertyValue(&quot;nodepath&quot;, psPreference))

	_GetSetting = oConfigProvider.createInstanceWithArguments( _
					&quot;com.sun.star.configuration.ConfigurationAccess&quot;, vNodePath()).getByName(psProperty)

End Function	&apos;	ScriptForge.SF_Utils._GetSetting

REM -----------------------------------------------------------------------------
Public Function _GetUNOService(ByVal psService As String _
									, Optional ByVal pvArg As Variant _
									) As Object
&apos;&apos;&apos;	Create a UNO service
&apos;&apos;&apos;	Each service is called only once
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psService: shortcut to service
&apos;&apos;&apos;		pvArg: some services might require an argument

Dim sLocale As String			&apos;	fr-BE f.i.
Dim oDefaultContext As Object

	Set _GetUNOService = Nothing
	With _SF_
		Select Case psService
			Case &quot;BrowseNodeFactory&quot;
				Set oDefaultContext = GetDefaultContext()
				If Not IsNull(oDefaultContext) Then Set _GetUNOService = oDefaultContext.getValueByName(&quot;/singletons/com.sun.star.script.browse.theBrowseNodeFactory&quot;)
			Case &quot;CalendarImpl&quot;
				If IsEmpty(.CalendarImpl) Or IsNull(.CalendarImpl) Then
					Set .CalendarImpl = CreateUnoService(&quot;com.sun.star.i18n.CalendarImpl&quot;)
				End If
				Set _GetUNOService = .CalendarImpl
			Case &quot;CharacterClass&quot;
				If IsEmpty(.CharacterClass) Or IsNull(.CharacterClass) Then
					Set .CharacterClass = CreateUnoService(&quot;com.sun.star.i18n.CharacterClassification&quot;)
				End If
				Set _GetUNOService = .CharacterClass
			Case &quot;ConfigurationProvider&quot;
				If IsEmpty(.ConfigurationProvider) Or IsNull(.ConfigurationProvider) Then
					Set .ConfigurationProvider = CreateUnoService(&quot;com.sun.star.configuration.ConfigurationProvider&quot;)
				End If
				Set _GetUNOService = .ConfigurationProvider
			Case &quot;CoreReflection&quot;
				If IsEmpty(.CoreReflection) Or IsNull(.CoreReflection) Then
					Set .CoreReflection = CreateUnoService(&quot;com.sun.star.reflection.CoreReflection&quot;)
				End If
				Set _GetUNOService = .CoreReflection
			Case &quot;DatabaseContext&quot;
				If IsEmpty(.DatabaseContext) Or IsNull(.DatabaseContext) Then
					Set .DatabaseContext = CreateUnoService(&quot;com.sun.star.sdb.DatabaseContext&quot;)
				End If
				Set _GetUNOService = .DatabaseContext
			Case &quot;DispatchHelper&quot;
				If IsEmpty(.DispatchHelper) Or IsNull(.DispatchHelper) Then
					Set .DispatchHelper = CreateUnoService(&quot;com.sun.star.frame.DispatchHelper&quot;)
				End If
				Set _GetUNOService = .DispatchHelper
			Case &quot;FileAccess&quot;
				If IsEmpty(.FileAccess) Or IsNull(.FileAccess) Then
					Set .FileAccess = CreateUnoService(&quot;com.sun.star.ucb.SimpleFileAccess&quot;)
				End If
				Set _GetUNOService = .FileAccess
			Case &quot;FilterFactory&quot;
				If IsEmpty(.FilterFactory) Or IsNull(.FilterFactory) Then
					Set .FilterFactory = CreateUnoService(&quot;com.sun.star.document.FilterFactory&quot;)
				End If
				Set _GetUNOService = .FilterFactory
			Case &quot;FormatLocale&quot;
				If IsEmpty(.FormatLocale) Or IsNull(.FormatLocale) Then
					.FormatLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
					&apos;	1st and 2nd chance
					sLocale = SF_Utils._GetSetting(&quot;org.openoffice.Setup/L10N&quot;, &quot;ooSetupSystemLocale&quot;)
					If Len(sLocale) = 0 Then sLocale = SF_Utils._GetSetting(&quot;org.openoffice.System/L10N&quot;, &quot;UILocale&quot;)
					.FormatLocale.Language = Split(sLocale, &quot;-&quot;)(0)	&apos;	Language is most often 2 chars long, but not always
					.FormatLocale.Country = Right(sLocale, 2)
				End If
				Set _GetUNOService = .FormatLocale
			Case &quot;FunctionAccess&quot;
				If IsEmpty(.FunctionAccess) Or IsNull(.FunctionAccess) Then
					Set .FunctionAccess = CreateUnoService(&quot;com.sun.star.sheet.FunctionAccess&quot;)
				End If
				Set _GetUNOService = .FunctionAccess
			Case &quot;GraphicExportFilter&quot;
				If IsEmpty(.GraphicExportFilter) Or IsNull(.GraphicExportFilter) Then
					Set .GraphicExportFilter = CreateUnoService(&quot;com.sun.star.drawing.GraphicExportFilter&quot;)
				End If
				Set _GetUNOService = .GraphicExportFilter
			Case &quot;GraphicProvider&quot;
				If IsEmpty(.GraphicProvider) Or IsNull(.GraphicProvider) Then
					Set .GraphicProvider = CreateUnoService(&quot;com.sun.star.graphic.GraphicProvider&quot;)
				End If
				Set _GetUNOService = .GraphicProvider
			Case &quot;Introspection&quot;
				If IsEmpty(.Introspection) Or IsNull(.Introspection) Then
					Set .Introspection = CreateUnoService(&quot;com.sun.star.beans.Introspection&quot;)
				End If
				Set _GetUNOService = .Introspection
			Case &quot;LocaleData&quot;
				If IsEmpty(.LocaleData) Or IsNull(.LocaleData) Then
					Set .LocaleData = CreateUnoService(&quot;com.sun.star.i18n.LocaleData&quot;)
				End If
				Set _GetUNOService = .LocaleData
			Case &quot;MacroExpander&quot;
				Set oDefaultContext = GetDefaultContext()
				If Not IsNull(oDefaultContext) Then Set _GetUNOService = oDefaultContext.getValueByName(&quot;/singletons/com.sun.star.util.theMacroExpander&quot;)
			Case &quot;MailService&quot;
				If IsEmpty(.MailService) Or IsNull(.MailService) Then
					If GetGuiType = 1 Then		&apos;	Windows
						Set .MailService = CreateUnoService(&quot;com.sun.star.system.SimpleSystemMail&quot;)
					Else
						Set .MailService = CreateUnoService(&quot;com.sun.star.system.SimpleCommandMail&quot;)
					End If
				End If
				Set _GetUNOService = .MailService
			Case &quot;ModuleUIConfigurationManagerSupplier&quot;
				If IsEmpty(.ModuleUIConfigurationManagerSupplier) Or IsNull(.ModuleUIConfigurationManagerSupplier) Then
					Set .ModuleUIConfigurationManagerSupplier = CreateUnoService(&quot;com.sun.star.ui.ModuleUIConfigurationManagerSupplier&quot;)
				End If
				Set _GetUNOService = .ModuleUIConfigurationManagerSupplier
			Case &quot;Number2Text&quot;
				If IsEmpty(.Number2Text) Or IsNull(.Number2Text) Then
					Set .Number2Text = CreateUnoService(&quot;com.sun.star.linguistic2.NumberText&quot;)
				End If
				Set _GetUNOService = .Number2Text
			Case &quot;OfficeLocale&quot;
				If IsEmpty(.OfficeLocale) Or IsNull(.OfficeLocale) Then
					.OfficeLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
					&apos;	1st and 2nd chance
					sLocale = SF_Utils._GetSetting(&quot;org.openoffice.Setup/L10N&quot;, &quot;ooLocale&quot;)
					If Len(sLocale) = 0 Then sLocale = SF_Utils._GetSetting(&quot;org.openoffice.System/L10N&quot;, &quot;UILocale&quot;)
					.OfficeLocale.Language = Split(sLocale, &quot;-&quot;)(0)	&apos;	Language is most often 2 chars long, but not always
					.OfficeLocale.Country = Right(sLocale, 2)
				End If
				Set _GetUNOService = .OfficeLocale
			Case &quot;PackageInformationProvider&quot;
				If IsEmpty(.PackageProvider) Or IsNull(.PackageProvider) Then
					Set .PackageProvider = GetDefaultContext.getByName(&quot;/singletons/com.sun.star.deployment.PackageInformationProvider&quot;)
				End If
				Set _GetUNOService = .PackageProvider
			Case &quot;PathSettings&quot;
				If IsEmpty(.PathSettings) Or IsNull(.PathSettings) Then
					Set .PathSettings = CreateUnoService(&quot;com.sun.star.util.PathSettings&quot;)
				End If
				Set _GetUNOService = .PathSettings
			Case &quot;PathSubstitution&quot;
				If IsEmpty(.PathSubstitution) Or IsNull(.PathSubstitution) Then
					Set .PathSubstitution = CreateUnoService(&quot;com.sun.star.util.PathSubstitution&quot;)
				End If
				Set _GetUNOService = .PathSubstitution
			Case &quot;PrinterServer&quot;
				If IsEmpty(.PrinterServer) Or IsNull(.PrinterServer) Then
					Set .PrinterServer = CreateUnoService(&quot;com.sun.star.awt.PrinterServer&quot;)
				End If
				Set _GetUNOService = .PrinterServer
			Case &quot;ScriptProvider&quot;
				If IsMissing(pvArg) Then pvArg = SF_Session.SCRIPTISAPPLICATION
				Select Case LCase(pvArg)
					Case SF_Session.SCRIPTISEMBEDDED	&apos;	Document
						If Not IsNull(ThisComponent) Then Set _GetUNOService = ThisComponent.getScriptProvider()
					Case Else
						If IsEmpty(.ScriptProvider) Or IsNull(.ScriptProvider) Then
							Set .ScriptProvider =  _
								CreateUnoService(&quot;com.sun.star.script.provider.MasterScriptProviderFactory&quot;).createScriptProvider(&quot;&quot;)
						End If
						Set _GetUNOService = .ScriptProvider
				End Select
			Case &quot;SearchOptions&quot;
				If IsEmpty(.SearchOptions) Or IsNull(.SearchOptions) Then
					Set .SearchOptions = New com.sun.star.util.SearchOptions
					With .SearchOptions
						.algorithmType = com.sun.star.util.SearchAlgorithms.REGEXP
						.searchFlag = 0
					End With
				End If
				Set _GetUNOService = .SearchOptions
			Case &quot;SystemLocale&quot;, &quot;Locale&quot;
				If IsEmpty(.SystemLocale) Or IsNull(.SystemLocale) Then
					.SystemLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
					sLocale = SF_Utils._GetSetting(&quot;org.openoffice.System/L10N&quot;, &quot;SystemLocale&quot;)
					.SystemLocale.Language = Split(sLocale, &quot;-&quot;)(0)	&apos;	Language is most often 2 chars long, but not always
					.SystemLocale.Country = Right(sLocale, 2)
				End If
				Set _GetUNOService = .SystemLocale
			Case &quot;SystemShellExecute&quot;
				If IsEmpty(.SystemShellExecute) Or IsNull(.SystemShellExecute) Then
					Set .SystemShellExecute = CreateUnoService(&quot;com.sun.star.system.SystemShellExecute&quot;)
				End If
				Set _GetUNOService = .SystemShellExecute
			Case &quot;TextSearch&quot;
				If IsEmpty(.TextSearch) Or IsNull(.TextSearch) Then
					Set .TextSearch = CreateUnoService(&quot;com.sun.star.util.TextSearch&quot;)
				End If
				Set _GetUNOService = .TextSearch
			Case &quot;Toolkit&quot;
				If IsEmpty(.Toolkit) Or IsNull(.Toolkit) Then
					Set .Toolkit = CreateUnoService(&quot;com.sun.star.awt.Toolkit&quot;)
				End If
				Set _GetUNOService = .Toolkit
			Case &quot;TransientDocumentFactory&quot;
				If IsEmpty(.TransientDocument) Or IsNull(.TransientDocument) Then
					Set .TransientDocument = CreateUnoService(&quot;com.sun.star.frame.TransientDocumentsDocumentContentFactory&quot;)
				End If
				Set _GetUNOService = .TransientDocument
			Case &quot;URLTransformer&quot;
				If IsEmpty(.URLTransformer) Or IsNull(.URLTransformer) Then
					Set .URLTransformer = CreateUnoService(&quot;com.sun.star.util.URLTransformer&quot;)
				End If
				Set _GetUNOService = .URLTransformer
			Case Else
		End Select
	End With

End Function	&apos;	ScriptForge.SF_Utils._GetUNOService

REM -----------------------------------------------------------------------------
Public Sub _InitializeRoot(Optional ByVal pbForce As Boolean)
&apos;&apos;&apos;	Initialize _SF_ as SF_Root basic object
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pbForce = True forces the reinit (default = False)

	If IsMissing(pbForce) Then pbForce = False
	If pbForce Then Set _SF_ = Nothing
	If IsEmpty(_SF_) Or IsNull(_SF_) Then
		Set _SF_ = New SF_Root
		Set _SF_.[Me] = _SF_
	End If
	
End Sub		&apos;	ScriptForge.SF_Utils._InitializeRoot

REM -----------------------------------------------------------------------------
Public Function _MakePropertyValue(ByVal psName As String _
									, ByRef pvValue As Variant _
									) As com.sun.star.beans.PropertyValue
&apos;&apos;&apos;	Create and return a new com.sun.star.beans.PropertyValue

Dim oPropertyValue As New com.sun.star.beans.PropertyValue

	With oPropertyValue
		.Name = psName
		.Value = SF_Utils._CPropertyValue(pvValue)
	End With
	_MakePropertyValue() = oPropertyValue
	
End Function	&apos;	ScriptForge.SF_Utils._MakePropertyValue

REM -----------------------------------------------------------------------------
Public Function _Repr(ByVal pvArg As Variant, Optional ByVal plMax As Long) As String
&apos;&apos;&apos;	Convert pvArg into a readable string (truncated if length &gt; plMax)
&apos;&apos;&apos;	Args
&apos;&apos;&apos;		pvArg: may be of any type
&apos;&apos;&apos;		plMax: maximum length of the resulting string (default = 32K)

Dim sArg As String			&apos;	Return value
Dim oObject As Object		&apos;	Alias of argument to avoid &quot;Object variable not set&quot;
Dim oObjectDesc As Object	&apos;	Object descriptor
Dim sLength As String		&apos;	String length as a string
Dim i As Long
Const cstBasicObject = &quot;com.sun.star.script.NativeObjectWrapper&quot;

Const cstMaxLength = 2^15 - 1	&apos;	32767
Const cstByteLength = 25
Const cstEtc = &quot; … &quot;

	If IsMissing(plMax) Then plMax = cstMaxLength
	If plMax = 0 Then plMax = cstMaxLength
	If IsArray(pvArg) Then
		sArg = SF_Array._Repr(pvArg)
	Else
		Select Case VarType(pvArg)
			Case V_EMPTY			:		sArg = &quot;[EMPTY]&quot;
			Case V_NULL				:		sArg = &quot;[NULL]&quot;
			Case V_OBJECT
				Set oObjectDesc = SF_Utils._VarTypeObj(pvArg)
				With oObjectDesc
					Select Case .iVarType
						Case V_NOTHING		:	sArg = &quot;[NOTHING]&quot;
						Case V_OBJECT, V_BASICOBJECT
							sArg = &quot;[OBJECT]&quot;
						Case V_UNOOBJECT	:	sArg = &quot;[&quot; &amp; .sObjectType &amp; &quot;]&quot;
						Case V_SFOBJECT
							If Left(.sObjectType, 3) = &quot;SF_&quot; Then	&apos;	Standard module
								sArg = &quot;[&quot; &amp; .sObjectType &amp; &quot;]&quot;
							Else									&apos;	Class module must have a _Repr() method
								Set oObject = pvArg
								sArg = oObject._Repr()
							End If
					End Select
				End With
			Case V_VARIANT			:		sArg = &quot;[VARIANT]&quot;
			Case V_STRING
				sArg = SF_String._Repr(pvArg)
			Case V_BOOLEAN			:		sArg = Iif(pvArg, &quot;[TRUE]&quot;, &quot;[FALSE]&quot;)
			Case V_BYTE				:		sArg = Right(&quot;00&quot; &amp; Hex(pvArg), 2)
			Case V_SINGLE, V_DOUBLE, V_CURRENCY
				sArg = Format(pvArg)
				If InStr(1, sArg, &quot;E&quot;, 1) = 0 Then sArg = Format(pvArg, &quot;##0.0##&quot;)
				sArg = Replace(sArg, &quot;,&quot;, &quot;.&quot;)	&apos;Force decimal point
			Case V_BIGINT			:		sArg = CStr(CLng(pvArg))
			Case V_DATE				:		sArg = _CDateToIso(pvArg)
			Case Else				:		sArg = CStr(pvArg)
		End Select
	End If
	If Len(sArg) &gt; plMax Then 
		sLength = &quot;(&quot; &amp; Len(sArg) &amp; &quot;)&quot;
		sArg = Left(sArg, plMax - Len(cstEtc) - Len(slength)) &amp; cstEtc &amp; sLength
	End If
	_Repr = sArg
	
End Function	&apos;	ScriptForge.SF_Utils._Repr

REM -----------------------------------------------------------------------------
Private Function _ReprValues(Optional ByVal pvArgs As Variant _
								, Optional ByVal plMax As Long _
								) As String
&apos;&apos;&apos;	Convert an array of values to a comma-separated list of readable strings

Dim sValues As String			&apos;	Return value
Dim sValue As String			&apos;	A single value
Dim vValue As Variant			&apos;	A single item in the argument
Dim i As Long					&apos;	Items counter
Const cstMax = 20				&apos;	Maximum length of single string
Const cstContinue = &quot;…&quot;			&apos;	Unicode continuation char U+2026

	_ReprValues = &quot;&quot;
	If IsMissing(pvArgs) Then Exit Function
	If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
	sValues = &quot;&quot;
	For i = 0 To UBound(pvArgs)
		vValue = pvArgs(i)
		If i &lt; plMax Then
			If VarType(vValue) = V_STRING Then sValue = &quot;&quot;&quot;&quot; &amp; vValue &amp; &quot;&quot;&quot;&quot; Else sValue = SF_Utils._Repr(vValue, cstMax)
			If Len(sValues) = 0 Then sValues = sValue Else sValues = sValues &amp; &quot;, &quot; &amp; sValue
		ElseIf i &lt; UBound(pvArgs) Then
			sValues = sValues &amp; &quot;, &quot; &amp; cstContinue
			Exit For
		End If
	Next i
	_ReprValues = sValues
	
End Function	&apos;	ScriptForge.SF_Utils._ReprValues

REM -----------------------------------------------------------------------------
Public Function _SetPropertyValue(ByVal pvPropertyValue As Variant _
									, ByVal psName As String _
									, ByRef pvValue As Variant _
									) As Variant
&apos;&apos;&apos;	Return the 1st argument (passed by reference), which is an array of property values
&apos;&apos;&apos;	If the property psName exists, update it with pvValue, otherwise create it on top of the returned array

Dim oPropertyValue As New com.sun.star.beans.PropertyValue
Dim lIndex As Long				&apos;	Found entry
Dim vValue As Variant			&apos;	Alias of pvValue
Dim vProperties As Variant		&apos;	Alias of pvPropertyValue
Dim i As Long

	lIndex = -1
	vProperties = pvPropertyValue
	For i = 0 To UBound(vProperties)
		If vProperties(i).Name = psName Then
			lIndex = i
			Exit For
		End If
	Next i
	If lIndex &lt; 0 Then		&apos;	Not found
		lIndex = UBound(vProperties) + 1
		ReDim Preserve vProperties(0 To lIndex)
		Set oPropertyValue = SF_Utils._MakePropertyValue(psName, pvValue)
		vProperties(lIndex) = oPropertyValue
		vProperties = vProperties
	Else					&apos;	psName exists already in array of property values
		vProperties(lIndex).Value = SF_Utils._CPropertyValue(pvValue)
	End If

	_SetPropertyValue = vProperties
	
End Function	&apos;	ScriptForge.SF_Utils._SetPropertyValue

REM -----------------------------------------------------------------------------
Private Function _TypeNames(Optional ByVal pvArgs As Variant) As String
&apos;&apos;&apos;	Converts the array of VarTypes to a comma-separated list of TypeNames

Dim sTypes As String			&apos;	Return value
Dim sType As String				&apos;	A single type
Dim iType As Integer			&apos;	A single item of the argument

	_TypeNames = &quot;&quot;
	If IsMissing(pvArgs) Then Exit Function
	If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs)
	sTypes = &quot;&quot;
	For Each iType In pvArgs
		Select Case iType
			Case V_EMPTY	:	sType = &quot;Empty&quot;
			Case V_NULL		:	sType = &quot;Null&quot;
			Case V_INTEGER	:	sType = &quot;Integer&quot;
			Case V_LONG		:	sType = &quot;Long&quot;
			Case V_SINGLE	:	sType = &quot;Single&quot;
			Case V_DOUBLE	:	sType = &quot;Double&quot;
			Case V_CURRENCY	:	sType = &quot;Currency&quot;
			Case V_DATE		:	sType = &quot;Date&quot;
			Case V_STRING	:	sType = &quot;String&quot;
			Case V_OBJECT	:	sType = &quot;Object&quot;
			Case V_BOOLEAN	:	sType = &quot;Boolean&quot;
			Case V_VARIANT	:	sType = &quot;Variant&quot;
			Case V_DECIMAL	:	sType = &quot;Decimal&quot;
			Case &gt;= V_ARRAY	:	sType = &quot;Array&quot;
			Case V_NUMERIC	:	sType = &quot;Numeric&quot;
		End Select
		If Len(sTypes) = 0 Then sTypes = sType Else sTypes = sTypes &amp; &quot;, &quot; &amp; sType
	Next iType
	_TypeNames = sTypes

End Function	&apos;	ScriptForge.SF_Utils._TypeNames

REM -----------------------------------------------------------------------------
Public Function _Validate(Optional ByRef pvArgument As Variant _
							, ByVal psName As String _
							, Optional ByVal pvTypes As Variant _
							, Optional ByVal pvValues As Variant _
							, Optional ByVal pvCaseSensitive As Variant _
							, Optional ByVal pvObjectType As Variant _
							) As Boolean
&apos;&apos;&apos;	Validate the arguments set by user scripts
&apos;&apos;&apos;	The arguments of the function define the validation rules
&apos;&apos;&apos; This function ignores arrays. Use _ValidateArray instead
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvArgument: the argument to (in)validate
&apos;&apos;&apos;		psName: the documented name of the argument (can be inserted in an error message)
&apos;&apos;&apos;		pvTypes: array of allowed VarTypes
&apos;&apos;&apos;		pvValues: array of allowed values
&apos;&apos;&apos;		pvCaseSensitive: when True the comparison between strings is done case-sensitively
&apos;&apos;&apos;		pvObjectType: mandatory Basic class
&apos;&apos;&apos;	Return: True if validation OK
&apos;&apos;&apos;			Otherwise an error is raised
&apos;&apos;&apos;	Exceptions:
&apos;&apos;&apos;		ARGUMENTERROR

Dim iVarType As Integer			&apos;	Extended VarType of argument
Dim bValid As Boolean			&apos;	Returned value
Dim oObjectDescriptor As Object	&apos;	_ObjectDescriptor type
Const cstMaxLength = 256	&apos;	Maximum length of readable value
Const cstMaxValues = 10		&apos;	Maximum number of allowed items to list in an error message 

	&apos;	To avoid useless recursions, keep main function, only increase stack depth
	_SF_.StackLevel = _SF_.StackLevel + 1
	On Local Error GoTo Finally		&apos;	Do never interrupt

Try:
	bValid = True
	If IsMissing(pvArgument) Then GoTo CatchMissing
	If IsMissing(pvCaseSensitive) Or IsEmpty(pvCaseSensitive) Then pvCaseSensitive = False
	If IsMissing(pvObjectType) Or IsEmpty(pvObjectType) Then pvObjectType = &quot;&quot;
	iVarType = SF_Utils._VarTypeExt(pvArgument)

	&apos;	Arrays NEVER pass validation
	If iVarType &gt;= V_ARRAY Then
		bValid = False
	Else
		&apos;	Check existence of argument
		bValid = iVarType &lt;&gt; V_NULL And iVarType &lt;&gt; V_EMPTY
		&apos;	Check if argument&apos;s VarType is valid
		If bValid And Not IsMissing(pvTypes) Then
			If Not IsArray(pvTypes) Then bValid = ( pvTypes = iVarType ) Else bValid = SF_Array.Contains(pvTypes, iVarType)
		End If
		&apos;	Check if argument&apos;s value is valid
		If bValid And Not IsMissing(pvValues) Then
			If Not IsArray(pvValues) Then pvValues = Array(pvValues)
			bValid = SF_Array.Contains(pvValues, pvArgument, CaseSensitive := pvCaseSensitive)
		End If
		&apos;	Check instance types
		If bValid And Len(pvObjectType) &gt; 0 And iVarType = V_OBJECT Then
			&apos;Set oArgument = pvArgument
			Set oObjectDescriptor = SF_Utils._VarTypeObj(pvArgument)
			bValid = ( oObjectDescriptor.iVarType = V_SFOBJECT )
			If bValid Then bValid = ( oObjectDescriptor.sObjectType = pvObjectType )
		End If
	End If

	If Not bValid Then
		&apos;&apos;&apos;	Library:	ScriptForge
		&apos;&apos;&apos;	Service:	Array
		&apos;&apos;&apos;	Method:		Contains
		&apos;&apos;&apos;	Arguments:	Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;]
		&apos;&apos;&apos;	A serious error has been detected on argument SortOrder
		&apos;&apos;&apos;		Rules:	SortOrder is of type String
		&apos;&apos;&apos;				SortOrder must contain one of next values: &quot;ASC&quot;, &quot;DESC&quot;, &quot;&quot;
		&apos;&apos;&apos;		Actual value:	&quot;Ascending&quot;
		SF_Exception.RaiseFatal(ARGUMENTERROR _
				, SF_Utils._Repr(pvArgument, cstMaxLength), psName, SF_Utils._TypeNames(pvTypes) _
				, SF_Utils._ReprValues(pvValues, cstMaxValues), pvCaseSensitive, pvObjectType _
				)
	End If

Finally:
	_Validate = bValid
	_SF_.StackLevel = _SF_.StackLevel - 1
	Exit Function
CatchMissing:
	bValid = False
	SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
	GoTo Finally
End Function	&apos;	ScriptForge.SF_Utils._Validate

REM -----------------------------------------------------------------------------
Public Function _ValidateArray(Optional ByRef pvArray As Variant _
								, ByVal psName As String _
								, Optional ByVal piDimensions As Integer _
								, Optional ByVal piType As Integer _
								, Optional ByVal pbNotNull As Boolean _
								) As Boolean
&apos;&apos;&apos;	Validate the (array) arguments set by user scripts
&apos;&apos;&apos;	The arguments of the function define the validation rules
&apos;&apos;&apos; This function ignores non-arrays. Use _Validate instead
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvArray: the argument to (in)validate
&apos;&apos;&apos;		psName: the documented name of the array (can be inserted in an error message)
&apos;&apos;&apos;		piDimensions: the # of dimensions the array must have. 0 = Any (default)
&apos;&apos;&apos;		piType: (default = -1, i.e. not applicable)
&apos;&apos;&apos;			For 2D arrays, the 1st column is checked
&apos;&apos;&apos;			0 =&gt; all items must be any out of next types: string, date or numeric,
&apos;&apos;&apos;					but homogeneously: all strings or all dates or all numeric
&apos;&apos;&apos;			V_STRING or V_DATE or V_NUMERIC =&gt; that specific type is required
&apos;&apos;&apos;		pbNotNull: piType must be &gt;=0, otherwise ignored
&apos;&apos;&apos;			If True: Empty, Null items are rejected
&apos;&apos;&apos;	Return: True if validation OK
&apos;&apos;&apos;			Otherwise an error is raised
&apos;&apos;&apos;	Exceptions:
&apos;&apos;&apos;		ARRAYERROR

Dim iVarType As Integer			&apos;	VarType of argument
Dim vItem As Variant			&apos;	Array item
Dim iItemType As Integer		&apos;	VarType of individual items of argument
Dim iDims As Integer			&apos;	Number of dimensions of the argument
Dim bValid As Boolean			&apos;	Returned value
Dim iArrayType As Integer		&apos;	Static array type
Dim iFirstItemType As Integer	&apos;	Type of 1st non-null/empty item
Dim sType As String				&apos;	Allowed item types as a string
Dim i As Long
Const cstMaxLength = 256		&apos;	Maximum length of readable value

	&apos;	To avoid useless recursions, keep main function, only increase stack depth

	_SF_.StackLevel = _SF_.StackLevel + 1
	On Local Error GoTo Finally		&apos;	Do never interrupt

Try:
	bValid = True
	If IsMissing(pvArray) Then GoTo CatchMissing
	If IsMissing(piDimensions) Then piDimensions = 0
	If IsMissing(piType) Then piType = -1
	If IsMissing(pbNotNull) Then pbNotNull = False
	iVarType = VarType(pvArray)

	&apos;	Scalars NEVER pass validation
	If iVarType &lt; V_ARRAY Then
		bValid = False
	Else
		&apos;	Check dimensions
		iDims = SF_Array.CountDims(pvArray)
		If iDims &gt; 2 Then bValid = False		&apos;	Only 1D and 2D arrays
		If bValid And piDimensions &gt; 0 Then
			bValid = ( iDims = piDimensions Or (iDims = 0 And piDimensions = 1) )	&apos;	Allow empty vectors
		End If
		&apos;	Check VarType and Empty/Null status of the array items
		If bValid And iDims = 1 And piType &gt;= 0 Then
			iArrayType = SF_Array._StaticType(pvArray)
			If (piType = 0 And iArrayType &gt; 0) Or (piType &gt; 0 And iArrayType = piType) Then
				&apos;	If static array of the right VarType ..., OK
			Else
				&apos;	Go through array and check individual items
				iFirstItemType = -1
				For i = LBound(pvArray, 1) To UBound(pvArray, 1)
					If iDims = 1 Then vItem = pvArray(i) Else vItem = pvArray(i, LBound(pvArray, 2))
					iItemType = SF_Utils._VarTypeExt(vItem)
					If iItemType &gt; V_NULL Then	&apos;	Exclude Empty and Null
						&apos;	Initialization at first non-null item
						If iFirstItemType &lt; 0 Then
							iFirstItemType = iItemType
							If piType &gt; 0 Then bValid = ( iFirstItemType = piType ) Else bValid = SF_Array.Contains(Array(V_STRING, V_DATE, V_NUMERIC), iFirstItemType)
						Else
							bValid = (iItemType = iFirstItemType)
						End If
					Else
						bValid = Not pbNotNull
					End If
					If Not bValid Then Exit For
				Next i
			End If
		End If
	End If

	If Not bValid Then
		&apos;&apos;&apos;	Library:	ScriptForge
		&apos;&apos;&apos;	Service:	Array
		&apos;&apos;&apos;	Method:		Contains
		&apos;&apos;&apos;	Arguments:	Array_1D, ToFind, [CaseSensitive=False], [SortOrder=&quot;&quot;|&quot;ASC&quot;|&quot;DESC&quot;]
		&apos;&apos;&apos;	An error was detected on argument Array_1D
		&apos;&apos;&apos;		Rules:	Array_1D is of type Array
		&apos;&apos;&apos;				Array_1D must have maximum 1 dimension
		&apos;&apos;&apos;				Array_1D must have all elements of the same type: either String, Date or Numeric
		&apos;&apos;&apos;		Actual value: (0:2, 0:3)
		sType = &quot;&quot;
		If piType = 0 Then
			sType = &quot;String, Date, Numeric&quot;
		ElseIf piType &gt; 0 Then
			sType = SF_Utils._TypeNames(piType)
		End If
		SF_Exception.RaiseFatal(ARRAYERROR _
				, SF_Utils._Repr(pvArray, cstMaxLength), psName, piDimensions, sType, pbNotNull)
	End If

Finally:
	_ValidateArray = bValid
	_SF_.StackLevel = _SF_.StackLevel - 1
	Exit Function
CatchMissing:
	bValid = False
	SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
	GoTo Finally
End Function	&apos;	ScriptForge.SF_Utils._ValidateArray

REM -----------------------------------------------------------------------------
Public Function _ValidateFile(Optional ByRef pvArgument As Variant _
								, ByVal psName As String _
								, Optional ByVal pbWildCards As Boolean _
								, Optional ByVal pbSpace As Boolean _
								)
&apos;&apos;&apos; Validate the argument as a valid FileName
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvArgument: the argument to (in)validate
&apos;&apos;&apos;		pbWildCards: if True, wildcard characters are accepted in the last component of the 1st argument
&apos;&apos;&apos;		pbSpace: if True, the argument may be an empty string. Default = False
&apos;&apos;&apos;	Return: True if validation OK
&apos;&apos;&apos;			Otherwise an error is raised
&apos;&apos;&apos;	Exceptions:
&apos;&apos;&apos;		ARGUMENTERROR

Dim iVarType As Integer		&apos;	VarType of argument
Dim sFile As String			&apos;	Alias for argument
Dim bValid As Boolean		&apos;	Returned value
Dim sFileNaming As String	&apos;	Alias of SF_FileSystem.FileNaming
Dim oArgument As Variant	&apos;	Workaround &quot;Object variable not set&quot; error on 1st executable statement
Const cstMaxLength = 256	&apos;	Maximum length of readable value
Const DOCFILESYSTEM = &quot;vnd.sun.star.tdoc:/&quot;

	&apos;	To avoid useless recursions, keep main function, only increase stack depth

	_SF_.StackLevel = _SF_.StackLevel + 1
	On Local Error GoTo Finally		&apos;	Do never interrupt

Try:
	bValid = True
	If IsMissing(pvArgument) Then GoTo CatchMissing
	If IsMissing(pbWildCards) Then pbWildCards = False
	If IsMissing(pbSpace) Then pbSpace = False
	iVarType = VarType(pvArgument)

	&apos;	Arrays NEVER pass validation
	If iVarType &gt;= V_ARRAY Then
		bValid = False
	Else
		&apos;	Argument must be a string containing a valid file name
		bValid = ( iVarType = V_STRING )
		If bValid Then
			bValid = ( Len(pvArgument) &gt; 0 Or pbSpace )
			If bValid And Len(pvArgument) &gt; 0 Then
				&apos;	 Wildcards are replaced by arbitrary alpha characters
				If pbWildCards Then
					sFile = Replace(Replace(pvArgument, &quot;?&quot;, &quot;Z&quot;), &quot;*&quot;, &quot;A&quot;)
				Else
					sFile = pvArgument
					bValid = ( InStr(sFile, &quot;?&quot;) + InStr(sFile, &quot;*&quot;) = 0 )
				End If
				&apos;	Check file format without wildcards
				If bValid Then
					With SF_FileSystem
						sFileNaming = .FileNaming
						If SF_String.StartsWith(sFile, DOCFILESYSTEM) Then sFileNaming = &quot;URL&quot;
						Select Case sFileNaming
							Case &quot;ANY&quot;	:	bValid = SF_String.IsUrl(ConvertToUrl(sFile))
							Case &quot;URL&quot;	:	bValid = SF_String.IsUrl(sFile)
							Case &quot;SYS&quot;	:	bValid = SF_String.IsFileName(sFile)
						End Select
					End With
				End If
				&apos;	Check that wildcards are only present in last component
				If bValid And pbWildCards Then
					sFile = SF_FileSystem.GetParentFolderName(pvArgument)
					bValid = ( InStr(sFile, &quot;*&quot;) + InStr(sFile, &quot;?&quot;) + InStr(sFile,&quot;%3F&quot;) = 0 )	&apos;	ConvertToUrl replaces ? by %3F
				End If
			End If
		End If
	End If

	If Not bValid Then
		&apos;&apos;&apos;	Library:	ScriptForge
		&apos;&apos;&apos;	Service:	FileSystem
		&apos;&apos;&apos;	Method:		CopyFile
		&apos;&apos;&apos;	Arguments:	Source, Destination
		&apos;&apos;&apos;	A serious error has been detected on argument Source
		&apos;&apos;&apos;		Rules:	Source is of type String
		&apos;&apos;&apos;				Source must be a valid file name expressed in operating system notation
		&apos;&apos;&apos;				Source may contain one or more wildcard characters in its last component
		&apos;&apos;&apos;		Actual value:	/home/jean-*/SomeFile.odt
		SF_Exception.RaiseFatal(FILEERROR _
				, SF_Utils._Repr(pvArgument, cstMaxLength), psName, pbWildCards)
	End If

Finally:
	_ValidateFile = bValid
	_SF_.StackLevel = _SF_.StackLevel - 1
	Exit Function
CatchMissing:
	bValid = False
	SF_Exception.RaiseFatal(MISSINGARGERROR, psName)
	GoTo Finally
End Function	&apos;	ScriptForge.SF_Utils._ValidateFile

REM -----------------------------------------------------------------------------
Public Function _VarTypeExt(ByRef pvValue As Variant) As Integer
&apos;&apos;&apos;	Return the VarType of the argument but all numeric types are aggregated into V_NUMERIC
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pvValue: value to examine
&apos;&apos;&apos;	Return:
&apos;&apos;&apos;		The extended VarType

Dim iType As Integer	&apos;	VarType of argument

	iType = VarType(pvValue)
	Select Case iType
		Case V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE, V_CURRENCY, V_BIGINT, V_DECIMAL
			_VarTypeExt = V_NUMERIC
		Case Else	:	_VarTypeExt = iType
	End Select

End Function	&apos;	ScriptForge.SF_Utils._VarTypeExt

REM -----------------------------------------------------------------------------
Public Function _VarTypeObj(ByRef pvValue As Variant) As Object
&apos;&apos;&apos;	Inspect the argument that is supposed to be an Object
&apos;&apos;&apos;	Return the internal type of object as one of the values
&apos;&apos;&apos;		V_NOTHING		Null object
&apos;&apos;&apos;		V_UNOOBJECT		Uno object or Uno structure
&apos;&apos;&apos;		V_SFOBJECT		ScriptForge object: has ObjectType and ServiceName properties
&apos;&apos;&apos;		V_BASICOBJECT	User Basic object
&apos;&apos;&apos;	coupled with object type as a string (&quot;com.sun.star...&quot; or &quot;SF_...&quot; or &quot;... ScriptForge class ...&quot;)
&apos;&apos;&apos;	When the argument is not an Object, return the usual VarType() of the argument

Dim oObjDesc As _ObjectDescriptor	&apos;	Return value
Dim oValue As Object				&apos;	Alias of pvValue used to avoid &quot;Object variable not set&quot; error
Dim sObjType As String				&apos;	The type of object is first derived as a string
Dim oReflection As Object			&apos;	com.sun.star.reflection.CoreReflection
Dim vClass As Variant				&apos;	com.sun.star.reflection.XIdlClass
Dim bUno As Boolean					&apos;	True when object recognized as UNO object

Const cstBasicClass = &quot;com.sun.star.script.NativeObjectWrapper&quot;		&apos;	Way to recognize Basic objects

	On Local Error Resume Next	&apos;	Object type is established by trial and error

Try:
	With oObjDesc
		.iVarType = VarType(pvValue)
		.sObjectType = &quot;&quot;
		.sServiceName = &quot;&quot;
		bUno = False
		If .iVarType = V_OBJECT Then
			If IsNull(pvValue) Then
				.iVarType = V_NOTHING
			Else
				Set oValue = pvValue
				&apos;	Try UNO type with usual ImplementationName property
				.sObjectType = oValue.getImplementationName()
				If .sObjectType = &quot;&quot; Then
					&apos;	Try UNO type with alternative CoreReflection trick
					Set oReflection = SF_Utils._GetUNOService(&quot;CoreReflection&quot;)
					vClass = oReflection.getType(oValue)
					If vClass.TypeClass &gt;= com.sun.star.uno.TypeClass.STRUCT  Then
						.sObjectType = vClass.Name
						bUno = True
					End If
				Else
					bUno = True
				End If
				&apos;	Identify Basic objects
				If .sObjectType = cstBasicClass Then
					bUno = False
					&apos;	Try if the Basic object has an ObjectType property
					.sObjectType = oValue.ObjectType
					.sServiceName = oValue.ServiceName
				End If
				&apos;	Derive the return value from the object type
				Select Case True
					Case Len(.sObjectType) = 0			&apos;	Do nothing (return V_OBJECT)
					Case .sObjectType = cstBasicClass	:	.iVarType = V_BASICOBJECT
					Case bUno							:	.iVarType = V_UNOOBJECT
					Case Else							:	.iVarType = V_SFOBJECT
				End Select
			End If
		End If
	End With

Finally:
	Set _VarTypeObj = oObjDesc
	Exit Function
End Function	&apos;	ScriptForge.SF_Utils._VarTypeObj

REM ================================================= END OF SCRIPTFORGE.SF_UTILS
</script:module>