diff --git a/docs/search/search_index.json b/docs/search/search_index.json
index ffcfbd0..52f9dc8 100644
--- a/docs/search/search_index.json
+++ b/docs/search/search_index.json
@@ -1 +1 @@
-{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Welcome to MkDocs For full documentation visit mkdocs.org . Commands mkdocs new [dir-name] - Create a new project. mkdocs serve - Start the live-reloading docs server. mkdocs build - Build the documentation site. mkdocs -h - Print help message and exit. mkdocs -h - Print help message and exit. Project layout mkdocs.yml # The configuration file. docs/ index.md # The documentation homepage. ... # Other markdown pages, images and other files.","title":"Welcome to MkDocs"},{"location":"#welcome-to-mkdocs","text":"For full documentation visit mkdocs.org .","title":"Welcome to MkDocs"},{"location":"#commands","text":"mkdocs new [dir-name] - Create a new project. mkdocs serve - Start the live-reloading docs server. mkdocs build - Build the documentation site. mkdocs -h - Print help message and exit. mkdocs -h - Print help message and exit.","title":"Commands"},{"location":"#project-layout","text":"mkdocs.yml # The configuration file. docs/ index.md # The documentation homepage. ... # Other markdown pages, images and other files.","title":"Project layout"},{"location":"license/","text":"License MIT License Copyright (c) 2024 INVITE Communications Co. Ltd. Copyright (c) 2024 Brian LaVallee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"License"},{"location":"license/#license","text":"MIT License Copyright (c) 2024 INVITE Communications Co. Ltd. Copyright (c) 2024 Brian LaVallee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"License"}]}
\ No newline at end of file
+{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Welcome to MkDocs For full documentation visit mkdocs.org . Commands mkdocs new [dir-name] - Create a new project. mkdocs serve - Start the live-reloading docs server. mkdocs build - Build the documentation site. mkdocs -h - Print help message and exit. mkdocs -h - Print help message and exit. Project layout mkdocs.yml # The configuration file. docs/ index.md # The documentation homepage. ... # Other markdown pages, images and other files.","title":"Welcome to MkDocs"},{"location":"#welcome-to-mkdocs","text":"For full documentation visit mkdocs.org .","title":"Welcome to MkDocs"},{"location":"#commands","text":"mkdocs new [dir-name] - Create a new project. mkdocs serve - Start the live-reloading docs server. mkdocs build - Build the documentation site. mkdocs -h - Print help message and exit. mkdocs -h - Print help message and exit.","title":"Commands"},{"location":"#project-layout","text":"mkdocs.yml # The configuration file. docs/ index.md # The documentation homepage. ... # Other markdown pages, images and other files.","title":"Project layout"},{"location":"gems/","text":"Gems, Snippets, and Concepts Something about getting to a working Python and JavaScript interop will go here.","title":"Gems, Snippets, and Concepts"},{"location":"gems/#gems-snippets-and-concepts","text":"Something about getting to a working Python and JavaScript interop will go here.","title":"Gems, Snippets, and Concepts"},{"location":"license/","text":"License MIT License Copyright (c) 2024 INVITE Communications Co. Ltd. Copyright (c) 2024 Brian LaVallee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"License"},{"location":"license/#license","text":"MIT License Copyright (c) 2024 INVITE Communications Co. Ltd. Copyright (c) 2024 Brian LaVallee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","title":"License"}]}
\ No newline at end of file
diff --git a/docs/sitemap.xml.gz b/docs/sitemap.xml.gz
index e918761..543f7df 100644
Binary files a/docs/sitemap.xml.gz and b/docs/sitemap.xml.gz differ
diff --git a/docs_source/gems.md b/docs_source/gems.md
new file mode 100644
index 0000000..41731c5
--- /dev/null
+++ b/docs_source/gems.md
@@ -0,0 +1,3 @@
+# Gems, Snippets, and Concepts
+
+Something about getting to a working Python and JavaScript interop will go here.
\ No newline at end of file
diff --git a/gems/README.md b/gems/README.md
new file mode 100644
index 0000000..517b62e
--- /dev/null
+++ b/gems/README.md
@@ -0,0 +1,29 @@
+# Gems Directory
+
+Welcome to the "gems" directory! 🚀 Here, you'll find a collection of code snippets that serve as proof-of-concept (PoC) implementations. These snippets, while not directly used in the project, have been valuable in the development process. They've provided insights, solutions, or innovative approaches that have contributed to the overall success of the project.
+
+## Purpose
+
+- **Idea Exploration:** The snippets in this directory were created during the exploration phase, where various ideas and concepts were tested before implementation in the main project codebase.
+
+- **Problem Solving:** These code snippets may contain solutions to specific challenges or problems encountered during development. While they might not be part of the final code, they showcase different approaches to problem-solving.
+
+- **Learning and Experimentation:** The "gems" directory is also a space for experimentation and learning. Developers can refer to these PoCs to understand different techniques and methodologies.
+
+## Organization
+
+The directory is organized with each code snippet placed in a separate file or subdirectory, named descriptively to indicate its purpose or the problem it addresses. Additionally, a brief explanation is provided within each file to give context and insights into the PoC.
+
+## How to Use
+
+While the code in this directory is not directly integrated into the main project, you may find value in reviewing these snippets for reference or inspiration. If a particular PoC aligns with a current or future project requirement, feel free to adapt and incorporate the code into your work.
+
+## Contributing
+
+If you have additional PoCs or innovative code snippets that you believe could benefit the project, consider contributing them to this directory. Follow the contribution guidelines outlined in the project's main README.
+
+## License
+
+All code snippets in this directory are provided under the [project's license](https://github.com/poing/JS2PySecrets/blob/main/LICENSE). Please review the license before using or distributing any code from this directory.
+
+Happy coding! 🎉
diff --git a/gems/dict2json.py b/gems/dict2json.py
new file mode 100755
index 0000000..0ed6970
--- /dev/null
+++ b/gems/dict2json.py
@@ -0,0 +1,36 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# dict2json.py
+
+"""
+This is a basic example of taking a Python dict and returning JSON.
+
+The goal is passing function names and argument groups in a nested JSON.
+
+It's a work in progress where the assumption is, there will be a set of setup commands (that are likely static), followed by a dynamic command with var based arguments.
+"""
+
+import json
+
+# key: value (the function & arguments)
+setup = [
+ {"function": "setRNG", "args": ["testRandom"]},
+ {"function": "init", "args": [12, 'testRandom']}
+]
+
+# Dynamic Values
+foo = ["1234abc", 6, 3]
+
+# key: value (the function & dynamic arguments)
+main = {"function": "share", "args": foo}
+
+# Combine setup and main
+tasks = [{"setup": setup, "start": main}]
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+
+# Print or use the JSON data as needed
+print(json_data)
diff --git a/gems/example1.py b/gems/example1.py
new file mode 100755
index 0000000..c6c0050
--- /dev/null
+++ b/gems/example1.py
@@ -0,0 +1,38 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# example1.py
+
+import json
+import js2pysecrets
+
+# // generate a 512-bit key
+# key = js2pysecrets.random(512) // => key is a hex string
+key = js2pysecrets.random(512)
+print(key)
+
+# // split into 10 shares with a threshold of 5
+# shares = js2pysecrets.share(key, 10, 5)
+# // => shares = ['801xxx...xxx','802xxx...xxx','803xxx...xxx','804xxx...xxx','805xxx...xxx']
+shares = js2pysecrets.share(key, 10, 5)
+print(shares)
+
+# // combine 4 shares
+# var comb = secrets.combine(shares.slice(0, 4))
+# console.log(comb === key) // => false
+#
+# // combine 5 shares
+# comb = secrets.combine(shares.slice(4, 9))
+# console.log(comb === key) // => true
+#
+# // combine ALL shares
+# comb = secrets.combine(shares)
+# console.log(comb === key) // => true
+#
+# // create another share with id 8
+# var newShare = secrets.newShare(8, shares) // => newShare = '808xxx...xxx'
+#
+# // reconstruct using 4 original shares and the new share:
+# comb = secrets.combine(shares.slice(1, 5).concat(newShare))
+# console.log(comb === key) // => true
\ No newline at end of file
diff --git a/gems/example2.py b/gems/example2.py
new file mode 100755
index 0000000..60fc018
--- /dev/null
+++ b/gems/example2.py
@@ -0,0 +1,36 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# example1.py
+
+import json
+import js2pysecrets
+
+# var pw = "<>"
+pw = "<>"
+
+# // convert the text into a hex string
+# var pwHex = secrets.str2hex(pw) // => hex string
+jsHex = js2pysecrets.str2hex(pw)
+print(jsHex)
+
+pyHex = pw.encode('utf-16-be').hex().lstrip('fe')
+print(pyHex)
+
+# // split into 5 shares, with a threshold of 3
+# var shares = secrets.share(pwHex, 5, 3)
+#
+# // combine 2 shares:
+# var comb = secrets.combine(shares.slice(1, 3))
+#
+# //convert back to UTF string:
+# comb = secrets.hex2str(comb)
+# console.log(comb === pw) // => false
+#
+# // combine 3 shares:
+# comb = secrets.combine([shares[1], shares[3], shares[4]])
+#
+# //convert back to UTF string:
+# comb = secrets.hex2str(comb)
+# console.log(comb === pw) // => true
\ No newline at end of file
diff --git a/gems/func2str.py b/gems/func2str.py
new file mode 100755
index 0000000..88bd3f9
--- /dev/null
+++ b/gems/func2str.py
@@ -0,0 +1,55 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# func2str.py
+
+from functools import wraps
+import json
+
+
+def function_to_string(func):
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ args_str = ', '.join(repr(arg) for arg in args)
+ kwargs_str = ', '.join(f'{key}={repr(value)}' for key, value in kwargs.items())
+ all_args = ', '.join(filter(None, [args_str, kwargs_str]))
+
+ return f"{func.__name__}({all_args});"
+
+ return wrapper
+
+# Applying the decorator to functions
+@function_to_string
+def funcA(*args, **kwargs):
+ pass
+
+@function_to_string
+def funcB(*args, **kwargs):
+ pass
+
+funcC = function_to_string('blue')
+
+# Testing
+print(funcA("aa", "bb", 123, x=123)) # "funcA('aa', 'bb', 123, x=123)"
+print(funcA('aa', 'bb', 123, x=123)) # "funcA('aa', 'bb', 123, x=123)"
+print(funcA('aa', 'bb', 123, x=123)) # "funcA('aa', 'bb', 123, x=123)"
+
+# Support and pass dict
+print(funcB(["aa", "bb"], 123, x=123)) # 'funcB(["aa", "bb"], 123, x=123)'
+
+foobar = "AAFF"
+
+tasks = [
+ funcA(foobar, 2, "that"),
+ funcA(["some", "more", 2]),
+ funcB("and something", "else", 2, plus=22),
+ blue('hey'),
+]
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+
+# Print or use the JSON data as needed
+print(json_data)
+
diff --git a/gems/func2str2.py b/gems/func2str2.py
new file mode 100755
index 0000000..6566f4d
--- /dev/null
+++ b/gems/func2str2.py
@@ -0,0 +1,60 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# func2str2.py
+
+"""
+This script demonstrates making the JsFunction class work both as a callable and as a decorator.
+"""
+
+class JsFunction:
+ def __init__(self, func):
+ self.func = func
+
+ def __call__(self, *args, **kwargs):
+ def wrapped_func(*args, **kwargs):
+ args_str = ', '.join(repr(arg) for arg in args)
+ kwargs_str = ', '.join(f'{key}={repr(value)}'
+ for key, value in kwargs.items())
+ all_args = ', '.join(filter(None, [args_str, kwargs_str]))
+
+ return f"{self.func.__name__}({all_args})"
+
+ return wrapped_func(*args, **kwargs) if args else self.func(*args, **kwargs)
+
+ def __get__(self, instance, owner):
+ return self if instance is None else types.MethodType(self, instance)
+
+# Applied as a decorator
+# Functional placeholder that uses the JS code, until the Python function is created
+@JsFunction
+def alpha(*args, **kwargs):
+ pass
+
+# Eventually independent python function will be created
+def bravo():
+ return "bravo('aa', 'bb', 123, x=123)"
+
+# Create a alternately named instance of the JsFunction class that's callable
+# Which is important for testing against python functions
+testBravo = JsFunction(bravo)
+
+"""
+WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
+You cannot create an alternate instance using JsFunction it is already used. Attempting to do so may lead to unexpected behavior. For example, you cannot use testAlpha = JsFunction(alpha) if alpha() already has the JsFunction decorator applied.
+WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
+"""
+
+print(alpha("aa", "bb", 123, x=123)) # Returns: alpha('aa', 'bb', 123, x=123)
+print(bravo()) # Returns: bravo('aa', 'bb', 123, x=123)
+print(testBravo("aa", "bb", 123, x=123)) # Returns: bravo('aa', 'bb', 123, x=123)
+
+def string_comparison(str1, str2):
+ if str1 == str2:
+ return "Test Passed: Strings are equal"
+ else:
+ return "Test Failed: Strings are not equal"
+
+print(string_comparison(alpha(123,'aaa'), testBravo(123,'aaa')))
+print(string_comparison(bravo(), testBravo('aa', 'bb', 123, x=123)))
diff --git a/gems/func2str3.py b/gems/func2str3.py
new file mode 100755
index 0000000..dc709a7
--- /dev/null
+++ b/gems/func2str3.py
@@ -0,0 +1,68 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# func2str3.py
+
+"""
+This script demonstrates making the JsFunction class work both as a callable and as a decorator. Excluding **kwargs in the output. Added test flag.
+"""
+
+class JsFunction:
+ def __init__(self, func, test=False):
+ self.func = func
+ self.test = test
+
+ def __call__(self, *args, test=False, **kwargs):
+ def wrapped_func(*args, **kwargs):
+ args_str = ', '.join(repr(arg) for arg in args)
+ #kwargs_str = ', '.join(f'{key}={repr(value)}'
+ # for key, value in kwargs.items())
+ #all_args = ', '.join(filter(None, [args_str, kwargs_str]))
+
+ return f"{self.func.__name__}({args_str})"
+
+ data = ["init()"]
+ if test or self.test:
+ data.append("setRNG('testRandom')")
+
+ data.append(wrapped_func(*args, **kwargs) if args else self.func(*args, **kwargs))
+ return data
+
+ def __get__(self, instance, owner):
+ return self if instance is None else types.MethodType(self, instance)
+
+# Applied as a decorator
+# Functional placeholder that uses the JS code, until the Python function is created
+@JsFunction
+def alpha(*args, **kwargs):
+ pass
+
+# Eventually independent python function will be created
+def bravo():
+ return "bravo('aa', 'bb', 123)"
+
+# Create a alternately named instance of the JsFunction class that's callable
+# Which is important for testing against python functions
+testBravo = JsFunction(bravo, test=True)
+regBravo = JsFunction(bravo)
+
+"""
+WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
+You cannot create an alternate instance using the JsFunction if it is already used. Attempting to do so may lead to unexpected behavior. For example, you cannot use testAlpha = JsFunction(alpha) if alpha() already has the JsFunction decorator applied.
+WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
+"""
+
+print(alpha("aa", "bb", 123, x=123)) # Returns: alpha('aa', 'bb', 123, x=123)
+print(bravo()) # Returns: bravo('aa', 'bb', 123, x=123)
+print(testBravo("aa", "bb", 123, x=123)) # Returns: bravo('aa', 'bb', 123, x=123)
+print(regBravo("aa", "bb", 123, x=123)) # Returns: bravo('aa', 'bb', 123, x=123)
+
+def string_comparison(str1, str2):
+ if str1 == str2:
+ return "Test Passed: Strings are equal"
+ else:
+ return "Test Failed: Strings are not equal"
+
+print(string_comparison(alpha(123,'aaa'), testBravo(123,'aaa')))
+print(string_comparison(bravo(), testBravo('aa', 'bb', 123, x=123)))
diff --git a/gems/proc_commV1.py b/gems/proc_commV1.py
new file mode 100755
index 0000000..2578340
--- /dev/null
+++ b/gems/proc_commV1.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# proc_commV1.py
+
+# Trying to use process.communicate() with Node
+
+import subprocess
+
+#JS_FILE_PATH = "wrapperV7.js"
+#js_command = ["node", "-i", JS_FILE_PATH]
+
+# Start the Node.js process
+node_process = subprocess.Popen(["node", "-i"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+
+# Send JavaScript commands
+commands = [
+ "const secrets = require('../secrets.js/secrets.js')",
+ "console.log('Hello from Node.js!')",
+ "console.log(2 + 2)",
+ "console.log(Math.random())",
+ "var HHGTTG = 42",
+ "console.log(HHGTTG)",
+ "secrets.share('1234abc', 6, 3)"
+]
+
+
+# Send commands to the Node.js process
+for command in commands:
+ node_process.stdin.write(command + '\n')
+
+# Read output
+output, error = node_process.communicate()
+
+# Close stdin to indicate end of input
+node_process.stdin.close()
+
+print("Output:")
+print(output)
+
+print("Error:")
+print(error)
diff --git a/gems/proc_commV2.py b/gems/proc_commV2.py
new file mode 100755
index 0000000..e04ff3d
--- /dev/null
+++ b/gems/proc_commV2.py
@@ -0,0 +1,47 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# proc_commV2.py
+
+# Trying to use process.communicate() with Node
+
+import subprocess
+
+#JS_FILE_PATH = "wrapperV7.js"
+#js_command = ["node", "-i", JS_FILE_PATH]
+
+# Start the Node.js process
+node_process = subprocess.Popen(["node", "-i"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+
+# Send JavaScript commands
+commands = [
+ "const secrets = require('../secrets.js/secrets.js')",
+ "console.log('Hello from Node.js!')",
+ "console.log(2 + 2)",
+ "console.log(Math.random())",
+ "var HHGTTG = 42",
+ "console.log(HHGTTG)",
+ "secrets.share('1234abc', 6, 3)"
+]
+
+#print(commands[0])
+
+# Send commands to the Node.js process
+for command in commands:
+ node_process.stdin.write(command + '\n')
+#node_process.stdin.write(commands[1] + '\n')
+#foo.stdout.readline()
+
+# Read output
+output, error = node_process.communicate()
+
+# Close stdin to indicate end of input
+node_process.stdin.close()
+
+
+print("Output:")
+print(output)
+
+print("Error:")
+print(error)
\ No newline at end of file
diff --git a/gems/test_call.py b/gems/test_call.py
new file mode 100755
index 0000000..e36c94c
--- /dev/null
+++ b/gems/test_call.py
@@ -0,0 +1,10 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# test_call.py
+
+from test_func import forTesting
+
+print(forTesting())
+# Expected "Hello World"
\ No newline at end of file
diff --git a/gems/test_func.py b/gems/test_func.py
new file mode 100755
index 0000000..d01d24f
--- /dev/null
+++ b/gems/test_func.py
@@ -0,0 +1,29 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# test_func.py
+
+from test_inject import TESTER
+
+#TESTER = True # Define the TESTER variable
+
+def forTesting(str1='What', str2='Now'):
+ result = str1 + ' ' + str2
+ if TESTER:
+ return "blaa blaa"
+ else:
+ return result
+
+# A decorator function to inject behavior
+def inject_behavior(original_function):
+ def wrapper(*args, **kwargs):
+ if TESTER:
+ kwargs['str2'] = "Developer"
+ return original_function(*args, **kwargs)
+ return wrapper
+
+# Wrap the forTesting function with the inject_behavior decorator
+#forTesting = inject_behavior(forTesting)
+
+# Maybe can use the wrapper from the test_inject, setting the global HERE.
diff --git a/gems/test_import1.py b/gems/test_import1.py
new file mode 100755
index 0000000..6be7de1
--- /dev/null
+++ b/gems/test_import1.py
@@ -0,0 +1,31 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# test.py
+
+import json
+from js2pysecrets import wrapper
+
+
+# Example usage
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = ['1234abc', 6, 3]
+
+# Main function
+main = {'function': 'share', 'args': foo}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+#print(json_data)
+
+doit = wrapper(json_data)
+print(doit)
diff --git a/gems/test_import2.py b/gems/test_import2.py
new file mode 100755
index 0000000..c279b6c
--- /dev/null
+++ b/gems/test_import2.py
@@ -0,0 +1,36 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# test.py
+
+import json
+import js2pysecrets
+
+# from js2pysecrets import wrapper
+#
+#
+# setup = []
+# main = {'function': 'getConfig', 'args': []}
+# tasks = {'tasks': [{'setup': setup, 'start': main}]}
+# json_data = json.dumps(tasks, indent=None)
+# print(wrapper(json_data))
+
+# print(js2pysecrets.getConfig())
+# print(js2pysecrets._reset())
+# print(js2pysecrets.getConfig())
+
+# data = js2pysecrets.random(64)
+# print(js2pysecrets.str2hex(data))
+#random = js2pysecrets.jsFunction('random', test=True)
+#print(random(32))
+print(js2pysecrets.random(32))
+print(js2pysecrets.share("ababab", 6, 3, test=True))
+
+shares = js2pysecrets.share("ababab", 6, 3)
+print(shares[1])
+print(shares[3])
+print(shares[5])
+
+recoveredPass = js2pysecrets.combine([shares[1],shares[3],shares[5]])
+print("recovered password is: ", recoveredPass)
\ No newline at end of file
diff --git a/gems/test_inject.py b/gems/test_inject.py
new file mode 100755
index 0000000..cb6b8c2
--- /dev/null
+++ b/gems/test_inject.py
@@ -0,0 +1,23 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# test_inject.py
+
+#from test_func import forTesting
+
+TESTER = False
+
+# Set the global variable TESTER to True to inject behavior
+def run_test():
+ global TESTER # Use the global keyword to modify the global variable
+ TESTER = True
+
+ # Call the forTesting function as usual
+ result = forTesting()
+ return result
+
+#print(run_test()) # Expected result "Hello Developer"
+print(TESTER)
+#print(run_test())
+print(False)
\ No newline at end of file
diff --git a/gems/wrapperV1.js b/gems/wrapperV1.js
new file mode 100755
index 0000000..6fdac44
--- /dev/null
+++ b/gems/wrapperV1.js
@@ -0,0 +1,58 @@
+// wrapperV1.js
+
+/*
+This is the first working version of the wrapper. It's called by Python to run
+one (1) JavaScript command for the secrets.js package.
+
+It's rudimentary, and any commands that need to be run before the main function
+need to be added. This is because Node is called as a single instance, and it does not support subsequent calls.
+
+In the next version, the goal is to pass a series of commands and eliminate
+the need to include setup commands.
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ // Retrieve input JSON from command line arguments
+ const inputJson = process.argv[2];
+
+ // Commands run before the main command
+ //secrets.setRNG("testRandom");
+ //secrets.init(12, "testRandom");
+
+ if (!inputJson) {
+ console.error("No input provided.");
+ process.exit(1);
+ }
+
+ try {
+ // Parse the input JSON
+ const input_data = JSON.parse(inputJson);
+
+ const functionName = input_data.functionName;
+ const arguments = input_data.arguments;
+
+ // Dynamically call the function
+ const selectedFunction = secrets[functionName];
+
+ if (selectedFunction && typeof selectedFunction === 'function') {
+ // Call the selected function
+ const result = selectedFunction(...arguments);
+
+ // Format the result as a JSON object
+ const resultJson = JSON.stringify({ result });
+
+ // Print only the result to the console
+ console.log(resultJson);
+ } else {
+ console.log(JSON.stringify({ error: `Unknown function: ${functionName}` }));
+ }
+ } catch (error) {
+ console.error("Error parsing or executing:", error.message);
+ // In case of an error, print a JSON object with an "error" key
+ console.log(JSON.stringify({ error: error.message }));
+ }
+}
diff --git a/gems/wrapperV10.js b/gems/wrapperV10.js
new file mode 100755
index 0000000..4ae4d6b
--- /dev/null
+++ b/gems/wrapperV10.js
@@ -0,0 +1,51 @@
+// wrapperV10.js
+
+/*
+This is the third working version of the wrapper. Better error handling and accepting multiple JavaScript commands for the secrets.js package.
+*/
+
+// Hex to ASCII
+function hex2a(hex)
+{
+ var str = '';
+ for (var i = 0; i < hex.length; i += 2)
+ str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+ return str;
+}
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const commands = hex2a(process.argv[2]);
+
+ if (!commands.length) {
+ console.error("No commands provided.");
+ process.exit(1);
+ }
+
+ try {
+
+
+ //return commands;
+ const inputData = JSON.parse(commands);
+
+ // Debugging statements
+ //console.log("Commands received from Python:", commands);
+ //console.log("inputData[0][0]: ", inputData[0][0]); // returns: init(33)
+
+ // Loop through commands
+ for (const command of inputData) {
+ // Evaluate each command
+ lastResult = eval('secrets.' + command[0]);
+ }
+
+ // Return the result of the last command
+ console.log(JSON.stringify(lastResult));
+
+ } catch (error) {
+ console.error("Error executing command:", error.message);
+ process.exit(1);
+ }
+}
\ No newline at end of file
diff --git a/gems/wrapperV10_test.py b/gems/wrapperV10_test.py
new file mode 100755
index 0000000..3af6bde
--- /dev/null
+++ b/gems/wrapperV10_test.py
@@ -0,0 +1,132 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV10_test.py
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV10.js"
+
+def wrapper(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (list): List containing the function calls as strings.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Enclose input_json in single quotes
+ js_command = ["node", JS_FILE_PATH, input_data]
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ # print("Input data sent to JavaScript:", input_data)
+ # print("stdout:", result.stdout)
+ # print("stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+ #print('json.loads')
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ return js_result
+
+ except json.JSONDecodeError as e:
+ print("Python error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = e.stderr.strip() # Use e.stderr instead of result.stderr
+ print("JavaScript error:", js_error)
+ return None
+
+'''
+Used to pass a "clean" string as an arg to the CLI
+'''
+def encode_to_base36(data):
+ base36_string = ""
+ for key, value in data.items():
+ base36_string += key + str(value)
+ return base36_string
+
+class JsFunction:
+ def __init__(self, func, test=False):
+ self.func = func
+ self.test = test
+
+ def __call__(self, *args, test=False, **kwargs):
+ def wrapped_func(*args, **kwargs):
+ args_str = ', '.join(repr(arg) for arg in args)
+ #kwargs_str = ', '.join(f'{key}={repr(value)}'
+ # for key, value in kwargs.items())
+ #all_args = ', '.join(filter(None, [args_str, kwargs_str]))
+
+ return f"{self.func.__name__}({args_str})"
+
+ data = []
+
+ # DO NOT REMOVE THIS
+ if test or self.test:
+ data.append("setRNG('testRandom')")
+
+ data.append(wrapped_func(*args, **kwargs) if args else self.func(*args, **kwargs))
+ return data
+
+ def __get__(self, instance, owner):
+ return self if instance is None else types.MethodType(self, instance)
+
+@JsFunction
+def init(*args, **kwargs):
+ pass
+
+@JsFunction
+def setRNG(*args, **kwargs):
+ pass
+
+@JsFunction
+def share(*args, **kwargs):
+ pass
+
+
+
+alpha = init(18)
+bravo = setRNG("testRandom")
+delta = share('1234abc', 6, 3)
+
+
+# Combine
+tasks = [
+ bravo,
+ delta
+]
+
+#tasks = {alpha, bravo}
+
+#print("Tasks: ", tasks)
+
+
+
+json_data = json.dumps(tasks, indent=None).replace("'", "`")
+#print(json_data)
+#print(json_data.encode().hex())
+data = json_data.encode().hex()
+#print(data)
+# Call the wrapper function
+js_result = wrapper(data)
+
+print(js_result)
+#print(js_result)
diff --git a/gems/wrapperV11.js b/gems/wrapperV11.js
new file mode 100755
index 0000000..fb7980d
--- /dev/null
+++ b/gems/wrapperV11.js
@@ -0,0 +1,51 @@
+// wrapperV11.js
+
+/*
+This is the third working version of the wrapper. Better error handling and accepting multiple JavaScript commands for the secrets.js package.
+*/
+
+// Hex to ASCII
+function hex2a(hex)
+{
+ var str = '';
+ for (var i = 0; i < hex.length; i += 2)
+ str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+ return str;
+}
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const commands = hex2a(process.argv[2]);
+
+ if (!commands.length) {
+ console.error("No commands provided.");
+ process.exit(1);
+ }
+
+ try {
+
+
+ //return commands;
+ const inputData = JSON.parse(commands);
+
+ // Debugging statements
+ //console.log("Commands received from Python:", commands);
+ //console.log("inputData[0][0]: ", inputData[0][0]); // returns: init(33)
+
+ // Loop through commands
+ for (const command of inputData) {
+ // Evaluate each command
+ lastResult = eval('secrets.' + command[0]);
+ }
+
+ // Return the result of the last command
+ console.log(JSON.stringify(lastResult));
+
+ } catch (error) {
+ console.error("Error executing command:", error.message);
+ process.exit(1);
+ }
+}
\ No newline at end of file
diff --git a/gems/wrapperV11_test.py b/gems/wrapperV11_test.py
new file mode 100755
index 0000000..dffce6e
--- /dev/null
+++ b/gems/wrapperV11_test.py
@@ -0,0 +1,152 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV11_test.py
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV11.js"
+
+def wrapper(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (list): List containing the function calls as strings.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Enclose input_json in single quotes
+ js_command = ["node", JS_FILE_PATH, input_data]
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ # print("Input data sent to JavaScript:", input_data)
+ # print("stdout:", result.stdout)
+ # print("stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+ #print('json.loads')
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ return js_result
+
+ except json.JSONDecodeError as e:
+ print("Python error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = e.stderr.strip() # Use e.stderr instead of result.stderr
+ print("JavaScript error:", js_error)
+ return None
+
+'''
+Used to pass a "clean" string as an arg to the CLI
+'''
+def encode_to_base36(data):
+ base36_string = ""
+ for key, value in data.items():
+ base36_string += key + str(value)
+ return base36_string
+
+class JsFunction:
+ def __init__(self, func, test=False):
+ self.func = func
+ self.test = test
+
+ def __call__(self, *args, test=False, **kwargs):
+ def wrapped_func(*args, **kwargs):
+ args_str = ', '.join(repr(arg) for arg in args)
+ #kwargs_str = ', '.join(f'{key}={repr(value)}'
+ # for key, value in kwargs.items())
+ #all_args = ', '.join(filter(None, [args_str, kwargs_str]))
+
+ return f"{self.func.__name__}({args_str})"
+
+ data = []
+
+ # DO NOT REMOVE THIS
+ if test or self.test:
+ data.append("setRNG('testRandom')")
+
+ data.append(wrapped_func(*args, **kwargs) if args else self.func(*args, **kwargs))
+ return data
+
+ def __get__(self, instance, owner):
+ return self if instance is None else types.MethodType(self, instance)
+
+@JsFunction
+def init(*args, **kwargs):
+ pass
+
+@JsFunction
+def setRNG(*args, **kwargs):
+ pass
+
+@JsFunction
+def share(*args, **kwargs):
+ pass
+
+@JsFunction
+def combine(*args, **kwargs):
+ pass
+
+alpha = init(18)
+bravo = setRNG("testRandom")
+delta = share('1234abc', 6, 3)
+
+
+# Combine
+tasks = [
+ bravo,
+ delta
+]
+
+#tasks = {alpha, bravo}
+
+#print("Tasks: ", tasks)
+
+
+
+json_data = json.dumps(tasks, indent=None).replace("'", "`")
+#print(json_data)
+#print(json_data.encode().hex())
+data = json_data.encode().hex()
+#print(data)
+# Call the wrapper function
+shares = wrapper(data)
+
+print(shares[1])
+print(shares[3])
+print(shares[5])
+
+foobar = combine([shares[1], shares[3], shares[5]])
+tasks = [ foobar ]
+json_data = json.dumps(tasks, indent=None).replace("'", "`")
+data = json_data.encode().hex()
+print(wrapper(data))
+# print(shares)
+# #print(js_result)
+#
+# todo = combine([shares[2], shares[3], shares[4]])
+# json_data = json.dumps(todo, indent=None).replace("'", "`")
+# data = json_data.encode().hex()
+#
+# answer = wrapper(data)
+
+
+#print(answer)
diff --git a/gems/wrapperV1_test.py b/gems/wrapperV1_test.py
new file mode 100755
index 0000000..b5aa201
--- /dev/null
+++ b/gems/wrapperV1_test.py
@@ -0,0 +1,130 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV1_test.py
+
+"""
+This script demonstrates the first working version of calling Node.js to execute JavaScript using a wrapper to load the secrets.js package.
+It's rudimentary and currently only handles one (1) command. But it works!
+
+The example usage at the end showcases calling different JavaScript functions with corresponding arguments and the rudimentary goal of comparing the results with Python calculations.
+"""
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV1.js"
+
+def run_js_function(function_name, arguments):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ function_name (str): Name of the JavaScript function to call.
+ arguments (list): List of arguments to pass to the JavaScript function.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+ input_data = {
+ "functionName": function_name,
+ "arguments": arguments
+ }
+ input_json = json.dumps(input_data)
+
+ js_command = ["node", JS_FILE_PATH, input_json]
+
+ try:
+ # Run the command and capture the output
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ print("stdout:", result.stdout)
+ print("stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+
+ # Check if the result is "None" or missing 'result' key
+ if js_result is not None and "result" in js_result:
+ extracted_result = js_result.get("result", None)
+ print("Extracted JavaScript result:", extracted_result)
+ return extracted_result
+ else:
+ print("JavaScript result is None or missing 'result' key.")
+ return None
+ except json.JSONDecodeError as e:
+ print("Error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+ return None
+
+ except subprocess.CalledProcessError as e:
+ print("Error executing subprocess:", e)
+ return None
+
+# Example usage
+# Example 1: Convert hexadecimal to binary
+function_name = "_hex2bin"
+arguments = ["ABAB"]
+js_result = run_js_function(function_name, arguments)
+
+# Compare with the Python result
+expected_python_result = bin(int("ABAB", 16))[2:]
+print("Expected Python Result:", expected_python_result)
+
+if js_result is not None:
+ assert js_result == expected_python_result
+else:
+ print("Test failed: JavaScript result is None or missing 'result' key.")
+
+# Example 2: Left pad a binary string
+function_name = "_padLeft"
+arguments = ["111", 32]
+js_result = run_js_function(function_name, arguments)
+
+# Example 3: Call the 'share' function
+function_name = "share"
+arguments = ["1234abc", 6, 3]
+js_result = run_js_function(function_name, arguments)
+
+# Example 4: Generate a random string
+function_name = "random"
+arguments = [32]
+js_result = run_js_function(function_name, arguments)
+
+
+
+
+# # # Example usage
+# function_name = "_hex2bin"
+# arguments = ["ABAB"]
+# js_result = run_js_function(function_name, arguments)
+# #
+# # # Compare with the Python result
+# # expected_python_result = bin(int("ABAB", 16))[2:]
+# # print("Expected Python Result:", expected_python_result)
+# #
+# # if js_result is not None:
+# # assert js_result == expected_python_result
+# # else:
+# # print("Test failed: JavaScript result is None or missing 'result' key.")
+# #
+# function_name = "_padLeft"
+# arguments = ["111", 32]
+# js_result = run_js_function(function_name, arguments)
+# #
+# #
+# function_name = "share"
+# arguments = ["1234abc", 6, 3]
+# js_result = run_js_function(function_name, arguments)
+# #
+# # # function_name = "getConfig"
+# # # arguments = []
+# # # js_result = run_js_function(function_name, arguments)
+# # #
+# # function_name = "random"
+# # arguments = [32]
+# # js_result = run_js_function(function_name, arguments)
\ No newline at end of file
diff --git a/gems/wrapperV2.js b/gems/wrapperV2.js
new file mode 100755
index 0000000..ddb14d7
--- /dev/null
+++ b/gems/wrapperV2.js
@@ -0,0 +1,74 @@
+// wrapperV2.js
+
+/*
+This is the second working version of the wrapper. accepting multiple JavaScript command for the secrets.js package.
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const inputJson = process.argv[2];
+
+ if (!inputJson) {
+ console.error("No input provided.");
+ process.exit(1);
+ }
+
+ try {
+ const inputData = JSON.parse(inputJson);
+ //console.log(typeof inputData.tasks);
+
+ // Check if inputData has a "tasks" key
+ if ("tasks" in inputData && Array.isArray(inputData.tasks)) {
+ // Loop through tasks
+ for (const task of inputData.tasks) {
+ // Check if task has a "setup" key
+ if ("setup" in task && Array.isArray(task.setup)) {
+ // Loop through setup tasks
+ for (const setupTask of task.setup) {
+ const setupFunction = setupTask.function;
+ const setupArguments = setupTask.args;
+
+ // Dynamically call the setup function
+ const setupFn = secrets[setupFunction];
+
+ if (setupFn && typeof setupFn === 'function') {
+ // Call the setup function
+ setupFn(...setupArguments);
+ } else {
+ console.log(JSON.stringify({ error: `Unknown function: ${setupFunction}` }));
+ }
+ }
+ }
+
+ // Check if task has a "start" key
+ if ("start" in task) {
+ const functionName = task.start.function;
+ const arguments = task.start.args;
+
+ // Dynamically call the main function
+ const selectedFunction = secrets[functionName];
+
+ if (selectedFunction && typeof selectedFunction === 'function') {
+ // Call the main function
+ const result = selectedFunction(...arguments);
+
+ // Format the result as a JSON object
+ const resultJson = JSON.stringify({ result });
+
+ // Print only the result to the console
+ console.log(resultJson);
+ } else {
+ console.log(JSON.stringify({ error: `Unknown function: ${functionName}` }));
+ }
+ }
+ }
+ }
+ } catch (error) {
+ console.error("Error parsing or executing:", error.message);
+ // In case of an error, print a JSON object with an "error" key
+ console.log(JSON.stringify({ error: error.message }));
+ }
+}
diff --git a/gems/wrapperV2_test.py b/gems/wrapperV2_test.py
new file mode 100755
index 0000000..da0ce77
--- /dev/null
+++ b/gems/wrapperV2_test.py
@@ -0,0 +1,151 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV2_test.py
+
+"""
+This script demonstrates the second working version of calling Node.js to execute JavaScript using a wrapper to load the secrets.js package.
+This version handles multiple commands, sent as setup and start.
+"""
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV2.js"
+
+def run_js_functions(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (dict): Dictionary containing the function name and arguments.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+ #input_json = json.dumps(input_data) #Removed this
+
+ # Enclose input_json in single quotes
+ js_command = ["node", JS_FILE_PATH, input_data]
+
+ try:
+ # Run the command and capture the output
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ #print("stdout:", result.stdout)
+ #print("stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+
+ # Check if the result is "None" or missing 'result' key
+ if js_result is not None and "result" in js_result:
+ extracted_result = js_result.get("result", None)
+ print("Extracted JavaScript result:", extracted_result)
+ return extracted_result
+ else:
+ print("JavaScript result is None or missing 'result' key.")
+ return None
+ except json.JSONDecodeError as e:
+ print("Error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+ return None
+
+ except subprocess.CalledProcessError as e:
+ print("Error executing subprocess:", e)
+ return None
+
+
+# Example usage
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = ['1234abc', 6, 3]
+
+# Main function
+main = {'function': 'share', 'args': foo}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+#print(json_data)
+
+js_result = run_js_functions(json_data)
+
+# You can uncomment the following examples if needed
+# ...
+
+
+
+# # Example usage
+# # Example 1: Convert hexadecimal to binary
+# function_name = "_hex2bin"
+# arguments = ["ABAB"]
+# js_result = run_js_function(function_name, arguments)
+#
+# # Compare with the Python result
+# expected_python_result = bin(int("ABAB", 16))[2:]
+# print("Expected Python Result:", expected_python_result)
+#
+# if js_result is not None:
+# assert js_result == expected_python_result
+# else:
+# print("Test failed: JavaScript result is None or missing 'result' key.")
+#
+# # Example 2: Left pad a binary string
+# function_name = "_padLeft"
+# arguments = ["111", 32]
+# js_result = run_js_function(function_name, arguments)
+#
+# # Example 3: Call the 'share' function
+# function_name = "share"
+# arguments = ["1234abc", 6, 3]
+# js_result = run_js_function(function_name, arguments)
+#
+# # Example 4: Generate a random string
+# function_name = "random"
+# arguments = [32]
+# js_result = run_js_function(function_name, arguments)
+
+
+
+
+# # # Example usage
+# function_name = "_hex2bin"
+# arguments = ["ABAB"]
+# js_result = run_js_function(function_name, arguments)
+# #
+# # # Compare with the Python result
+# # expected_python_result = bin(int("ABAB", 16))[2:]
+# # print("Expected Python Result:", expected_python_result)
+# #
+# # if js_result is not None:
+# # assert js_result == expected_python_result
+# # else:
+# # print("Test failed: JavaScript result is None or missing 'result' key.")
+# #
+# function_name = "_padLeft"
+# arguments = ["111", 32]
+# js_result = run_js_function(function_name, arguments)
+# #
+# #
+# function_name = "share"
+# arguments = ["1234abc", 6, 3]
+# js_result = run_js_function(function_name, arguments)
+# #
+# # # function_name = "getConfig"
+# # # arguments = []
+# # # js_result = run_js_function(function_name, arguments)
+# # #
+# # function_name = "random"
+# # arguments = [32]
+# # js_result = run_js_function(function_name, arguments)
\ No newline at end of file
diff --git a/gems/wrapperV3.js b/gems/wrapperV3.js
new file mode 100755
index 0000000..efafdf4
--- /dev/null
+++ b/gems/wrapperV3.js
@@ -0,0 +1,97 @@
+// wrapperV3.js
+
+/*
+This is the third working version of the wrapper. Better error handling and accepting multiple JavaScript command for the secrets.js package.
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const inputJson = process.argv[2];
+
+ if (!inputJson) {
+ console.error("No input provided.");
+ process.exit(1);
+ }
+
+ try {
+ const inputData = JSON.parse(inputJson);
+ const output = { results: [] };
+
+ // Check if inputData has a "tasks" key
+ if ("tasks" in inputData && Array.isArray(inputData.tasks)) {
+ // Loop through tasks
+ for (const task of inputData.tasks) {
+ const taskResult = {};
+
+ // Check if task has a "setup" key
+ if ("setup" in task && Array.isArray(task.setup)) {
+ // Loop through setup tasks
+ for (const setupTask of task.setup) {
+ const setupFunction = setupTask.function;
+ const setupArguments = setupTask.args;
+
+ // Dynamically call the setup function
+ const setupFn = secrets[setupFunction];
+
+ if (setupFn && typeof setupFn === 'function') {
+ try {
+ // Call the setup function
+ setupFn(...setupArguments);
+ taskResult.setupResult = { success: true };
+ } catch (error) {
+ // Capture and report the error to stderr
+ console.error(error.message);
+ taskResult.setupResult = { success: false, error: error.message };
+ }
+ } else {
+ // Report unknown function
+ const errorMessage = `Unknown function: ${setupFunction}`;
+ console.error(errorMessage);
+ taskResult.setupResult = { success: false, error: errorMessage };
+ }
+ }
+ }
+
+ // Check if task has a "start" key
+ if ("start" in task) {
+ const functionName = task.start.function;
+ const arguments = task.start.args;
+
+ // Dynamically call the main function
+ const selectedFunction = secrets[functionName];
+
+ if (selectedFunction && typeof selectedFunction === 'function') {
+ try {
+ // Call the main function
+ const result = selectedFunction(...arguments);
+ taskResult.startResult = { success: true, result };
+ } catch (error) {
+ // Capture and report the error to stderr
+ console.error(error.message);
+ taskResult.startResult = { success: false, error: error.message };
+ }
+ } else {
+ // Report unknown function
+ const errorMessage = `Unknown function: ${functionName}`;
+ console.error(errorMessage);
+ taskResult.startResult = { success: false, error: errorMessage };
+ }
+ }
+
+ // Add task result to the output
+ output.results.push(taskResult);
+ }
+
+ // Print the output as a JSON object
+ console.log(JSON.stringify(output));
+ }
+ } catch (error) {
+ console.error("Error parsing or executing:", error.message);
+ // In case of an error, print a JSON object with an "error" key
+ console.log(JSON.stringify({ error: error.message }));
+ }
+}
+
diff --git a/gems/wrapperV3_test.py b/gems/wrapperV3_test.py
new file mode 100755
index 0000000..ab0fbd6
--- /dev/null
+++ b/gems/wrapperV3_test.py
@@ -0,0 +1,115 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV3_test.py
+
+"""
+This script demonstrates the third working version of calling Node.js to execute JavaScript using a wrapper to load the secrets.js package.
+This version handles multiple commands, sent as setup and start. And have improved error handling.
+"""
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV3.js"
+
+def run_js_functions(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (dict): Dictionary containing the function name and arguments.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Enclose input_json in single quotes
+ js_command = ["node", JS_FILE_PATH, input_data]
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ # print("stdout:", result.stdout)
+ # print("stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+
+ # Check if the result has 'error' or 'results' key
+ if js_result is not None and "results" in js_result:
+ start_result = js_result.get("results", [])[0].get("startResult", {}).get("result")
+ if start_result is not None:
+ print("Result of 'start' function:", start_result)
+ else:
+ print("No result found for 'start' function.")
+ elif js_result is not None and "error" in js_result:
+ print("JavaScript error:", js_result.get("error"))
+ else:
+ print("JavaScript output is missing 'error' or 'results' key.")
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ except json.JSONDecodeError as e:
+ print("Error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = result.stderr.strip()
+ print("JavaScript error:", js_error)
+ return None
+
+
+# Working Example: Valid JavaScript: share('1234abc', 6, 3);
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = ['1234abc', 6, 3]
+
+# Main function
+main = {'function': 'share', 'args': foo}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+#print(json_data)
+
+js_result = run_js_functions(json_data)
+print(js_result)
+
+
+# Problem Example: Invalid JavaScript: combine(['8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2', '805191919191919191919191919083a53a5', '80667676767676767676767676776442ddb']);
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = ['8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2', '805191919191919191919191919083a53a5', '80667676767676767676767676776442ddb']
+
+# Main function
+main = {'function': 'combine', 'args': foo}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+#print(json_data)
+
+js_result = run_js_functions(json_data)
+print(js_result)
+
diff --git a/gems/wrapperV4.js b/gems/wrapperV4.js
new file mode 100755
index 0000000..b370f35
--- /dev/null
+++ b/gems/wrapperV4.js
@@ -0,0 +1,104 @@
+// wrapperV4.js
+
+/*
+A working version of JavaScript the wrapper. Better error handling and accepts multiple JavaScript commands for the secrets.js package.
+
+But there is an issue passing array data from the Python. combine(["aa", "bb", "cc"]); does not work.
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const inputJson = process.argv[2];
+
+ if (!inputJson) {
+ console.error("No input provided.");
+ process.exit(1);
+ }
+
+ try {
+ const inputData = JSON.parse(inputJson);
+ const output = { results: [] };
+
+ // Check if inputData has a "tasks" key
+ if ("tasks" in inputData && Array.isArray(inputData.tasks)) {
+ // Loop through tasks
+ for (const task of inputData.tasks) {
+ const taskResult = {};
+
+ // Check if task has a "setup" key
+ if ("setup" in task && Array.isArray(task.setup)) {
+ // Loop through setup tasks
+ for (const setupTask of task.setup) {
+ const setupFunction = setupTask.function;
+ const setupArguments = setupTask.args;
+
+ // Dynamically call the setup function
+ const setupFn = secrets[setupFunction];
+
+ if (setupFn && typeof setupFn === 'function') {
+ try {
+ // Call the setup function
+ setupFn(...setupArguments);
+ taskResult.setupResult = { success: true };
+ } catch (error) {
+ // Capture and report the error to stderr
+ console.error(error.message);
+ taskResult.setupResult = { success: false, error: error.message };
+ }
+ } else {
+ // Report unknown function
+ const errorMessage = `Unknown function: ${setupFunction}`;
+ console.error(errorMessage);
+ taskResult.setupResult = { success: false, error: errorMessage };
+ }
+ }
+ }
+
+ // Check if task has a "start" key
+ if ("start" in task) {
+ const functionName = task.start.function;
+ const arguments = task.start.args;
+
+ // Dynamically call the main function
+ const selectedFunction = secrets[functionName];
+
+ if (selectedFunction && typeof selectedFunction === 'function') {
+ try {
+ // Call the main function
+ const result = selectedFunction(...arguments);
+ //const result = secrets.combine(['8027e7e7e7e7e7e7e7e7e7e7e7e7e7e7fd5', '8037e7e7e7e7e7e7e7e7e7e7e7e7e7e7fd5', '804191919191919191919191919191918b2', '805191919191919191919191919191918b2']);
+ taskResult.startResult = { success: true, result };
+ } catch (error) {
+ // Log the full command and arguments
+ console.log(`Executing command: ${functionName}(${arguments.join(', ')})`);
+ // Capture and report the error to stderr
+ console.error(error.message);
+ taskResult.startResult = { success: false, error: error.message };
+ }
+ } else {
+ // Log the full command and arguments
+ console.log(`Executing command: ${functionName}(${arguments.join(', ')})`);
+ // Report unknown function
+ const errorMessage = `Unknown function: ${functionName}`;
+ console.error(errorMessage);
+ taskResult.startResult = { success: false, error: errorMessage };
+ }
+ }
+
+ // Add task result to the output
+ output.results.push(taskResult);
+ }
+
+ // Print the output as a JSON object
+ console.log(JSON.stringify(output));
+ }
+ } catch (error) {
+ console.error("Error parsing or executing:", error.message);
+ // In case of an error, print a JSON object with an "error" key
+ console.log(JSON.stringify({ error: error.message }));
+ }
+}
+
diff --git a/gems/wrapperV4_test.py b/gems/wrapperV4_test.py
new file mode 100755
index 0000000..819ab8b
--- /dev/null
+++ b/gems/wrapperV4_test.py
@@ -0,0 +1,125 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV4_test.py
+
+"""
+This script demonstrates the another working version, based on V3, calling Node.js to execute JavaScript using a wrapper to load the secrets.js package.
+This version handles multiple commands, sent as setup and start. And have improved error handling. But there is an issue passing array data to the JS. combine(["aa", "bb", "cc"]); does not work in the wrapper.
+"""
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV4.js"
+
+# ... (previous code)
+
+def run_js_functions(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (dict): Dictionary containing the function name and arguments.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Enclose input_json in single quotes
+ js_command = ["node", JS_FILE_PATH, input_data]
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ # print("stdout:", result.stdout)
+ # print("stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+
+ # Check if the result has 'error' or 'results' key
+ if js_result is not None and "results" in js_result:
+ start_result = js_result.get("results", [])[0].get("startResult", {}).get("result")
+ if start_result is not None:
+ print("Result of 'start' function:", start_result)
+ else:
+ print("No result found for 'start' function.")
+ elif js_result is not None and "error" in js_result:
+ print("JavaScript error:", js_result.get("error"))
+ else:
+ print("JavaScript output is missing 'error' or 'results' key.")
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ except json.JSONDecodeError as e:
+ print("Error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = result.stderr.strip()
+ print("JavaScript error:", js_error)
+ return None
+
+
+# Working Example: Valid JavaScript: share('1234abc', 6, 3);
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = ['1234abc', 6, 3]
+
+# Main function
+main = {'function': 'share', 'args': foo}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+print(tasks)
+
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+
+# Run the JavaScript functions
+js_result = run_js_functions(json_data)
+print(js_result)
+
+# Problem Example: Invalid JavaScript: combine(['8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2', '805191919191919191919191919083a53a5', '80667676767676767676767676776442ddb']);
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = [
+ '8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2',
+ '805191919191919191919191919083a53a5',
+ '80667676767676767676767676776442ddb'
+]
+
+# Main function
+main = {'function': 'combine', 'args': [foo]}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+print(tasks)
+
+# Convert the Python dictionary to JSON
+json_data = json.dumps(tasks, indent=None)
+
+# Run the JavaScript functions
+js_result = run_js_functions(json_data)
+print(js_result)
+
diff --git a/gems/wrapperV5.js b/gems/wrapperV5.js
new file mode 100755
index 0000000..32e00c0
--- /dev/null
+++ b/gems/wrapperV5.js
@@ -0,0 +1,111 @@
+// wrapperV5.js
+
+/*
+FAILED - FAILED - FAILED - FAILED - FAILED - FAILED
+
+This is the FAILED wrapper. Better error handling and accepting multiple JavaScript command for the secrets.js package.
+
+FAILED - FAILED - FAILED - FAILED - FAILED - FAILED
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const inputJson = process.argv[2];
+
+ if (!inputJson) {
+ console.error("No input provided.");
+ process.exit(1);
+ }
+
+ try {
+ const inputData = JSON.parse(inputJson);
+ const output = { results: [] };
+
+ // Check if inputData has a "tasks" key
+ if ("tasks" in inputData && Array.isArray(inputData.tasks)) {
+ // Loop through tasks
+ for (const task of inputData.tasks) {
+ const taskResult = {};
+
+ // Check if task has a "setup" key
+ if ("setup" in task && Array.isArray(task.setup)) {
+ // Loop through setup tasks
+ for (const setupTask of task.setup) {
+ const setupFunction = setupTask.function;
+ const setupArguments = setupTask.args;
+
+ // Dynamically call the setup function
+ const setupFn = secrets[setupFunction];
+
+ if (setupFn && typeof setupFn === 'function') {
+ try {
+ // Call the setup function
+ setupFn(...setupArguments);
+ taskResult.setupResult = { success: true };
+ } catch (error) {
+ // Capture and report the error to stderr
+ console.error(error.message);
+ taskResult.setupResult = { success: false, error: error.message };
+ }
+ } else {
+ // Report unknown function
+ const errorMessage = `Unknown function: ${setupFunction}`;
+ console.error(errorMessage);
+ taskResult.setupResult = { success: false, error: errorMessage };
+ }
+ }
+ }
+
+ // Check if task has a "start" key
+ if ("start" in task) {
+ const functionName = task.start.function;
+ const arguments = task.start.args;
+
+ // Dynamically call the main function
+ const selectedFunction = secrets[functionName];
+
+ if (selectedFunction && typeof selectedFunction === 'function') {
+ try {
+ // Check if the argument is a dictionary with 'arrayArg'
+ if (arguments && typeof arguments === 'object' && 'arrayArg' in arguments) {
+ // Extract the array from the dictionary
+ const arrayArg = arguments.arrayArg;
+ //console.error(arguments.arrayArg);
+ // Call the main function with the array argument
+ const result = selectedFunction(arrayArg);
+ taskResult.startResult = { success: true, result };
+ } else {
+ // Call the main function with the provided arguments
+ const result = selectedFunction(...arguments);
+ taskResult.startResult = { success: true, result };
+ }
+ } catch (error) {
+ // Capture and report the error to stderr
+ console.error(error.message);
+ taskResult.startResult = { success: false, error: error.message };
+ }
+ } else {
+ // Report unknown function
+ const errorMessage = `Unknown function: ${functionName}`;
+ console.error(errorMessage);
+ taskResult.startResult = { success: false, error: errorMessage };
+ }
+ }
+
+ // Add task result to the output
+ output.results.push(taskResult);
+ }
+
+ // Print the output as a JSON object
+ console.log(JSON.stringify(output));
+ }
+ } catch (error) {
+ console.error("Error parsing or executing:", error.message);
+ // In case of an error, print a JSON object with an "error" key
+ console.log(JSON.stringify({ error: error.message }));
+ }
+}
+
diff --git a/gems/wrapperV5_test.py b/gems/wrapperV5_test.py
new file mode 100755
index 0000000..127ac87
--- /dev/null
+++ b/gems/wrapperV5_test.py
@@ -0,0 +1,111 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV5_test.py
+
+"""
+FAILED - FAILED - FAILED - FAILED - FAILED - FAILED
+This script FAILED, based on V3, calling Node.js to execute JavaScript using a wrapper to load the secrets.js package.
+This version handles multiple commands, sent as setup and start. And have improved error handling. Failed attempt to pass array data to the JS. combine(["aa", "bb", "cc"]); does not work in the wrapper.
+FAILED - FAILED - FAILED - FAILED - FAILED - FAILED
+"""
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV5.js"
+
+def run_js_functions(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (dict): Dictionary containing the function name and arguments.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Convert the Python dictionary to JSON
+ json_data = json.dumps(input_data, indent=None)
+
+ # Run the command and capture the output and stderr
+ js_command = ["node", JS_FILE_PATH, json_data]
+
+ try:
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ # print("stdout:", result.stdout)
+ # print("stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+
+ # Check if the result has 'error' or 'results' key
+ if js_result is not None and "results" in js_result:
+ start_result = js_result.get("results", [])[0].get("startResult", {}).get("result")
+ if start_result is not None:
+ print("Result of 'start' function:", start_result)
+ else:
+ print("No result found for 'start' function.")
+ elif js_result is not None and "error" in js_result:
+ print("JavaScript error:", js_result.get("error"))
+ else:
+ print("JavaScript output is missing 'error' or 'results' key.")
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ except json.JSONDecodeError as e:
+ print("Error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = result.stderr.strip()
+ print("JavaScript error:", js_error)
+ return None
+
+
+# Working Example: Valid JavaScript: share('1234abc', 6, 3);
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = ['1234abc', 6, 3]
+
+# Main function
+main = {'function': 'share', 'args': foo}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+js_result = run_js_functions(tasks)
+print(js_result)
+
+
+# Problem Example: Invalid JavaScript: combine(['8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2', '805191919191919191919191919083a53a5', '80667676767676767676767676776442ddb']);
+# Setup commands
+setup = [
+ {'function': 'setRNG', 'args': ['testRandom']},
+]
+
+# Dynamic Values
+foo = {'arrayArg': ['8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2', '805191919191919191919191919083a53a5', '80667676767676767676767676776442ddb']}
+
+# Main function
+main = {'function': 'combine', 'args': foo}
+
+# Combine setup and main
+tasks = {'tasks': [{'setup': setup, 'start': main}]}
+
+js_result = run_js_functions(tasks)
+print(js_result)
+
diff --git a/gems/wrapperV6.js b/gems/wrapperV6.js
new file mode 100755
index 0000000..68fa07a
--- /dev/null
+++ b/gems/wrapperV6.js
@@ -0,0 +1,85 @@
+// wrapperV6.js
+
+/*
+This is the third working version of the wrapper. Better error handling and accepting multiple JavaScript commands for the secrets.js package.
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const inputJson = process.argv[2];
+
+ if (!inputJson) {
+ console.error("No input provided.");
+ process.exit(1);
+ }
+
+ let lastResult = null;
+
+ try {
+ const inputData = parseStringArray(inputJson);
+ //const inputData = inputJson;
+ //console.log("Commands received from Python: inputJSON: ", inputJson);
+ console.log("Commands received from Python:", inputData);
+
+ //jsonn = inputData.split(",");
+ //console.log("Three: ", jsonn[2]);
+
+ // Check if inputData is an array
+ if (Array.isArray(inputData)) {
+ // Loop through input data
+ for (const command of inputData) {
+ // Extract function name and arguments
+ const functionName = command[0];
+ const args = command.slice(1);
+
+ // Dynamically call the function
+ const selectedFunction = secrets[functionName];
+
+ if (selectedFunction && typeof selectedFunction === 'function') {
+ try {
+ // Call the function with arguments
+ lastResult = selectedFunction(...args);
+ } catch (error) {
+ // Capture and report the error to stderr
+ console.error(error.message);
+ }
+ } else {
+ // Report unknown function
+ const errorMessage = `Unknown function: ${functionName}`;
+ console.error(errorMessage);
+ }
+ }
+
+ // Print the result of the last command
+ console.log(JSON.stringify(lastResult));
+ }
+ } catch (error) {
+ console.error("Error parsing or executing:", error.message);
+ // In case of an error, print a JSON object with an "error" key
+ console.log(JSON.stringify({ error: error.message }));
+ }
+}
+
+
+function parseStringArray(inputString) {
+ // Remove the opening and closing brackets and split the string by '], ['
+ var arrayStr = inputString.slice(1, -1);
+ var arrayItems = arrayStr.split(/\], \[/);
+
+ // Iterate over each item and remove escape characters
+ var parsedArray = arrayItems.map(item => {
+ // Remove leading and trailing quotes
+ item = item.replace(/^"/, '').replace(/"$/, '');
+
+ // Replace escaped single quotes with single quotes
+ item = item.replace(/\\'/g, "'");
+
+ return [item];
+ });
+
+ // Return the parsed array
+ return parsedArray;
+}
diff --git a/gems/wrapperV6_test.py b/gems/wrapperV6_test.py
new file mode 100755
index 0000000..90626b3
--- /dev/null
+++ b/gems/wrapperV6_test.py
@@ -0,0 +1,181 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV6_test.py
+
+"""
+This script demonstrates the third working version of calling Node.js to execute JavaScript using a wrapper to load the secrets.js package.
+This version handles multiple commands, sent as setup and start. And have improved error handling.
+"""
+
+import json
+import subprocess
+import ast
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV6.js"
+
+def wrapper(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (dict): Dictionary containing the function name and arguments.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Enclose input_json in single quotes
+ js_command = ["node", JS_FILE_PATH, input_data]
+ print("Input data sent to JavaScript:", input_data)
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ print("Result stdout:", result.stdout)
+ print("Result stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+ print('json.loads')
+
+ # Check if the result has 'error' or 'results' key
+ if js_result is not None and "results" in js_result:
+ start_result = js_result.get("results", [])[0].get("startResult", {}).get("result")
+ if start_result is not None:
+ return(start_result)
+ else:
+ print("No result found for 'start' function.")
+ elif js_result is not None and "error" in js_result:
+ print("JavaScript error:", js_result.get("error"))
+ else:
+ print("JavaScript output is missing 'error' or 'results' key.")
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ except json.JSONDecodeError as e:
+ print("Python error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = result.stderr.strip()
+ print("JavaScript error:", js_error)
+ return None
+
+class JsFunction:
+ def __init__(self, func, test=False):
+ self.func = func
+ self.test = test
+
+ def __call__(self, *args, test=False, **kwargs):
+ def wrapped_func(*args, **kwargs):
+ args_str = ', '.join(repr(arg) for arg in args)
+ #kwargs_str = ', '.join(f'{key}={repr(value)}'
+ # for key, value in kwargs.items())
+ #all_args = ', '.join(filter(None, [args_str, kwargs_str]))
+
+ return f"{self.func.__name__}({args_str})"
+
+ data = []
+
+ # DO NOT REMOVE THIS
+ if test or self.test:
+ data.append("setRNG('testRandom')")
+
+ data.append(wrapped_func(*args, **kwargs) if args else self.func(*args, **kwargs))
+ return data
+
+ def __get__(self, instance, owner):
+ return self if instance is None else types.MethodType(self, instance)
+
+@JsFunction
+def init(*args, **kwargs):
+ pass
+
+@JsFunction
+def setRNG(*args, **kwargs):
+ pass
+
+@JsFunction
+def share(*args, **kwargs):
+ pass
+
+
+
+alpha = init(33)
+bravo = setRNG("testRandom")
+delta = share('1234abc', 6, 3)
+
+
+# Combine
+tasks = [
+ alpha,
+ bravo,
+ delta,
+ share(["aaa"],["bbb"], ["ccc"])
+]
+
+print("Tasks: ", tasks)
+
+#tasks = delta
+
+json_data = json.dumps(tasks, indent=None)
+#print("JSON Data: ", json_data) # [["init(33)"], ["setRNG('testRandom')"], ["share('1234abc', 6, 3)"]]
+
+
+js_result = wrapper(json_data)
+print(js_result)
+
+# # Working Example: Valid JavaScript: share('1234abc', 6, 3);
+# # Setup commands
+# setup = [
+# {'function': 'setRNG', 'args': ['testRandom']},
+# ]
+#
+# # Dynamic Values
+# foo = ['1234abc', 6, 3]
+#
+# # Main function
+# main = {'function': 'share', 'args': foo}
+#
+# # Combine setup and main
+# tasks = {'tasks': [{'setup': setup, 'start': main}]}
+#
+# # Convert the Python dictionary to JSON
+# json_data = json.dumps(tasks, indent=None)
+# #print(json_data)
+#
+# js_result = run_js_functions(json_data)
+# print(js_result)
+#
+#
+# # Problem Example: Invalid JavaScript: combine(['8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2', '805191919191919191919191919083a53a5', '80667676767676767676767676776442ddb']);
+# # Setup commands
+# setup = [
+# {'function': 'setRNG', 'args': ['testRandom']},
+# ]
+#
+# # Dynamic Values
+# foo = ['8027e7e7e7e7e7e7e7e7e7e7e7e6f5d34c2', '805191919191919191919191919083a53a5', '80667676767676767676767676776442ddb']
+#
+# # Main function
+# main = {'function': 'combine', 'args': foo}
+#
+# # Combine setup and main
+# tasks = {'tasks': [{'setup': setup, 'start': main}]}
+#
+# # Convert the Python dictionary to JSON
+# json_data = json.dumps(tasks, indent=None)
+# #print(json_data)
+#
+# js_result = run_js_functions(json_data)
+# print(js_result)
+
diff --git a/gems/wrapperV7.js b/gems/wrapperV7.js
new file mode 100755
index 0000000..38f3f1c
--- /dev/null
+++ b/gems/wrapperV7.js
@@ -0,0 +1,36 @@
+// wrapperV7.js
+
+/*
+This is the third working version of the wrapper. Better error handling and accepting multiple JavaScript commands for the secrets.js package.
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const inputJson = process.argv[2];
+
+ if (!inputJson) {
+ console.error("No input provided.");
+ process.exit(1);
+ }
+
+ try {
+ const inputData = JSON.parse(inputJson);
+ console.log("Commands received from Python:", inputData);
+
+ // Check if inputData is an array
+ if (Array.isArray(inputData)) {
+ // Loop through input data
+ for (const command of inputData) {
+ // Evaluate each command
+ eval(command);
+ }
+ }
+ } catch (error) {
+ console.error("Error parsing or executing:", error.message);
+ // In case of an error, print a JSON object with an "error" key
+ console.log(JSON.stringify({ error: error.message }));
+ }
+}
diff --git a/gems/wrapperV7_test.py b/gems/wrapperV7_test.py
new file mode 100755
index 0000000..1644bd6
--- /dev/null
+++ b/gems/wrapperV7_test.py
@@ -0,0 +1,67 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV7_test.py
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV7.js"
+
+def wrapper(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (list): List containing the function calls as strings.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Convert the list to JSON string
+ json_data = json.dumps(input_data)
+ print("Input data sent to JavaScript:", json_data)
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(["node", JS_FILE_PATH, json_data], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ print("Result stdout:", result.stdout)
+ print("Result stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+ print('json.loads')
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ return js_result
+
+ except json.JSONDecodeError as e:
+ print("Python error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = result.stderr.strip()
+ print("JavaScript error:", js_error)
+ return None
+
+# Define tasks
+tasks = [
+ "init(33)",
+ "setRNG('testRandom')",
+ "share('1234abc', 6, 3)",
+ "share(['aaa'], ['bbb'], ['ccc'])"
+]
+
+# Call the wrapper function
+js_result = wrapper(tasks)
+print(js_result)
diff --git a/gems/wrapperV8.js b/gems/wrapperV8.js
new file mode 100755
index 0000000..5898590
--- /dev/null
+++ b/gems/wrapperV8.js
@@ -0,0 +1,31 @@
+// wrapperV8.js
+
+/*
+This is the third working version of the wrapper. Better error handling and accepting multiple JavaScript commands for the secrets.js package.
+*/
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const commands = process.argv.slice(2);
+
+ if (!commands.length) {
+ console.error("No commands provided.");
+ process.exit(1);
+ }
+
+ try {
+ console.log("Commands received from Python:", commands);
+
+ // Loop through commands
+ for (const command of commands) {
+ // Evaluate each command
+ eval(command);
+ }
+ } catch (error) {
+ console.error("Error executing command:", error.message);
+ process.exit(1);
+ }
+}
diff --git a/gems/wrapperV8_test.py b/gems/wrapperV8_test.py
new file mode 100755
index 0000000..ee9af7c
--- /dev/null
+++ b/gems/wrapperV8_test.py
@@ -0,0 +1,65 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV8_test.py
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV6.js"
+
+def wrapper(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (list): List containing the function calls as strings.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(["node", JS_FILE_PATH] + input_data, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ print("Input data sent to JavaScript:", input_data)
+
+ # Debugging statement to print stdout and stderr
+ print("Result stdout:", result.stdout)
+ print("Result stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+ print('json.loads')
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ return js_result
+
+ except json.JSONDecodeError as e:
+ print("Python error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = result.stderr.strip()
+ print("JavaScript error:", js_error)
+ return None
+
+# Define tasks
+tasks = [
+ "init(33)",
+ "setRNG('testRandom')",
+ "share('1234abc', 6, 3)",
+ "share(['aaa'], ['bbb'], ['ccc'])"
+]
+
+# Call the wrapper function
+js_result = wrapper(tasks)
+print(js_result)
diff --git a/gems/wrapperV9.js b/gems/wrapperV9.js
new file mode 100755
index 0000000..06f1cd0
--- /dev/null
+++ b/gems/wrapperV9.js
@@ -0,0 +1,64 @@
+// wrapperV9.js
+
+/*
+This is the third working version of the wrapper. Better error handling and accepting multiple JavaScript commands for the secrets.js package.
+*/
+
+// Used to decode the CLI arg
+// function decodeFromBase36(base36String) {
+// const decodedData = {};
+// while (base36String.length > 0) {
+// const key = base36String.substring(0, 4);
+// const value = parseInt(base36String.substring(4, 6), 36);
+// decodedData[key] = value;
+// base36String = base36String.substring(6);
+// }
+// return decodedData;
+// }
+
+function hex2a(hex)
+{
+ var str = '';
+ for (var i = 0; i < hex.length; i += 2)
+ str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+ return str;
+}
+
+function escapeSingleQuotes(str) {
+ return str.replace(/'/g, "\\'");
+}
+
+// Require the secrets package and assign it to a variable
+const secrets = require('../secrets.js/secrets.js');
+
+// If the script is executed directly, call the appropriate function based on arguments
+if (require.main === module) {
+ const commands = hex2a(process.argv[2]); // Change here
+
+ if (!commands.length) {
+ console.error("No commands provided.");
+ process.exit(1);
+ }
+
+ try {
+
+ console.log("Commands received from Python:", commands);
+
+ //return commands;
+ const inputData = JSON.parse(commands);
+ //cleanup = escapeSingleQuotes(commands);
+ //console.log("Cleanup: ", cleanup);
+ //inputData = JSON.parse(cleanup);
+ //inputData = JSON.parse(commands);
+ console.log("inputData[1][0]: ", inputData[1][0]);
+
+ // Loop through commands
+// for (const command of commands) {
+ // Evaluate each command
+// eval(command);
+// }
+ } catch (error) {
+ console.error("Error executing command:", error.message);
+ process.exit(1);
+ }
+}
diff --git a/gems/wrapperV9_test.py b/gems/wrapperV9_test.py
new file mode 100755
index 0000000..2b9fb78
--- /dev/null
+++ b/gems/wrapperV9_test.py
@@ -0,0 +1,135 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+# vim: set et sw=4 fenc=utf-8:
+#
+# wrapperV9_test.py
+
+import json
+import subprocess
+
+# Path to the Node.js wrapper script
+JS_FILE_PATH = "wrapperV9.js"
+
+def wrapper(input_data):
+ """
+ Run a JavaScript function using the Node.js wrapper.
+
+ Args:
+ input_data (list): List containing the function calls as strings.
+
+ Returns:
+ The result of the JavaScript function or None if there is an error.
+ """
+
+ # Enclose input_json in single quotes
+ js_command = ["node", JS_FILE_PATH, input_data]
+
+ try:
+ # Run the command and capture the output and stderr
+ result = subprocess.run(js_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True)
+
+ # Debugging statement to print stdout and stderr
+ # print("stdout:", result.stdout)
+ # print("stderr:", result.stderr)
+
+ #print("Input data sent to JavaScript:", input_data)
+
+ # Debugging statement to print stdout and stderr
+ print("Result stdout:", result.stdout)
+ print("Result stderr:", result.stderr)
+
+ try:
+ # Attempt to load the entire stdout as JSON
+ js_result = json.loads(result.stdout)
+ print('json.loads')
+
+ # Print stderr if it exists
+ if result.stderr:
+ print("JavaScript stderr:", result.stderr)
+
+ return js_result
+
+ except json.JSONDecodeError as e:
+ print("Python error decoding JSON:", e)
+ print("Raw stdout content:", result.stdout)
+
+ except subprocess.CalledProcessError as e:
+ # Print the error from the JavaScript script
+ js_error = e.stderr.strip() # Use e.stderr instead of result.stderr
+ print("JavaScript error:", js_error)
+ return None
+
+'''
+Used to pass a "clean" string as an arg to the CLI
+'''
+def encode_to_base36(data):
+ base36_string = ""
+ for key, value in data.items():
+ base36_string += key + str(value)
+ return base36_string
+
+class JsFunction:
+ def __init__(self, func, test=False):
+ self.func = func
+ self.test = test
+
+ def __call__(self, *args, test=False, **kwargs):
+ def wrapped_func(*args, **kwargs):
+ args_str = ', '.join(repr(arg) for arg in args)
+ #kwargs_str = ', '.join(f'{key}={repr(value)}'
+ # for key, value in kwargs.items())
+ #all_args = ', '.join(filter(None, [args_str, kwargs_str]))
+
+ return f"{self.func.__name__}({args_str})"
+
+ data = []
+
+ # DO NOT REMOVE THIS
+ if test or self.test:
+ data.append("setRNG('testRandom')")
+
+ data.append(wrapped_func(*args, **kwargs) if args else self.func(*args, **kwargs))
+ return data
+
+ def __get__(self, instance, owner):
+ return self if instance is None else types.MethodType(self, instance)
+
+@JsFunction
+def init(*args, **kwargs):
+ pass
+
+@JsFunction
+def setRNG(*args, **kwargs):
+ pass
+
+@JsFunction
+def share(*args, **kwargs):
+ pass
+
+
+
+alpha = init(33)
+bravo = setRNG("testRandom")
+delta = share('1234abc', 6, 3)
+
+
+# Combine
+tasks = [
+ alpha,
+ bravo,
+ delta,
+ share(["aaa"],["bbb"], ["ccc"])
+]
+
+print("Tasks: ", tasks)
+
+
+
+json_data = json.dumps(tasks, indent=None).replace("'", "`")
+#print(json_data)
+#print(json_data.encode().hex())
+data = json_data.encode().hex()
+#print(data)
+# Call the wrapper function
+js_result = wrapper(data)
+#print(js_result)
diff --git a/mkdocs.yml b/mkdocs.yml
index 8dfbd28..6ed6769 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,4 +1,8 @@
site_name: js2pysecrets
theme: readthedocs
docs_dir: docs_source
-site_dir: docs
\ No newline at end of file
+site_dir: docs
+nav:
+ - 'index.md'
+ - 'gems.md'
+ - 'license.md'
\ No newline at end of file