summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wizards/source/scriptforge/SF_Exception.xba95
-rw-r--r--wizards/source/scriptforge/SF_PythonHelper.xba14
-rw-r--r--wizards/source/scriptforge/SF_Root.xba7
-rw-r--r--wizards/source/scriptforge/po/ScriptForge.pot6
-rw-r--r--wizards/source/scriptforge/po/en.po6
5 files changed, 111 insertions, 17 deletions
diff --git a/wizards/source/scriptforge/SF_Exception.xba b/wizards/source/scriptforge/SF_Exception.xba
index 9b26466aa818..fd108e14f9ac 100644
--- a/wizards/source/scriptforge/SF_Exception.xba
+++ b/wizards/source/scriptforge/SF_Exception.xba
@@ -716,7 +716,7 @@ Try:
vLocation = Split(_SF_.MainFunction, ".")
If UBound(vLocation) < 2 Then vLocation = SF_Array.Prepend(vLocation, "ScriptForge")
sLocation = L10N.GetText("VALIDATESOURCE", vLocation(0), vLocation(1), vLocation(2)) _
- & "\n" & L10N.GetText("VALIDATEARGS", _SF_.MainFunctionArgs)
+ & "\n" & L10N.GetText("VALIDATEARGS", _RightCaseArgs(_SF_.MainFunctionArgs))
Else
sLocation = ""
End If
@@ -724,10 +724,12 @@ Try:
With L10N
Select Case UCase(ErrorCode)
Case MISSINGARGERROR ' SF_Utils._Validate(Name)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("VALIDATEMISSING", pvArgs(0))
Case ARGUMENTERROR ' SF_Utils._Validate(Value, Name, Types, Values, Regex, Class)
+ pvArgs(1) = _RightCase(pvArgs(1))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(1)) _
& "\n" & "\n" & .GetText("VALIDATIONRULES")
@@ -737,6 +739,7 @@ Try:
If Len(pvArgs(5)) > 0 Then sMessage = sMessage & "\n" & .GetText("VALIDATECLASS", pvArgs(1), pvArgs(5))
sMessage = sMessage & "\n" & "\n" & .GetText("VALIDATEACTUAL", pvArgs(1), pvArgs(0))
Case ARRAYERROR ' SF_Utils._ValidateArray(Value, Name, Dimensions, Types, NotNull)
+ pvArgs(1) = _RightCase(pvArgs(1))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(1)) _
& "\n" & "\n" & .GetText("VALIDATIONRULES") _
@@ -746,6 +749,7 @@ Try:
If pvArgs(4) Then sMessage = sMessage & "\n" & .GetText("VALIDATENOTNULL", pvArgs(1))
sMessage = sMessage & "\n" & "\n" & .GetText("VALIDATEACTUAL", pvArgs(1), pvArgs(0))
Case FILEERROR ' SF_Utils._ValidateFile(Value, Name, WildCards)
+ pvArgs(1) = _RightCase(pvArgs(1))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(1)) _
& "\n" & "\n" & .GetText("VALIDATIONRULES") _
@@ -782,57 +786,70 @@ Try:
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("INVALIDKEY")
Case UNKNOWNFILEERROR ' SF_FileSystem.CopyFile/MoveFile/DeleteFile/CreateScriptService("L10N")(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("UNKNOWNFILE", pvArgs(0), pvArgs(1))
Case UNKNOWNFOLDERERROR ' SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("UNKNOWNFOLDER", pvArgs(0), pvArgs(1))
Case NOTAFILEERROR ' SF_FileSystem.CopyFile/MoveFile/DeleteFile(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("NOTAFILE", pvArgs(0), pvArgs(1))
Case NOTAFOLDERERROR ' SF_FileSystem.CopyFolder/MoveFolder/DeleteFolder/Files/SubFolders(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("NOTAFOLDER", pvArgs(0), pvArgs(1))
Case OVERWRITEERROR ' SF_FileSystem.Copy+Move/File+Folder/CreateTextFile/OpenTextFile(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("OVERWRITE", pvArgs(0), pvArgs(1))
Case READONLYERROR ' SF_FileSystem.Copy+Move+Delete/File+Folder(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("READONLY", pvArgs(0), pvArgs(1))
Case NOFILEMATCHERROR ' SF_FileSystem.Copy+Move+Delete/File+Folder(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("NOFILEMATCH", pvArgs(0), pvArgs(1))
Case FOLDERCREATIONERROR ' SF_FileSystem.CreateFolder(ArgName, Filename)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("FOLDERCREATION", pvArgs(0), pvArgs(1))
Case UNKNOWNSERVICEERROR ' SF_Services.CreateScriptService(ArgName, Value, Library, Service)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("UNKNOWNSERVICE", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
Case SERVICESNOTLOADEDERROR ' SF_Services.CreateScriptService(ArgName, Value, Library)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("SERVICESNOTLOADED", pvArgs(0), pvArgs(1), pvArgs(2))
Case CALCFUNCERROR ' SF_Session.ExecuteCalcFunction(CalcFunction)
sMessage = sLocation _
- & "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", "CalcFunction") _
+ & "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", _RightCase("CalcFunction")) _
& "\n" & "\n" & .GetText("CALCFUNC", pvArgs(0))
Case NOSCRIPTERROR ' SF_Session._GetScript(Language, "Scope", Scope, "Script", Script)
+ pvArgs(1) = _RightCase(pvArgs(1)) : pvArgs(3) = _RightCase(pvArgs(3))
sMessage = sLocation _
- & "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", "Script") _
+ & "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", _RightCase("Script")) _
& "\n" & "\n" & .GetText("NOSCRIPT", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4))
Case SCRIPTEXECERROR ' SF_Session.ExecuteBasicScript("Script", Script, Cause)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & .GetText("SCRIPTEXEC", pvArgs(0), pvArgs(1), pvArgs(2))
Case WRONGEMAILERROR ' SF_Session.SendMail(Arg, Email)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("WRONGEMAIL", pvArgs(1))
@@ -849,42 +866,54 @@ Try:
sMessage = sLocation _
& "\n" & "\n" & .GetText("ENDOFFILE", pvArgs(0))
Case DOCUMENTERROR ' SF_UI.GetDocument(ArgName, WindowName)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("DOCUMENT", pvArgs(0), pvArgs(1))
Case DOCUMENTCREATIONERROR ' SF_UI.Create(Arg1Name, DocumentType, Arg2Name, TemplateFile)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
sMessage = sLocation _
& "\n" & "\n" & .GetText("DOCUMENTCREATION", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
Case DOCUMENTOPENERROR ' SF_UI.OpenDocument(Arg1Name, FileName, Arg2Name, Password, Arg3Name, FilterName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
sMessage = sLocation _
& "\n" & "\n" & .GetText("DOCUMENTOPEN", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4), pvArgs(5))
Case BASEDOCUMENTOPENERROR ' SF_UI.OpenBaseDocument(Arg1Name, FileName, Arg2Name, RegistrationName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
sMessage = sLocation _
& "\n" & "\n" & .GetText("BASEDOCUMENTOPEN", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
Case DOCUMENTDEADERROR ' SF_Document._IsStillAlive(FileName)
sMessage = sLocation _
& "\n" & "\n" & .GetText("DOCUMENTDEAD", pvArgs(0))
Case DOCUMENTSAVEERROR ' SF_Document.Save(Arg1Name, FileName)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & .GetText("DOCUMENTSAVE", pvArgs(0), pvArgs(1))
Case DOCUMENTSAVEASERROR ' SF_Document.SaveAs(Arg1Name, FileName, Arg2, Overwrite, Arg3, FilterName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
sMessage = sLocation _
& "\n" & "\n" & .GetText("DOCUMENTSAVEAS", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4), pvArgs(5))
Case DOCUMENTREADONLYERROR ' SF_Document.update property("Document", FileName)
+ pvArgs(0) = _RightCase(pvArgs(0))
sMessage = sLocation _
& "\n" & "\n" & .GetText("DOCUMENTREADONLY", pvArgs(0), pvArgs(1))
Case DBCONNECTERROR ' SF_Base.GetDatabase("User", User, "Password", Password, FileName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
sMessage = sLocation _
& "\n" & "\n" & .GetText("DBCONNECT", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4))
Case CALCADDRESSERROR ' SF_Calc._ParseAddress(Address, "Range"/"Sheet", Scope, Document)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("CALCADDRESS" & Iif(pvArgs(0) = "Sheet", "1", "2"), pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
Case DUPLICATESHEETERROR ' SF_Calc.InsertSheet(arg, SheetName, Document)
+ pvArgs(0) = _RightCase(pvArgs(2)) : pvArgs(0) = _RightCase(pvArgs(2))
sMessage = sLocation _
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
& "\n" & "\n" & .GetText("DUPLICATESHEET", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
- Case OFFSETADDRESSERROR ' SF_Calc.RangeOffset("range", Range, "Rows", Rows, "Columns", Columns, "Height", Height, "Width", Width, "Document, Document)
+ Case OFFSETADDRESSERROR ' SF_Calc.RangeOffset("Range", Range, "Rows", Rows, "Columns", Columns, "Height", Height, "Width", Width, "Document, Document)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
+ pvArgs(6) = _RightCase(pvArgs(6)) : pvArgs(8) = _RightCase(pvArgs(8)) : pvArgs(10) = _RightCase(pvArgs(10))
sMessage = sLocation _
& "\n" & "\n" & .GetText("OFFSETADDRESS", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4) _
, pvArgs(5), pvArgs(6), pvArgs(7), pvArgs(8), pvArgs(9), pvArgs(10), pvArgs(11))
@@ -907,6 +936,8 @@ Try:
sMessage = sLocation _
& "\n" & "\n" & .GetText("FORMCONTROLTYPE", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
Case DIALOGNOTFOUNDERROR ' SF_Dialog._NewDialog(Service, DialogName, WindowName)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2)) : pvArgs(4) = _RightCase(pvArgs(4))
+ pvArgs(6) = _RightCase(pvArgs(6))
sMessage = sLocation _
& "\n" & "\n" & .GetText("DIALOGNOTFOUND", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3), pvArgs(4) _
, pvArgs(5), pvArgs(6), pvArgs(7))
@@ -1188,5 +1219,61 @@ Private Function _Repr() As String
End Function ' ScriptForge.SF_Exception._Repr
+REM -----------------------------------------------------------------------------
+Private Function _RightCase(psString As String) As String
+''' Return the input argument in lower case only when the procedure in execution
+''' has been triggered from a Python script
+''' Indeed, Python requires lower case arguments
+''' Args:
+''' psString: probably an identifier in ProperCase
+''' Return:
+''' The input argument in lower case or left unchanged depending on the execution context
+
+Try:
+ If _SF_.TriggeredByPython Then _RightCase = LCase(psString) Else _RightCase = psString
+
+Finally:
+ Exit Function
+End Function ' ScriptForge.SF_Exception._RightCase
+
+REM -----------------------------------------------------------------------------
+Private Function _RightCaseArgs(psString As String) As String
+''' Return the input argument unchanged when the execution context is Basic
+''' When it is Python, the argument names are lowercased.
+''' Args:
+''' psString: one of the cstSubArgs strings located in each official method
+''' Return:
+''' The input string in which the argument names are put in lower case when called from Python scripts
+
+Dim sSubArgs As String ' Return value
+Dim vArgs As Variant ' Input string split on the comma character
+Dim sSingleArg As String ' Single vArgs item
+Dim vSingleArgs As Variant ' vSingleArg split on equal sign
+Dim i As Integer
+
+Const cstComma = ","
+Const cstEqual = "="
+
+Try:
+ If Len(psString) = 0 Then
+ sSubArgs = ""
+ ElseIf _SF_.TriggeredByPython Then
+ vArgs = SF_String.SplitNotQuoted(psString, cstComma, QuoteChar := """")
+ For i = 0 To UBound(vArgs)
+ sSingleArg = vArgs(i)
+ vSingleArgs = Split(sSingleArg, cstEqual)
+ vSingleArgs(0) = LCase(vSingleArgs(0))
+ vArgs(i) = join(vSingleArgs, cstEqual)
+ Next i
+ sSubArgs = Join(vArgs, cstComma)
+ Else
+ sSubArgs = psString
+ End If
+
+Finally:
+ _RightCaseArgs = sSubArgs
+ Exit Function
+End Function ' ScriptForge.SF_Exception._RightCaseArgs
+
REM ============================================ END OF SCRIPTFORGE.SF_EXCEPTION
</script:module> \ No newline at end of file
diff --git a/wizards/source/scriptforge/SF_PythonHelper.xba b/wizards/source/scriptforge/SF_PythonHelper.xba
index 931a37adb3c4..2addd1eca678 100644
--- a/wizards/source/scriptforge/SF_PythonHelper.xba
+++ b/wizards/source/scriptforge/SF_PythonHelper.xba
@@ -675,11 +675,14 @@ Try:
&apos; may be considered as properties when no argument
&apos; Requires Python and Basic update in the concerned library but is transparent for this dispatcher
- &apos; Initialize Python persistent storage at 1st call
-
- If IsEmpty(_SF_.PythonStorage) Then _SF_._InitPythonStorage()
- &apos; Reset any error
- _SF_._Stackreset()
+ With _SF_
+ &apos; Initialize Python persistent storage at 1st call
+ If IsEmpty(.PythonStorage) Then ._InitPythonStorage()
+ &apos; Reset any error
+ ._Stackreset()
+ &apos; Set Python trigger to manage signatures in error messages
+ .TriggeredByPython = True
+ End With
Select case VarType(BasicObject)
Case V_STRING
@@ -865,6 +868,7 @@ Try:
_PythonDispatcher = vReturnArray
Finally:
+ _SF_.TriggeredByPython = False &apos; Reset normal state
Exit Function
Catch:
GoTo Finally
diff --git a/wizards/source/scriptforge/SF_Root.xba b/wizards/source/scriptforge/SF_Root.xba
index 0a5aaa6055ab..f553ab5f5889 100644
--- a/wizards/source/scriptforge/SF_Root.xba
+++ b/wizards/source/scriptforge/SF_Root.xba
@@ -36,6 +36,7 @@ Private ConsoleDialog As Object &apos; SFDialogs.Dialog object
Private ConsoleControl As Object &apos; SFDialogs.DialogControl object
Private DisplayEnabled As Boolean &apos; When True, display of console or error messages is allowed
Private StopWhenError As Boolean &apos; When True, process stops after error &gt; &quot;WARNING&quot;
+Private TriggeredByPython As Boolean &apos; When True, the actual user script is a Python script
Private DebugMode As Boolean &apos; When True, log enter/exit each official Sub
&apos; Progress and status bars
@@ -98,6 +99,7 @@ Private Sub Class_Initialize()
Set ConsoleControl = Nothing
DisplayEnabled = True
StopWhenError = True
+ TriggeredByPython = False
DebugMode = False
Set ProgressBarDialog = Nothing
Set ProgressBarText = Nothing
@@ -605,8 +607,8 @@ Try:
&amp; &quot;%1: &apos;Basic&apos; or &apos;Python&apos;\n&quot; _
&amp; &quot;%2: An identifier\n&quot; _
&amp; &quot;%3: A string\n&quot; _
- &amp; &quot;%2: An identifier\n&quot; _
- &amp; &quot;%3: A string&quot; _
+ &amp; &quot;%4: An identifier\n&quot; _
+ &amp; &quot;%5: A string&quot; _
)
&apos; SF_Session.ExecuteBasicScript
.AddText( Context := &quot;SCRIPTEXEC&quot; _
@@ -971,6 +973,7 @@ Public Sub _StackReset()
MainFunction = &quot;&quot;
MainFunctionArgs = &quot;&quot;
StackLevel = 0
+ TriggeredByPython = False
End Sub &apos; ScriptForge.SF_Root._StackReset
diff --git a/wizards/source/scriptforge/po/ScriptForge.pot b/wizards/source/scriptforge/po/ScriptForge.pot
index dac8660fa867..5bb44f2d1d6e 100644
--- a/wizards/source/scriptforge/po/ScriptForge.pot
+++ b/wizards/source/scriptforge/po/ScriptForge.pot
@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
-"POT-Creation-Date: 2021-06-15 16:52:08\n"
+"POT-Creation-Date: 2021-06-19 16:57:15\n"
"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
@@ -451,8 +451,8 @@ msgstr ""
#. %1: 'Basic' or 'Python'
#. %2: An identifier
#. %3: A string
-#. %2: An identifier
-#. %3: A string
+#. %4: An identifier
+#. %5: A string
#, kde-format
msgctxt "NOSCRIPT"
msgid ""
diff --git a/wizards/source/scriptforge/po/en.po b/wizards/source/scriptforge/po/en.po
index dac8660fa867..5bb44f2d1d6e 100644
--- a/wizards/source/scriptforge/po/en.po
+++ b/wizards/source/scriptforge/po/en.po
@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
-"POT-Creation-Date: 2021-06-15 16:52:08\n"
+"POT-Creation-Date: 2021-06-19 16:57:15\n"
"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
@@ -451,8 +451,8 @@ msgstr ""
#. %1: 'Basic' or 'Python'
#. %2: An identifier
#. %3: A string
-#. %2: An identifier
-#. %3: A string
+#. %4: An identifier
+#. %5: A string
#, kde-format
msgctxt "NOSCRIPT"
msgid ""