Jump to content

Recommended Posts

Posted (edited)

I divide the project into parts for easier management.

The project is in early beta stage, for research and development.  🚀

 

AI_Assistant.au3

which is included in SciTE_AI_Assistant.au3, but can also be used as a standalone UDF

in which I #include "StringSize.au3" ; "https://www.autoitscript.com/forum/topic/114034-stringsize-m23-bugfix-version-27-dec-23"  by  Melba23  -  thanks for that
So that it folds the console output, and is visible within its boundaries (especially when it is on the side and is slim)  for more comfortable reading

works directly with the ollama. I use a small models  qwen2.5-coder:3b  as default, llama3.2:3b ,  phi4-mini:3.8b  so that I don't have to wait too long for a response.
However, I have set as a parameter which model it calls, so that it changes the model per job if necessary

I added a new function: _AI_Request which asynchronously sends a request to _AI_Call() and waits for the response.

I also added a new parameter $iThink -  Enable or disable thinking if Model supporting (0=none, 1=yes/not visible, 2=yes/visible). (Default is 0)
to conform with the new ability to enable or disable thinking.  (feature since version 0.9.0)

Ollama now has the ability to enable or disable thinking. This gives users the flexibility to choose the model’s thinking behavior for different applications and use cases.
When thinking is enabled, the output will separate the model’s thinking from the model’s output. When thinking is disabled, the model will not think and directly output the content.

Models that support thinking:


AI_Assistant\Example\Example2.au3  -  thinking example

#include "..\AI_Assistant.au3"

_AI_DebugInfo(True)

Example2()

Func Example2()

    Local $sPrompt = "how many r's are in strawberry?"
    Local $sModel = "qwen3:4b"

    ; _AI_Request with thinking Enable (0=none, 1=yes/not visible, 2=yes/visible)
    Local $sResponse = _AI_Request($sPrompt, $sModel, Default, 1, 2)
    ConsoleWrite($sResponse & @CRLF & @CRLF)

EndFunc

Output:

Thinking...

Okay, so the user is asking how many R's are in the word "strawberry". Let me think. First, I need to write out the word and check each letter. Let me spell it out: S-T-R-A-W-B-E-R-R-Y. Wait, let me make sure I have that right. Strawberry is S-T-R-A-W-B-E-R-R-Y. Let me break it down letter by letter.

S, T, R, A, W, B, E, R, R, Y. So that's 10 letters in total. Now, I need to count the number of R's. Let's go through each letter one by one. The first letter is S, not R. Second is T, no. Third is R—that's one. Fourth is A, no. Fifth is W, no. Sixth is B, no. Seventh is E, no. Eighth is R—that's two. Ninth is R—that's three. Tenth is Y, no. So that's three R's. Wait, let me check again to make sure I didn't miss any. S-T-R-A-W-B-E-R-R-Y. Yes, positions 3, 8, and 9 are R. So three R's in total. I think that's correct. Maybe I should write it out again to confirm. Strawberry: S T R A W B E R R Y. Yep, three R's. So the answer is 3.

...done thinking.

The word **"strawberry"** contains **3 R's**.  

Breaking it down:  
**S-T-R-A-W-B-E-R-R-Y**  
R's are in positions 3, 8, and 9.  

**Answer: 3** 🍓

 

SciTE_AI_Assistant.au3

I changed the approach, and made it as SciTE tool.
This way, the selection process, and console writing, is handled internally by SciTE.
To do this you need to add the following to SciTEUser.properties    (Adding_utilities_to_the_SciTE_Tools_menu)

#------------------------------------------------------------------------------
# 41 SciTE_AI_Assistant
command.41.$(au3)="$(SciteDefaultHome)\..\AutoIt3.exe" "D:\i\Pro\.AutoIT\SciTE_AI_Assistant\SciTE_AI_Assistant.au3"
command.subsystem.41.$(au3)=0
command.name.41.$(au3)=SciTE AI Assistant
command.shortcut.41.*.au3=F10
command.save.before.41.$(au3)=2
# command.replace.selection.41.$(au3)=1
# command.quiet.41.$(au3)=0
# command.input.41.$(au3)=$(CurrentSelection)
#------------------------------------------------------------------------------
#---------------------- Contex Menu -------------------------------------------
user.context.menu=\
||\
>>>  SciTE AI Assistant  <<< |1141|\
||\
Execute Selected Path|IDM_OPENSELECTED|\
#------------------------------------------------------------------------------

and make the necessary adjustments

e.g. in 
command.41.$(au3)="$(SciteDefaultHome)\..\AutoIt3.exe" "D:\i\Pro\.AutoIT\SciTE_AI_Assistant\SciTE_AI_Assistant.au3"

your path for the d:\your\location\SciTE_AI_Assistant\SciTE_AI_Assistant.au3

You may need to adjust the 41 to the first tool number available to you.

in this case, change the   >>>  SciTE AI Assistant  <<< |1141|\   as well in the Context Menu

 

After that, select the text in the SciTE, right-click and select  'instruction'  from the context menu '>>>  SciTE AI Assistant  <<<'
or hit F10

Clipboard_06-09-2025_01.pngClipboard_06-09-2025_03.png

output:

; #FUNCTION# ====================================================================================================================
; Name...........: IsMouseOverWin
; Description....: Determines if the mouse pointer is positioned over a specified window.
; Syntax.........: IsMouseOverWin($hWnd)
; Parameters.....: $hWnd - The handle of the window to check for mouse position.
; Return values .: Success: Returns True if the mouse is over the window, False otherwise.
;                  @error = 0: No error occurred.
; Author ........: ioa747
; Modified ......: 
; Remarks .......: This function uses MouseGetPos() to retrieve the current mouse position and WinGetPos($hWnd) to obtain
;                  the dimensions of the specified window. It checks if the mouse position falls within the boundaries of the window.
; Related .......: 
; Link ..........: 
; Example .......: 
; ===============================================================================================================================

 

FIM (Fill-in-the-Middle <??> )

when it comes to FIM (Fill-in-the-Middle <??> ), the '<??>' tag is to specify the-Middle
e.g. as in the example below,  highlight the text , right click , and select,   >>>  SciTE AI Assistant  <<< ,    FIM (Fill-in-the-Middle <??> )

Func SumNumbers($aNumbers)
    Local $iTotal = 0
        For $i = 0 To UBound($aNumbers) - 1
        <??>
        Next
    Return $iTotal
EndFunc

 

 

Prompt Builder GUI

250610-022819-090_AutoIt3_tL6Xs.png

The script described is an advanced AI prompt builder tool
The tool provides a user-friendly interface that allows users to create, manage, and execute AI prompts based on predefined
templates or customizable settings from .ini file.

macros in the Prompt Builder GUI
@Selection@  = the Selection of SciTE
@ScriptName@ = the Script Name (useful as title)
@ScriptFullPath@ = all the content of Script
@ClipGet@ = the content of Clipboard
@FileRead(FilePath)@ = the content of FilePath

 

 

self-introduction - ReadMe

Spoiler

Exploring SciTE AI Assistant: A Script for Enhanced Coding Experience

Introduction

The SciTE AI Assistant is a powerful script designed to enhance the coding experience within the SciTE editor. By leveraging AI capabilities, it provides developers with suggestions, code optimizations, and explanations, streamlining their workflow. This presentation explores the key functionalities of the SciTE AI Assistant and its integration with the AI Prompt Builder Script, which further enhances its capabilities.

Key Features of SciTE AI Assistant

  • Contextual Assistance: The assistant creates a context menu when right-clicking on any text in the SciTE editor, offering various AI-based options such as code comments, optimizations, and explanations.

  • Debugging Support: The _AI_DebugInfo(True) function enables debugging information, aiding developers during the debugging process.

  • Dynamic Content Handling: It retrieves the current selection or the entire file content, allowing for tailored suggestions based on the developer’s needs.

Functionality Overview

The SciTE AI Assistant operates through several key functions: - Code Optimization: It analyzes the selected code or entire file and provides suggestions for improvements. - Code Explanation: The assistant can explain complex code logic, making it easier for developers to understand and maintain their code. - Function Header Generation: It automatically generates function headers based on the selected code, saving time and ensuring consistency. - Filling-in-the-Middle (FIM) Comments: The assistant can insert comments in the code, enhancing readability and documentation.

Integration with AI Prompt Builder Script

The AI Prompt Builder Script complements the SciTE AI Assistant by providing a user-friendly interface for managing and executing AI prompts. Key features include:

  • User-Friendly GUI: The script offers a graphical interface for defining, saving, loading, and executing AI prompts tailored to various tasks.
  • Macro Processing: It processes special placeholders in prompts, ensuring that the AI model receives contextually relevant inputs.
  • Persistent Storage: The script manages INI files for storing saved prompts, allowing users to easily retrieve and utilize them.

Use Cases

The combined capabilities of the SciTE AI Assistant and the AI Prompt Builder Script can be applied in various scenarios: - Code Development: Developers can optimize their code and receive explanations, improving overall productivity. - Technical Support: Support teams can utilize the AI Prompt Builder to manage troubleshooting prompts efficiently. - Educational Tools: Educators can create interactive learning experiences, allowing students to engage with AI models in practical scenarios.

Conclusion

The SciTE AI Assistant, enhanced by the AI Prompt Builder Script, is an invaluable tool for developers. Its ability to provide AI-based assistance, optimize code, and manage prompts makes it a powerful addition to any developer’s toolkit. As technology evolves, these tools will continue to improve, further automating repetitive tasks and enhancing productivity in coding environments.

 

I will update the thread as soon as anything new comes up.
 

SciTE_AI_Assistant_0.12.zip


Please, every comment is appreciated!
leave your comments and experiences here!
Thank you very much  :)

 

 

Edited by ioa747
update to Version: 0.12

I know that I know nothing

Posted (edited)
... ...
Global $__g_OllamaAssistant_DefaultURL = "http://localhost:11434"

Func OllamaAssistant_DefaultURL($sStr = Default)
    If $sStr <> Default Then $__g_OllamaAssistant_DefaultURL = $sStr
    Return $__g_OllamaAssistant_DefaultURL
EndFunc

ConsoleWrite(Ollama_IsModelAvailable() & @CRLF)
If @error Then Exit 5

Func Ollama_IsModelAvailable($sStr = "qwen2.5-coder")
    Local $sRet = OllamaAPI() ; default is get models at default URL
    If @error Then
        ConsoleWrite("! Ollama is not running there  =(" & @CRLF)
        Return SetError(1, 0, "")
    EndIf
    If StringInStr($sRet, $sStr) Then Return $sRet
    ConsoleWrite(@CRLF & $sRet & @CRLF & "! the model was not found. Pull it !  =)" & @CRLF )
    Return SetError(2, 0, $sRet)
EndFunc

; "/api/tags" ; List models that are available locally.
; "/api/ps" ; List models that are currently loaded into memory.
; "/api/pull"  '{"model": "qwen2.5-coder:3b"}' ; well, pull the model
Func OllamaAPI($sAPI = "/api/tags", $sURL = $__g_OllamaAssistant_DefaultURL)
    Local $sStr = BinaryToString(InetRead($sURL & $sAPI))
    ; this is not the function I should use, but it works to present the idea

    Return SetError(@error, @extended, $sStr)
EndFunc ; ..you may need to retry at times ?, ..I don't have much experience with it to know much

ConsoleWrite('HotKeySet = ' & HotKeySet("{END}", "GenerateFunctionHeader") & @CRLF) ; * <--
... ...

Nice !.
I was thinking yesterday that "I don't wanna leave SciTE" in a child tantrum kind of childish voice :lol:

So, I highlighted a function, pressed the end key and got me a "1" in the console.
But I don't know if is all that is so, add a start and end line, like:

---- 8< ---- start
1
---- >8 ---- end

so I get some feedback.

Again, thanks for working on my wish :) 

Edited by argumentum
fixed OllamaAPI() default

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted (edited)
... ...
    If $oHttp.Status <> 200 Then
;~      MsgBox(0, "Error", "WinHttp request failed with status code: " & $oHttp.Status)
        FileWriteLine(StringTrimRight(@ScriptFullPath, 4) & ".log", 'Error: $oHttp.Status:' & $oHttp.Status & @CRLF)
... ...

Error: $oHttp.Status:400  :(
What does it mean ?


I pasted the question in open-webui ( ..not quite like that but I forgot what I did )

Spoiler
You are an AutoIt documentation assistant. Your task is to generate precise header comments for AutoIt functions, using the standard UDF format.
Now generate a header comment for the following function:
Func Ollama_IsModelAvailable($sStr = "qwen2.5-coder")
    Local $sRet = OllamaAPI() ; default is get models at default URL
    If @error Then
        ConsoleWrite("! Ollama is not running there  =(" & @CRLF)
        Return SetError(1, 0, "")
    EndIf
    If StringInStr($sRet, $sStr) Then Return $sRet
    ConsoleWrite(@CRLF & $sRet & @CRLF & "! the model was not found. Pull it !  =)" & @CRLF )
    Return SetError(2, 0, $sRet)
EndFunc

and returned it's answer:

Spoiler
qwen2.5-coder:latest
Today at 1:45 PM

Certainly! Below is a header comment for the Ollama_IsModelAvailable function in AutoIt using the standard UDF format:

; #FUNCTION# ===================================================================================================================
;
; Name...........: Ollama_IsModelAvailable
; Description....: Checks if an AI model specified by name is available.
; Syntax.........: $sStr = "qwen2.5-coder" (optional) - The name of the model to check.
; Parameters.....:
;   $sStr         - [optional] The name of the model to check. Default is "qwen2.5-coder".
;
; Return values  :
;               Success: Returns the available models if the specified model is found.
;               Failure: Sets @error and returns an empty string with a custom message.
;               @error = 1: Ollama is not running at the default URL.
;               @error = 2: The specified model was not found.
;
; Author.........: [Your Name]
; Remarks........: This function assumes that there is an API endpoint for checking available models.
;                  It uses the default URL if no other is provided.
;
; Related........:
; Link...........:
; Example........:
;
; #FUNCTION# ===================================================================================================================
Func Ollama_IsModelAvailable($sStr = "qwen2.5-coder")
    Local $sRet = OllamaAPI() ; default is get models at default URL
    If @error Then
        ConsoleWrite("! Ollama is not running there  =(" & @CRLF)
        Return SetError(1, 0, "")
    EndIf
    If StringInStr($sRet, $sStr) Then Return $sRet
    ConsoleWrite(@CRLF & $sRet & @CRLF & "! the model was not found. Pull it !  =)" & @CRLF )
    Return SetError(2, 0, $sRet)
EndFunc

This header comment follows the standard UDF format and includes:

  • The function name and its description.
  • Parameters and their descriptions.
  • Return values with error codes and custom messages.
  • Author and remarks (indicating that it assumes an API endpoint for checking available models).
  • Related functions, links, and examples if applicable.

 so, maybe sending the $sSystem and $sPrompt as a single string is better ?
( am just talking out of my ... imagination here )

Edited by argumentum
more

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
... ...
    $sRequest &= '"system": "' & $sSystem & '", '
    $sPrompt = StringReplace($sPrompt, @CRLF, "\r\n")
    $sPrompt = StringReplace($sPrompt, @TAB, "\t")
    $sPrompt = StringReplace($sPrompt, '"', "\""")
    $sRequest &= '"prompt": "' & $sPrompt & '", '
... ...

..it needed to escape stuff. All good :) 

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
7 minutes ago, argumentum said:

I understand you answer. But it only worked for me when I "man handle" the string 🤷‍♂️

Quote
#include "JSON.au3"   ;" https://www.autoitscript.com/forum/topic/209502-json-udf-in-pure-autoit/#comment-1511873 "

I went to the git and pulled the file from there. Maybe the version there is bad ?

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted (edited)

i have this

Spoiler

https://github.com/Sylvan86/autoit-json-udf

#include-once

; #INDEX# =======================================================================================================================
; Title .........: JSON-UDF
; Version .......: 0.10
; AutoIt Version : 3.3.16.1
; Language ......: english (german maybe by accident)
; Description ...: Function for interacting with JSON data in AutoIt.
;                  This includes import, export as well as helper functions for handling nested AutoIt data structures.
; Author(s) .....: AspirinJunkie, Sven Seyfert (SOLVE-SMART)
; Last changed ..: 2023-02-20
; Link ..........: https://autoit.de/thread/85435-json-udf/
; License .......: This work is free.
;                  You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2,
;                  as published by Sam Hocevar.
;                  See http://www.wtfpl.net/ for more details.
; ===============================================================================================================================

; #Function list# =======================================================================================================================
; ---- import and export from or to json ------
;  _JSON_Parse               - converts a JSON-structured string into a nested AutoIt data structure
;  _JSON_Generate            - converts a nested AutoIt data structure into a JSON structured string
;  _JSON_GenerateCompact     - shorthand for _JSON_Generate() to create JSON structured strings as compact as possible
;  _JSON_Unminify            - reads minified (compact) JSON file or string and converts to well readable JSON string
;  _JSON_Minify              - reads unminified (readable) JSON file or string and converts to minified (compact) JSON string
;
; ---- extraction and manipulation of nested AutoIt data structures ----
;  _JSON_Get                 - extract query nested AutoIt-datastructure with a simple selector string
;  _JSON_addChangeDelete     - create a nested AutoIt data structure, change values within existing structures or delete elements from a nested AutoIt data structure
;
; ---- helper functions ----
;      __JSON_FormatString   - converts a string into a json string by escaping the special symbols
;      __JSON_ParseString    - converts a json formatted string into an AutoIt-string by unescaping the json-escapes
;      __JSON_A2DToAinA      - converts a 2D array into a Arrays in Array
;      __JSON_AinAToA2d      - converts a Arrays in Array into a 2D array
;      __JSON_Base64Decode   - decode data which is coded as a base64-string into binary variable
;      __JSON_Base64Encode   - converts a binary- or string-Input into BASE64 (or optional base64url) format
; ===============================================================================================================================

#include <String.au3>

; #FUNCTION# ======================================================================================
; Name ..........: _JSON_Parse
; Description ...: convert a JSON-formatted string into a nested structure of AutoIt-datatypes
; Syntax ........: _JSON_Parse(ByRef $s_String, $i_Os = 1)
; Parameters ....: $s_String      - a string formatted as JSON
;                  [$i_Os]        - search position where to start (normally don't touch!)
; Return values .: Success - Return a nested structure of AutoIt-datatypes
;                       @extended = next string offset
;                  Failure - Return "" and set @error to:
;                       @error = 1 - part is not json-syntax
;                              = 2 - key name in object part is not json-syntax
;                              = 3 - value in object is not correct json
;                              = 4 - delimiter or object end expected but not gained
; Author ........: AspirinJunkie
; =================================================================================================
Func _JSON_Parse(ByRef $s_String, $i_Os = 1)
    Local $i_OsC = $i_Os, $o_Current, $o_Value
    ; Inside a character class, \R is treated as an unrecognized escape sequence, and so matches the letter "R" by default, but causes an error if
    Local Static _ ; '\s' = [\x20\x09\x0A\x0D]
            $s_RE_G_String = '\G\s*"([^"\\]*+(?>\\.[^"\\]*+)*+)"', _ ; old variant: '\G\s*"((?>[^\\"]+|\\.)*+)"' - new one is more efficient coz it searches firstly for non quotes and bs - these are more unlikely
            $s_RE_G_Number = '\G\s*(-?(?>0|[1-9]\d*)(?>\.\d+)?(?>[eE][-+]?\d+)?)', _
            $s_RE_G_KeyWord = '\G\s*\b(null|true|false)\b', _
            $s_RE_G_Object_Begin = '\G\s*\{', _
            $s_RE_G_Object_Key = '\G\s*"((?>[^\\"]+|\\.)*+)"\s*:', _
            $s_RE_G_Object_Further = '\G\s*,', _
            $s_RE_G_Object_End = '\G\s*\}', _
            $s_RE_G_Array_Begin = '\G\s*\[', _
            $s_RE_G_Array_End = '\G\s*\]'

    $o_Current = StringRegExp($s_String, $s_RE_G_String, 1, $i_Os) ; String
    If Not @error Then Return SetExtended(@extended, __JSON_ParseString($o_Current[0]))


    StringRegExp($s_String, $s_RE_G_Object_Begin, 1, $i_Os) ; Object
    If Not @error Then
        $i_OsC = @extended
        Local $s_Key, $a_T

        Local $o_Current[]

        StringRegExp($s_String, $s_RE_G_Object_End, 1, $i_OsC)     ; check for empty object
        If Not @error Then     ; empty object
            $i_OsC = @extended
        Else
            Do
                $a_T = StringRegExp($s_String, $s_RE_G_Object_Key, 1, $i_OsC)     ; key of element
                If @error Then Return SetError(2, $i_OsC, "")
                $i_OsC = @extended

                $s_Key = __JSON_ParseString($a_T[0])

                $o_Value = _JSON_Parse($s_String, $i_OsC)
                If @error Then Return SetError(3, $i_OsC, "")
                $i_OsC = @extended

                $o_Current[$s_Key] = $o_Value     ; add key:value to map

                StringRegExp($s_String, $s_RE_G_Object_Further, 1, $i_OsC)     ; more elements
                If Not @error Then
                    $i_OsC = @extended
                    ContinueLoop
                Else
                    StringRegExp($s_String, $s_RE_G_Object_End, 1, $i_OsC)     ; end of array
                    If Not @error Then
                        $i_OsC = @extended
                        ExitLoop
                    Else
                        Return SetError(4, $i_OsC, "")
                    EndIf
                EndIf
            Until False
        EndIf

        Return SetExtended($i_OsC, $o_Current)
    EndIf


    StringRegExp($s_String, $s_RE_G_Array_Begin, 1, $i_Os) ; Array
    If Not @error Then
        $i_OsC = @extended
        Local $o_Current[1], $d_N = 1, $i_C = 0

        StringRegExp($s_String, $s_RE_G_Array_End, 1, $i_OsC) ; check for empty array
        If Not @error Then ; empty array
            ReDim $o_Current[0]
            $i_OsC = @extended
            Return SetExtended($i_OsC, $o_Current)
        EndIf

        Do
            $o_Value = _JSON_Parse($s_String, $i_OsC)
            If @error Then Return SetError(3, $i_OsC, "")
            $i_OsC = @extended

            If $i_C = $d_N - 1 Then
                $d_N += $d_N  ; or *= 2
                ReDim $o_Current[$d_N]
            EndIf
            $o_Current[$i_C] = $o_Value
            $i_C += 1

            StringRegExp($s_String, $s_RE_G_Object_Further, 1, $i_OsC) ; more elements
            If Not @error Then
                $i_OsC = @extended
                ContinueLoop
            Else
                StringRegExp($s_String, $s_RE_G_Array_End, 1, $i_OsC) ; end of array
                If Not @error Then
                    $i_OsC = @extended
                    ExitLoop
                Else
                    Return SetError(5, $i_OsC, "")
                EndIf
            EndIf

        Until False

        If UBound($o_Current) <> $i_C Then ReDim $o_Current[$i_C]
        Return SetExtended($i_OsC, $o_Current)
    EndIf

    $o_Current = StringRegExp($s_String, $s_RE_G_Number, 1, $i_Os) ; Number
    If Not @error Then Return SetExtended(@extended, Number($o_Current[0]))

    $o_Current = StringRegExp($s_String, $s_RE_G_KeyWord, 1, $i_Os) ; KeyWord
    If Not @error Then Return SetExtended(@extended, Execute($o_Current[0])) ; $o_Current[0] = "null" ? Null : $o_Current[0] = "true" ? True : False)

    Return SetError(1, $i_OsC, "")
EndFunc   ;==>_JSON_Parse


; #FUNCTION# ======================================================================================
; Name ..........: _JSON_Generate
; Description ...: converts a nested AutoIt data structure into a JSON structured string
; Syntax ........: _JSON_Generate($o_Object, $s_ObjIndent = @TAB, $s_ObjDelEl = @CRLF, $s_ObjDelKey = " ", $s_ObjDelVal = "", $s_ArrIndent = @TAB, $s_ArrDelEl = @CRLF, $i_Level = 0)
; Parameters ....: $o_Object      - [nested] AutoIt data structure
;                  [$s_ObjIndent] - indent for object elements (only reasonable if $s_ObjDelEl contains a line skip
;                  [$s_ObjDelEl]  - delimiter between object elements
;                  [$s_ObjDelKey] - delimiter between keyname and ":" in object
;                  [$s_ObjDelVal] - delimiter between ":" and value in object
;                  [$s_ArrIndent] - indent for array elements (only reasonable if $s_ArrDelEl contains a line skip)
;                  [$s_ArrDelEl]  - delimiter between array elements
;                  [$i_Level]     - search position where to start (normally don't touch!)
; Return values .: Success - Return a JSON formatted string
;                  Failure - Return ""
; Author ........: AspirinJunkie
; =================================================================================================
Func _JSON_Generate($o_Object, $s_ObjIndent = @TAB, $s_ObjDelEl = @CRLF, $s_ObjDelKey = "", $s_ObjDelVal = " ", $s_ArrIndent = @TAB, $s_ArrDelEl = @CRLF, $i_Level = 0)
    Local Static $s_JSON_String
    If $i_Level = 0 Then $s_JSON_String = ""

    Switch VarGetType($o_Object)
        Case "String"
            __JSON_FormatString($o_Object)
            $s_JSON_String &= '"' & $o_Object & '"'
        Case "Int32", "Int64", "Float", "Double"
            $s_JSON_String &= String($o_Object)
        Case "Bool"
            $s_JSON_String &= StringLower($o_Object)
        Case "Keyword"
            If IsKeyword($o_Object) = 2 Then $s_JSON_String &= "null"
        Case "Binary"
            $s_JSON_String &= '"' & __JSON_Base64Encode($o_Object) & '"'
        Case "Array"
            If UBound($o_Object, 0) = 2 Then $o_Object = __JSON_A2DToAinA($o_Object)
            If UBound($o_Object) = 0 Then
                $s_JSON_String &= "[]"
            Else
                $s_JSON_String &= "[" & $s_ArrDelEl
                For $o_Value In $o_Object
                    $s_JSON_String &= _StringRepeat($s_ArrIndent, $i_Level + 1)
                    _JSON_Generate($o_Value, $s_ObjIndent, $s_ObjDelEl, $s_ObjDelKey, $s_ObjDelVal, $s_ArrIndent, $s_ArrDelEl, $i_Level + 1)

                    $s_JSON_String &= "," & $s_ArrDelEl
                Next
                $s_JSON_String = StringTrimRight($s_JSON_String, StringLen("," & $s_ArrDelEl)) & $s_ArrDelEl & _StringRepeat($s_ArrIndent, $i_Level) & "]"
            EndIf
        Case "Object"
            If ObjName($o_Object) = "Dictionary" Then
                Local $s_KeyTemp, $o_Value
                If $o_Object.Count() = 0 Then
                    $s_JSON_String &= "{}"
                Else
                    $s_JSON_String &= "{" & $s_ObjDelEl
                    For $s_Key In $o_Object.Keys
                        $s_KeyTemp = $s_Key
                        $o_Value = $o_Object($s_Key)
                        __JSON_FormatString($s_KeyTemp)

                        $s_JSON_String &= _StringRepeat($s_ObjIndent, $i_Level + 1) & '"' & $s_KeyTemp & '"' & $s_ObjDelKey & ':' & $s_ObjDelVal

                        _JSON_Generate($o_Value, $s_ObjIndent, $s_ObjDelEl, $s_ObjDelKey, $s_ObjDelVal, $s_ArrIndent, $s_ArrDelEl, $i_Level + 1)

                        $s_JSON_String &= "," & $s_ObjDelEl
                    Next
                    $s_JSON_String = StringTrimRight($s_JSON_String, StringLen("," & $s_ObjDelEl)) & $s_ObjDelEl & _StringRepeat($s_ObjIndent, $i_Level) & "}"
                EndIf
            EndIf
        Case "Map"
            Local $s_KeyTemp, $o_Value
            If UBound($o_Object) = 0 Then
                $s_JSON_String &= "{}"
            Else
                $s_JSON_String &= "{" & $s_ObjDelEl
                For $s_Key In MapKeys($o_Object)
                    $s_KeyTemp = $s_Key
                    $o_Value = $o_Object[$s_Key]
                    __JSON_FormatString($s_KeyTemp)

                    $s_JSON_String &= _StringRepeat($s_ObjIndent, $i_Level + 1) & '"' & $s_KeyTemp & '"' & $s_ObjDelKey & ':' & $s_ObjDelVal

                    _JSON_Generate($o_Value, $s_ObjIndent, $s_ObjDelEl, $s_ObjDelKey, $s_ObjDelVal, $s_ArrIndent, $s_ArrDelEl, $i_Level + 1)

                    $s_JSON_String &= "," & $s_ObjDelEl
                Next
                $s_JSON_String = StringTrimRight($s_JSON_String, StringLen("," & $s_ObjDelEl)) & $s_ObjDelEl & _StringRepeat($s_ObjIndent, $i_Level) & "}"
            EndIf
    EndSwitch

    If $i_Level = 0 Then
        Local $s_Temp = $s_JSON_String
        $s_JSON_String = ""
        Return $s_Temp
    EndIf
EndFunc   ;==>_JSON_Generate

; #FUNCTION# ====================================================================================================================
; Name ..........: _JSON_GenerateCompact
; Description ...: shorthand for _JSON_Generate()-parameters to produce a compact as possible JSON string
; Syntax ........: _JSON_GenerateCompact($o_Object)
; Parameters ....: $o_Object            - [nested] AutoIt data structure
; Return values .: Success - Return a JSON formatted string
;                  Failure - Return ""
; Author ........: AspirinJunkie
; Modified ......: 2023-05-23
; Related .......: _JSON_Generate
; ===============================================================================================================================
Func _JSON_GenerateCompact($o_Object)
    Return _JSON_Generate($o_Object, "", "", "", "", "", "")
EndFunc   ;==>_JSON_GenerateCompact

; #FUNCTION# ====================================================================================================================
; Name ..........: _JSON_Unminify
; Description ...: reads minified (compact) JSON file or string and converts to well readable JSON string
; Syntax ........: _JSON_Unminify($s_Input)
; Parameters ....: $s_Input - json file path/handle or json string
; Return values .: Success - Return a JSON formatted string
;                  Failure - Return "" and set @error to:
;                       @error = 1 - error during FileRead() - @extended = @error from FileRead()
;                              = 2 - no valid format for $s_Input
; Author ........: Sven Seyfert (SOLVE-SMART), AspirinJunkie
; Related .......: _JSON_Generate
; ===============================================================================================================================
Func _JSON_Unminify($s_Input)
    ; read file if $sInput = file name or file handle
    If FileExists($s_Input) Or IsInt($s_Input) Then $s_Input = FileRead($s_Input)
    If @error Then Return SetError(1, @error, False)
    If Not IsString($s_Input) Then Return SetError(2, 0, False)

    Local Const $o_Object = _JSON_Parse($s_Input)
    Return _JSON_Generate($o_Object)
EndFunc   ;==>_JSON_Unminify

; #FUNCTION# ====================================================================================================================
; Name ..........: _JSON_Minify
; Description ...: reads unminified (readable) JSON file or string and converts to minified (compact) JSON string
; Syntax ........: _JSON_Minify($s_Input)
; Parameters ....: $s_Input - json file path/handle or json string
; Return values .: Success - Return a JSON formatted string
;                  Failure - Return "" and set @error to:
;                       @error = 1 - error during FileRead() - @extended = @error from FileRead()
;                              = 2 - no valid format for $s_Input
; Author ........: Sven Seyfert (SOLVE-SMART), AspirinJunkie
; Related .......: _JSON_GenerateCompact
; ===============================================================================================================================
Func _JSON_Minify($s_Input)
    ; read file if $sInput = file name or file handle
    If FileExists($s_Input) Or IsInt($s_Input) Then $s_Input = FileRead($s_Input)
    If @error Then Return SetError(1, @error, False)
    If Not IsString($s_Input) Then Return SetError(2, 0, False)

    Local Const $o_Object = _JSON_Parse($s_Input)
    Return _JSON_GenerateCompact($o_Object)
EndFunc   ;==>_JSON_Minify

; #FUNCTION# ======================================================================================
; Name ..........: _JSON_Get
; Description ...: query nested AutoIt-datastructure with a simple query string with syntax:
;                  MapKey#1.MapKey#2.[ArrayIndex#1].MapKey#3... (points keynames can be achieved by "\.")
;                  multidimensional (2D or 3D only) array indices are separated through comma - e.g.: [2,3]
; Syntax ........: _JSON_Get(ByRef $o_Object, Const $s_Pattern)
; Parameters ....: $o_Object      - a nested AutoIt datastructure (Arrays, Dictionaries, basic scalar types)
;                  $s_Pattern     - query pattern like described above
; Return values .: Success - Return the queried object out of the nested datastructure
;                  Failure - Return "" and set @error to:
;                       @error = 1 - pattern is not correct
;                              = 2 - keyname query to none dictionary object
;                              = 3 - keyname queried not exists in dictionary
;                              = 4 - index query on none array object
;                              = 5 - index out of array range
;                              = 6 - number of subindices in index query not match array dimensions
;                              = 7 - more than 3 array dimensions are not supported
; Author ........: AspirinJunkie
; =================================================================================================
Func _JSON_Get(ByRef $o_Object, Const $s_Pattern)
    Local $o_Current = $o_Object, $d_Val
    Local $a_Tokens = StringRegExp($s_Pattern, '\[(\d+|[\d\h,]+)\]|((?>\\.|[^\.\[\]\\]+)+)', 4)
    If @error Then Return SetError(1, @error, "")

    For $a_CurToken In $a_Tokens

        If UBound($a_CurToken) = 3 Then ; KeyName
            $a_CurToken[2] = StringRegExpReplace($a_CurToken[2], '\\(.)', '$1')
            Switch VarGetType($o_Current)
                Case "Object"
                    If Not IsObj($o_Current) Or ObjName($o_Current) <> "Dictionary" Then Return SetError(2, 0, "")
                    If Not $o_Current.Exists($a_CurToken[2]) Then Return SetError(3, 0, "")

                    $o_Current = $o_Current($a_CurToken[2])
                Case "Map"
                    If Not MapExists($o_Current, $a_CurToken[2]) Then Return SetError(3, 0, "")

                    $o_Current = $o_Current[$a_CurToken[2]]
            EndSwitch
        ElseIf UBound($a_CurToken) = 2 Then ; ArrayIndex
            If (Not IsArray($o_Current)) Then Return SetError(4, UBound($o_Current, 0), "")

            ; multi dimensional array
            If StringInStr($a_CurToken[1], ',', 1) Then
                Local $aIndices = StringSplit($a_CurToken[1], ',', 3)
                If UBound($aIndices) <> UBound($o_Current, 0) Then Return SetError(6, UBound($o_Current, 0), "")

                ; get the indices and check their range
                Local $x = Int($aIndices[0]), $y = Int($aIndices[1])
                If $x < 0 Or $x >= UBound($o_Current, 1) Then Return SetError(5, $x, "")
                If $y < 0 Or $y >= UBound($o_Current, 2) Then Return SetError(5, $y, "")
                Switch UBound($aIndices)
                    Case 2 ; 2D array
                        $o_Current = $o_Current[$x][$y]
                    Case 3 ; 3D array
                        Local $z = Int($aIndices[2])
                        If $z < 0 Or $z >= UBound($o_Current, 3) Then Return SetError(5, $z, "")
                        $o_Current = $o_Current[$x][$y][$z]
                    Case Else
                        Return SetError(7, @error, "")
                EndSwitch

                ; 1D array
            Else
                If UBound($o_Current, 0) <> 1 Then Return SetError(6, UBound($o_Current, 0), "")
                $d_Val = Int($a_CurToken[1])
                If $d_Val < 0 Or $d_Val >= UBound($o_Current) Then Return SetError(5, $d_Val, "")
                $o_Current = $o_Current[$d_Val]
            EndIf
        EndIf
    Next
    Return $o_Current
EndFunc   ;==>_JSON_Get


; #FUNCTION# ======================================================================================
; Name ..........: _JSON_addChangeDelete
; Description ...: creates, modifies or deletes within nested AutoIt structures with a simple query string with syntax:
;                  MapKey#1.MapKey#2.[ArrayIndex#1].MapKey#3...  (points keynames can be achieved by "\.")
;                  If the specified structure already exists, then the function overwrite the existing data.
;                  If the specified structure not exists, then the functions creates this structure.
;                  If $vVal = Default, then the function deletes this specific data point inside the structure.
; Syntax ........: _JSON_addChangeDelete(ByRef $oObject, Const $sPattern, Const $vVal = Default [, Const $iRecLevel = 0])
; Parameters ....: $oObject    - a nested AutoIt datastructure (Arrays, Maps, basic scalar types etc.)
;                                in which the structure is to be created or data is to be changed or deleted
;                  $sPattern   - query pattern like described above
;                  $vVal       - the value which should be written at the position in $sPattern
;                              - if $vVal = Default then the position in $sPattern is to be deleted
;                  $iRecLevel  - don't touch! - only for internal purposes
; Return values .: Success - Return True
;                  Failure - Return False and set @error to:
;                       @error = 1 - pattern is not correct
;                       @error = 2 - wrong index for array element
; Author ........: AspirinJunkie
; =================================================================================================
Func _JSON_addChangeDelete(ByRef $oObject, Const $sPattern, Const $vVal = Default, Const $iRecLevel = 0)
    Local Static $aLevels[0]

    ; only on highest recursion level: process the selector string
    If $iRecLevel = 0 Then
        Local $aToken = StringRegExp($sPattern, '\[(\d+)\]|((?>\\.|[^\.\[\]\\]+)+)', 4)
        If @error Then Return SetError(1, @error, "")

        Local $aCurToken

        ReDim $aLevels[UBound($aToken) + 1][2]
        For $i = 0 To UBound($aToken) - 1
            $aCurToken = $aToken[$i]
            If UBound($aCurToken) = 3 Then ; KeyName
                $aLevels[$i][0] = "Map"
                $aLevels[$i][1] = StringRegExpReplace($aCurToken[2], '\\(.)', '$1')
            Else ; Array Index
                $aLevels[$i][0] = "Array"
                $aLevels[$i][1] = Int($aCurToken[1])
            EndIf
        Next
        $aLevels[UBound($aLevels) - 1][0] = "end"
    EndIf

    ; If data structure not exists already - build it as stated in the selector string:
    Local $sCurrenttype = $aLevels[$iRecLevel][0]
    If $sCurrenttype <> VarGetType($oObject) Then
        Switch $sCurrenttype
            Case "Map"
                Local $mTmp[]
                $oObject = $mTmp
            Case "Array"
                Local $aTmp[$aLevels[$iRecLevel][1] + 1]
                $oObject = $aTmp
            Case "end"
                Return $vVal
        EndSwitch
    EndIf

    ; special case treatment for arrays
    If $sCurrenttype = "Array" Then
        If UBound($oObject, 0) <> 1 Then
            Local $aTmp[$aLevels[$iRecLevel][1] + 1]
            $oObject = $aTmp
        ElseIf UBound($oObject) < ($aLevels[$iRecLevel][1] + 1) Then
            ReDim $oObject[$aLevels[$iRecLevel][1] + 1]
        EndIf
    EndIf

    ; create or change the objects in the next hierarchical level and use these as value for the current entry
    Local $vTmp = $oObject[$aLevels[$iRecLevel][1]], _
            $oNext = _JSON_addChangeDelete($vTmp, $sPattern, $vVal, $iRecLevel + 1)

    If $oNext = Default Then ; delete the current level
        Switch $sCurrenttype
            Case "Map"
                MapRemove($oObject, $aLevels[$iRecLevel][1])
            Case "Array"
                Local $iInd = $aLevels[$iRecLevel][1], $nElems = UBound($oObject)

                If $iInd < 0 Or $iInd >= $nElems Then Return SetError(2, @error, "")

                For $i = $iInd To $nElems - 2
                    $oObject[$i] = $oObject[$i + 1]
                Next
                ReDim $oObject[$nElems - 1]
            Case Else
                $oObject[$aLevels[$iRecLevel][1]] = ""
                For $j = UBound($oObject) - 1 To 0 Step -1
                    If $oObject[$j] <> "" Then
                        ReDim $oObject[$j + 1]
                        ExitLoop
                    EndIf
                Next
        EndSwitch
    Else
        $oObject[$aLevels[$iRecLevel][1]] = $oNext
    EndIf

    If $iRecLevel > 0 Then
        Return $oObject
    Else
        ReDim $aLevels[0] ; clean
        Return True
    EndIf
EndFunc   ;==>_JSON_addChangeDelete

; helper function for converting a json formatted string into an AutoIt-string
; slower variant of __JSON_ParseString but also can handle large strings
Func __JSON_ParseString(ByRef $s_String)
    Local $aB[5]

    Local $a_RE = StringRegExp($s_String, '\\\\(*SKIP)(*FAIL)|(\\["bf/]|\\u[[:xdigit:]]{4})', 3)
    If Not @error Then
        For $s_Esc In $a_RE
            Switch StringMid($s_Esc, 2, 1)
                Case "b"
                    If $aB[0] Then ContinueLoop
                    $s_String = StringRegExpReplace($s_String, '\\\\(*SKIP)(*FAIL)|\\b', Chr(8))
                    $aB[0] = True
                Case "f"
                    If $aB[1] Then ContinueLoop
                    $s_String = StringRegExpReplace($s_String, '\\\\(*SKIP)(*FAIL)|\\f', Chr(12))
                    $aB[1] = True
                Case "/"
                    If $aB[2] Then ContinueLoop
                    $s_String = StringRegExpReplace($s_String, '\\\\(*SKIP)(*FAIL)|\\/', "/")
                    $aB[2] = True
                Case '"'
                    If $aB[3] Then ContinueLoop
                    $s_String = StringRegExpReplace($s_String, '\\\\(*SKIP)(*FAIL)|\\"', '"')
                    $aB[3] = True
                Case "u"
                    If $aB[4] Then ContinueLoop
                    $a_RE = StringRegExp($s_String, '\\\\(*SKIP)(*FAIL)|\\u\K[[:xdigit:]]{4}', 3)
                    If Not @error Then
                        If UBound($a_RE) > 10 Then
                            Local $mCodes[]
                            For $s_Code In $a_RE
                                If MapExists($mCodes, $s_Code) Then ContinueLoop
                                $s_String = StringReplace($s_String, "\u" & $s_Code, ChrW(Dec($s_Code)), 0, 1)
                                $mCodes[$s_Code] = ""
                            Next
                        Else
                            For $s_Code In $a_RE
                                $s_String = StringReplace($s_String, "\u" & $s_Code, ChrW(Dec($s_Code)), 0, 1)
                            Next
                        EndIf
                        $aB[4] = True
                    EndIf
            EndSwitch
        Next
    EndIf

    ; converts \n \r \t \\ implicit:
    Return StringFormat(StringReplace($s_String, "%", "%%", 0, 1))
EndFunc   ;==>__JSON_ParseString

; helper function for converting a AutoIt-string into a json formatted string
Func __JSON_FormatString(ByRef $s_String)
    $s_String = _
        StringReplace( _
            StringReplace( _
                StringReplace( _
                    StringReplace( _
                        StringReplace( _
                            StringReplace( _
                                StringReplace( _
                                    StringReplace($s_String, '\', '\\', 0, 1) _
                                , Chr(8), "\b", 0, 1) _
                            , Chr(12), "\f", 0, 1) _
                        , @CRLF, "\n", 0, 1) _
                    , @LF, "\n", 0, 1) _
                , @CR, "\r", 0, 1) _
            , @TAB, "\t", 0, 1) _
        , '"', '\"', 0, 1)
EndFunc   ;==>__JSON_FormatString


; #FUNCTION# ======================================================================================
; Name ..........: __JSON_Base64Encode
; Description ...: convert a binary- or string-Input into BASE64 (or optional base64url) format
;                  mainly a wrapper for the CryptBinaryToString API-function
; Syntax ........: __JSON_Base64Encode(Const ByRef $s_Input, [Const $b_base64url = False])
; Parameters ....: $s_Input       - binary data or string which should be converted
;                  [$b_base64url] - If true the output is in base64url-format instead of base64
; Return values .: Success - Return base64 (or base64url) formatted string
;                  Failure - Return "" and set @error to:
;                       @error = 1 - failure at the first run to calculate the output size
;                              = 2 - failure at the second run to calculate the output
; Author ........: AspirinJunkie
; Example .......: Yes
;                  $s_Base64String = __JSON_Base64Encode("This is my test")
; =================================================================================================
Func __JSON_Base64Encode(Const ByRef $s_Input, Const $b_base64url = False)
    Local $b_Input = IsBinary($s_Input) ? $s_Input : Binary($s_Input)

    Local $t_BinArray = DllStructCreate("BYTE[" & BinaryLen($s_Input) & "]")
    DllStructSetData($t_BinArray, 1, $b_Input)

    Local $h_DLL_Crypt32 = DllOpen("Crypt32.dll")

    ; first run to calculate needed size of output buffer
    Local $a_Ret = DllCall($h_DLL_Crypt32, "BOOLEAN", "CryptBinaryToString", _
            "STRUCT*", $t_BinArray, _     ; *pbBinary
            "DWORD", DllStructGetSize($t_BinArray), _     ; cbBinary
            "DWORD", 1, _     ; dwFlags
            "PTR", Null, _ ; pszString
            "DWORD*", 0)
    If @error Or Not IsArray($a_Ret) Or $a_Ret[0] = 0 Then Return SetError(1, @error, DllClose($h_DLL_Crypt32))

    ; second run to calculate base64-string:
    Local $t_Output = DllStructCreate("CHAR Out[" & $a_Ret[5] & "]")
    Local $a_Ret2 = DllCall($h_DLL_Crypt32, "BOOLEAN", "CryptBinaryToString", _
            "STRUCT*", $t_BinArray, _     ; *pbBinary
            "DWORD", DllStructGetSize($t_BinArray), _     ; cbBinary
            "DWORD", 1, _     ; dwFlags
            "STRUCT*", $t_Output, _ ; pszString
            "DWORD*", $a_Ret[5])
    If @error Or Not IsArray($a_Ret2) Or $a_Ret2[0] = 0 Then Return SetError(2, @error, DllClose($h_DLL_Crypt32))

    Local $s_Output = $t_Output.Out
    If StringInStr($s_Output, "=", 1, 1) Then $s_Output = StringLeft($s_Output, StringInStr($s_Output, "=", 1, 1) - 1)

    If $b_base64url Then $s_Output = StringReplace(StringReplace($s_Output, "/", "_", 0, 1), "+", "-", 0, 1)

    DllClose($h_DLL_Crypt32)
    Return $s_Output
EndFunc   ;==>__JSON_Base64Encode


; #FUNCTION# ======================================================================================
; Name ..........: __JSON_Base64Decode
; Description ...: decode data which is coded as a base64-string into binary form
;                  mainly a wrapper for the CryptStringToBinary API-function
; Syntax ........: __JSON_Base64Decode(Const ByRef $s_Input, [Const $b_base64url = False])
; Parameters ....: $s_Input       - string in base64-format
;                  [$b_base64url] - If true the output is in base64url-format instead of base64
; Return values .: Success - Return base64 (or base64url) formatted string
;                  Failure - Return "" and set @error to:
;                       @error = 1 - failure at the first run to calculate the output size
;                              = 2 - failure at the second run to calculate the output
; Author ........: AspirinJunkie
; Example .......: Yes
;                  MsgBox(0, '', BinaryToString(__JSON_Base64Decode("VGVzdA")))
; =================================================================================================
Func __JSON_Base64Decode(Const ByRef $s_Input, Const $b_base64url = False)
    Local $h_DLL_Crypt32 = DllOpen("Crypt32.dll")

    ; hier noch einen Reg-Ex zum testen ob String base64-codiert ist

    ; first run to calculate needed size of output buffer
    Local $a_Ret = DllCall($h_DLL_Crypt32, "BOOLEAN", "CryptStringToBinary", _
            "STR", $s_Input, _ ; pszString
            "DWORD", 0, _ ; cchString
            "DWORD", 1, _ ; dwFlags
            "PTR", Null, _ ; pbBinary
            "DWORD*", 0, _ ; pcbBinary
            "PTR", Null, _ ; pdwSkip
            "PTR", Null) ; pdwFlags
    Local $t_Ret = DllStructCreate("BYTE Out[" & $a_Ret[5] & "]")
    If @error Or Not IsArray($a_Ret) Or $a_Ret[0] = 0 Then Return SetError(1, @error, DllClose($h_DLL_Crypt32))


    ; second run to calculate the output data:
    Local $a_Ret2 = DllCall($h_DLL_Crypt32, "BOOLEAN", "CryptStringToBinary", _
            "STR", $s_Input, _ ; pszString
            "DWORD", 0, _ ; cchString
            "DWORD", 1, _ ; dwFlags
            "STRUCT*", $t_Ret, _ ; pbBinary
            "DWORD*", $a_Ret[5], _ ; pcbBinary
            "PTR", Null, _ ; pdwSkip
            "PTR", Null) ; pdwFlags
    If @error Or Not IsArray($a_Ret2) Or $a_Ret2[0] = 0 Then Return SetError(2, @error, DllClose($h_DLL_Crypt32))
    DllClose($h_DLL_Crypt32)

    Local $s_Output = $t_Ret.Out
    If $b_base64url Then $s_Output = StringReplace(StringReplace($s_Output, "_", "/", 0, 1), "-", "+", 0, 1)

    Return $s_Output
EndFunc   ;==>__JSON_Base64Decode

; #FUNCTION# ======================================================================================
; Name ..........: __JSON_A2DToAinA()
; Description ...: Convert a 2D array into a Arrays in Array
; Syntax ........: __JSON_A2DToAinA(ByRef $A)
; Parameters ....: $A             - the 2D-Array  which should be converted
; Return values .: Success: a Arrays in Array build from the input array
;                  Failure: False
;                     @error = 1: $A is'nt an 2D array
; Author ........: AspirinJunkie
; =================================================================================================
Func __JSON_A2DToAinA(ByRef $A, $bTruncEmpty = True)
    If UBound($A, 0) <> 2 Then Return SetError(1, UBound($A, 0), False)
    Local $N = UBound($A), $u = UBound($A, 2)
    Local $a_Ret[$N]

    If $bTruncEmpty Then
        For $i = 0 To $N - 1
            Local $x = $u - 1
            While IsString($A[$i][$x]) And $A[$i][$x] = ""
                $x -= 1
            WEnd
            Local $t[$x + 1]
            For $j = 0 To $x
                $t[$j] = $A[$i][$j]
            Next
            $a_Ret[$i] = $t
        Next
    Else
        For $i = 0 To $N - 1
            Local $t[$u]
            For $j = 0 To $u - 1
                $t[$j] = $A[$i][$j]
            Next
            $a_Ret[$i] = $t
        Next
    EndIf
    Return $a_Ret
EndFunc   ;==>__JSON_A2DToAinA

; #FUNCTION# ======================================================================================
; Name ..........: __JSON_AinAToA2d()
; Description ...: Convert a Arrays in Array into a 2D array
;                  here useful if you want to recover 2D-arrays from a json-string
;                  (there exists only a array-in-array and no 2D-Arrays)
; Syntax ........: __JSON_AinAToA2d(ByRef $A)
; Parameters ....: $A             - the arrays in array which should be converted
; Return values .: Success: a 2D Array build from the input array
;                  Failure: False
;                     @error = 1: $A is'nt an 1D array
;                            = 2: $A is empty
;                            = 3: first element isn't a array
; Author ........: AspirinJunkie
; =================================================================================================
Func __JSON_AinAToA2d(ByRef $A)
    If UBound($A, 0) <> 1 Then Return SetError(1, UBound($A, 0), False)
    Local $N = UBound($A)
    If $N < 1 Then Return SetError(2, $N, False)
    Local $u = UBound($A[0])
    If $u < 1 Then Return SetError(3, $u, False)

    Local $a_Ret[$N][$u]

    For $i = 0 To $N - 1
        Local $t = $A[$i]
        If UBound($t) > $u Then ReDim $a_Ret[$N][UBound($t)]
        For $j = 0 To UBound($t) - 1
            $a_Ret[$i][$j] = $t[$j]
        Next
    Next
    Return $a_Ret
EndFunc   ;==>__JSON_AinAToA2d

 

 

Edited by ioa747

I know that I know nothing

Posted
5 minutes ago, ioa747 said:

; helper function for converting a AutoIt-string into a json formatted string
Func __JSON_FormatString(ByRef $s_String)
    $s_String = _
        StringReplace( _
            StringReplace( _
                StringReplace( _
                    StringReplace( _
                        StringReplace( _
                            StringReplace( _
                                StringReplace( _
                                    StringReplace($s_String, '\', '\\', 0, 1) _
                                , Chr(8), "\b", 0, 1) _
                            , Chr(12), "\f", 0, 1) _
                        , @CRLF, "\n", 0, 1) _
                    , @LF, "\n", 0, 1) _
                , @CR, "\r", 0, 1) _
            , @TAB, "\t", 0, 1) _
        , '"', '\"', 0, 1)
EndFunc   ;==>__JSON_FormatString

and I 

; helper function for converting a AutoIt-string into a json formatted string
Func __JSON_FormatString(ByRef $sString)
    Return StringLen($sString) < 50 ? _
    StringTrimRight(StringRegExpReplace($sString & '\\\b\f\n\r\t\"', '(?s)(?|\\(?=.*(\\\\))|[\b](?=.*(\\b))|\f(?=.*(\\f))|\r\n(?=.*(\\n))|\n(?=.*(\\n))|\r(?=.*(\\r))|\t(?=.*(\\t))|"(?=.*(\\")))', '\1'), 15) : _
    StringReplace( _
        StringReplace( _
            StringReplace( _
                StringReplace( _
                    StringReplace( _
                        StringReplace( _
                            StringReplace( _
                                StringReplace($sString, '\', '\\', 0, 1) _
                            , Chr(8), "\b", 0, 1) _
                        , Chr(12), "\f", 0, 1) _
                    , @CRLF, "\n", 0, 1) _
                , @LF, "\n", 0, 1) _
            , @CR, "\r", 0, 1) _
        , @TAB, "\t", 0, 1) _
    , '"', '\"', 0, 1)
EndFunc

hence the oops =/

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
3 hours ago, ioa747 said:

and which is the right one?
 ; Version .......: 0.10  ?

..good question.
 https://github.com/Sylvan86/autoit-json-udf/blob/master/JSON.au3 claims to be "0.10" and "Last changed ..: 2023-04-29" but,
was changed 2 month ago ( changed: _JSON_Parse(): removed Byref - direct input is now possible ).
I guess the one that works is the answer ? 😅

<rant>
That's why I rather have the files in the forum. Static.
These git places are here today and changed or gone some other time :(
</rant>

<note>I'll have to use a git of sorts/providers, to work with modern/current technologies 😭 </note>

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
6 hours ago, argumentum said:

https://github.com/Sylvan86/autoit-json-udf/blob/master/JSON.au3 claims to be "0.10" and "Last changed ..: 2023-04-29" but,
was changed 2 month ago

Yes, version 0.10 is correct, but it should be 0.11.0 instead I would say.
As you already mentioned @argumentum, @AspirinJunkie added few commits (changes) to the UDF which should lead to 0.11.0 from 2025-04-01.

6 hours ago, argumentum said:

<rant>
That's why I rather have the files in the forum. Static.
These git places are here today and changed or gone some other time :(
</rant>

I understand your point of view, but exactly for this situation the idea of forking a repository exists. Then you have your static version or you decide on your own when you want to pull new changes in your repository/fork. To be honest, to search within the forum is way harder then on GitHub (at least for me).

Best regards
Sven

==> AutoIt related: 🔗 GitHub, 🔗 Discord Server, 🔗 Cheat Sheet

Spoiler

🌍 Au3Forums

🎲 AutoIt (en) Cheat Sheet

📊 AutoIt limits/defaults

💎 Code Katas: [...] (comming soon)

🎭 Collection of GitHub users with AutoIt projects

🐞 False-Positives

🔮 Me on GitHub

💬 Opinion about new forum sub category

📑 UDF wiki list

✂ VSCode-AutoItSnippets

📑 WebDriver FAQs

👨‍🏫 WebDriver Tutorial (coming soon)

Posted
5 hours ago, SOLVE-SMART said:

To be honest, to search within the forum is way harder then on GitHub (at least for me).

but what about the future user going to use it and have for breakfast that it ( the code ) don't work because one of the dependencies changed fundamentally and, ...suck it.
I understand selfishness and still advocate for ethical behaviors that don't lead to forking. A letter R apart from the same trend of thought.
And I do understand that you are just adjusted to the current way of developing and you have to do what you must ( at least for you ).

I strongly disagree with this way of participation mainly because anyone trying to replicate what is claimed, is out of phase with time. The time at witch it was all put together because the forks are not what they were.

Pardon my less than nice posture but it is just non-functional. How can one be expected to have forked 2 years ago something so today ( because it was posed 1 day ago ) can not use what is supposed to be there as it was ?

Even tho this chat is with you @SOLVE-SMART, is not necessarily personal. Is the way it is, and leads to these mishaps, hence the concept is wrong.

And no, I can not change it ( the I fork what I need ) because it takes people to feel different, and people adjust for survival of the self over the survival of the group.
That's all there is to it so, foRk it, I guess.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

@argumentum I am not sure i get if it's the platform, the repositories, the individual users or a combination you dislike? :)
When it comes to git, keeping the version in the file seems wrong, in my opinion. Git tags and/or releases on some git platforms seems the best way to keep good track of the available versions of scripts/projects.

In regards to the same code being available at a later date, unless they delete or change the visibility of the repository, you could keep a commit hash reference for a perma-link to the code you were able to access last time ;)

I personally prefer git (GitHub more specifically). Old files on this forum sometimes go poof, and sometimes no one can provide a replica (it's rare, i know).

Both Git and this forum can be a time waster, if dependencies are not kept with the project, and you are forced to go on a treasure hunt to find the necessary files (happened once or twice to me 🫠).

Personally i am working towards a package manager, using primarily git to automatically resolve and fetch dependencies of a project. If developers use the semver standard, patches should be pain free and allow upgrading dependencies using a single command :)

I agree forking is not exactly a perfect solution, but is sometimes necessary, for example when dealing with abandoned projects or not agreeing on where a project is heading ;)

Posted
16 minutes ago, genius257 said:

you could keep a commit hash reference for a perma-link to the code you were able to access last time ;)

Good to know.
Since am not familiar with git, going to get "the file" and is not it, ..is frustrating.
I code so I can debug it but those that expect the stuff to run ( because is stuff we/they discover, run it, and if it didn't, meh, it does not work, next... ) will miss in using it and participating with bugs or code or anything.

21 minutes ago, genius257 said:

Both Git and this forum can be a time waster, if dependencies are not kept with the project, and you are forced to go on a treasure hunt to find the necessary files (happened once or twice to me 🫠).

I've found myself uploading files for those occasions when I have them ( and I have them because I hoard them ). 

Maybe I went overboard in my rant, maybe. I should have advised to include all the external includes and that is a better solution :) 

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted

Off topic

Spoiler
3 minutes ago, argumentum said:

Maybe I went overboard in my rant, maybe.

I get your point(s) @argumentumI am fine with your statements and I don't take it personally.

I guess I am simply more used to work with Git and GitHub/GitLab. Although I'm all for making things as easy as possible for users and programmers, the world around AutoIt relies on > 90% of Git and GitHub usage (or other platforms). I'm adapting to this because it's common sense, and thousands of developers have chosen this path. Certainly not without reason.

Anyhow, we can discuss such things in a separate thread or in the chat section, because I try not to hijack or disturb the original topic (again) 😇 .

Best regards
Sven

==> AutoIt related: 🔗 GitHub, 🔗 Discord Server, 🔗 Cheat Sheet

Spoiler

🌍 Au3Forums

🎲 AutoIt (en) Cheat Sheet

📊 AutoIt limits/defaults

💎 Code Katas: [...] (comming soon)

🎭 Collection of GitHub users with AutoIt projects

🐞 False-Positives

🔮 Me on GitHub

💬 Opinion about new forum sub category

📑 UDF wiki list

✂ VSCode-AutoItSnippets

📑 WebDriver FAQs

👨‍🏫 WebDriver Tutorial (coming soon)

Posted
14 minutes ago, argumentum said:

Good to know.
Since am not familiar with git, going to get "the file" and is not it, ..is frustrating.

I think then the reference link should be https://github.com/Sylvan86/autoit-json-udf/blob/8f326597f402c1576ef793b68552171472db62c9/JSON.au3 ( untested, just looking at it )
But it would be nice to fix just that function given that the file had many patches after that.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...