import os
import re
import json
import errno
import codecs

_SEMANTIC_VERSION = "2.0.0"

"""
Simple assert utils to make sure that an object matches some specified type
or the items in an iterable match some specified type

The main difference between using this function and using assert isinstance(...)
is that it provides a more in-depth error message

Running unit testing: `python3 -m unittest discover -s unittests`
"""

def assert_type(checked_object, *valid_types, additional_message=None, optional=False):
    """
    Checks whether an object is an instance of any of the valid types

    Args:
        checked_object (any)
        valid_types (any)
        additional_message (str or None)
        optional (bool): Whether the object can be a None object or not
    """
    assert isinstance(additional_message, str) or additional_message is None
    assert isinstance(optional, bool)

    if not (isinstance(checked_object, valid_types) or (optional and checked_object is None)):
        if len(valid_types) == 1:
            checked_types_str = f"{valid_types[0]}"
        else:
            checked_types_str = f"one of {valid_types}"

        if optional:
            checked_types_str += " or None"

        full_message = f"Expected type of {checked_object!r} to be {checked_types_str} but got {type(checked_object)}"
        #full_message = f"Expected type of {type(checked_object)} to be {checked_types_str} but got {type(checked_object)}"
        if additional_message is not None:
            full_message += f" {additional_message}"
        raise AssertionError(full_message)

def assert_iterable_types(checked_iterable, *valid_types, duplicate_key=None):
    """
    Checks whether all objects in a iterable are instances of one of the valid types

    Args:
        checked_iterable (iterable)
        valid_types (any)
        duplicate_key (None or callable): A function to give the value to check for duplicates
            Note that if you want to detect duplicates with itself, just do `duplicate_key=lambda x: x`
            If the option is None, no duplicate checking will be done

    """
    for index, item in enumerate(checked_iterable):
        assert_type(item, *valid_types, additional_message=f"in index {index} of iterable {checked_iterable}")

    # checks for duplicates
    if duplicate_key is not None:
        assert callable(duplicate_key), "The duplicate key must be a function"

        # uses a set because only the containment of an item matters
        found_objects = set()

        # iterates through each checked object to see if its within the found objects
        for checked_object in checked_iterable:
            result_object = duplicate_key(checked_object)
            # assert result_object not in found_objects, f"Found a duplicate of {result_object!r} in iterable {checked_iterable}"
            assert result_object not in found_objects, f"Found a duplicate of {result_object!r} in {checked_object!r}"
            found_objects.add(result_object)

def assert_list_types(checked_list, *valid_types, **kwargs):
    assert_type(checked_list, list)
    assert_iterable_types(checked_list, *valid_types, **kwargs)

def assert_tuple_types(checked_tuple, *valid_types, **kwargs):
    assert_type(checked_tuple, tuple)
    assert_iterable_types(checked_tuple, *valid_types, **kwargs)

"""
Utils to change the message of an exception
"""

def exc_add_msg(e: Exception, message: str, sep=" "):
    """
    Args:
        e (Exception): The exception to add a message to
        message (str): The message to be added to the exception
    """

    args = list(e.args)
    assert args, "You can only add a message if a message exists"
    args[-1] += sep + message
    e.args = tuple(args)


def exc_set_msg(e: Exception, message: str):
    """
    Args:
        e (Exception): The exception to set a message to
        message (str): The message to be set to the exception
    """
    e.args = (message,)


def make_dirs(file_path, is_dir_path=False):
    """
    Makes the directories if the directories to the file path does not exist

    Args:
        file_path (str): the path-like object to the file
        is_dir_path (bool): whether the file path is actually a directory path or not
            This will make the last basename directory instead of skipping it.

    Answer comes from:
        https://stackoverflow.com/a/12517490
    """
    dir_path = os.path.realpath((file_path if is_dir_path else os.path.dirname(file_path)))

    if not os.path.exists(dir_path):
        try:
            os.makedirs(dir_path)
        except OSError as e: # Guard against race condition
            # whereas errno is an error number, so this is just comparing a specific integer
            if e.errno != errno.EEXIST:
                raise


_alpha = re.compile("[A-Za-z_]")
_json_number = re.compile(r"-?(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?")
_nbt_float = re.compile(r"-?(0|[1-9]\d*)(\.\d+)([eE][+-]?\d+)?")

def is_json_number(string):
    """
    json_number ::= ("-")? && INT && ("." && INT)? && (["e", "E"] && ["+", "-"] && INT)?
    Follwing the picture for a general json number:
        http://www.json.org/number.gif
    """
    return bool(re.fullmatch(_json_number, string))

def is_number(string):
    """
    Checks whether the string has a proper signed number format for minecraft

    Args:
        string

    Returns:
        bool
    """

    try:
        float(string)
    except ValueError:
        return False

    # checks whether there is an alphabetical value is inside the number
    if re.search(_alpha, string) is not None:
        return False
    return True

def is_signed_int(num_str):
    """
    Args:
        num_str (str): The string that is checked to see if it represents a number

    Returns:
        bool
    """
    # if the num_str is a digit, that means that there are no special characters within the num_str
    # therefore making it a nonneg int
    # to check if it is a signed integer, the string is checked for one "-" and then the rest being the format of a nonneg int

    assert isinstance(num_str, str)
    return num_str.isdigit() or (num_str.startswith("-") and num_str[1:].isdigit())

def is_nonneg_int(num_str):
    """
    Args:
        num_str (str): The string that is checked to see if it represents a nonneg integer

    Returns:
        bool
    """

    assert isinstance(num_str, str)
    return num_str.isdigit()

def is_pos_int(num_str):
    """
    Args:
        num_str (str): The string that is checked to see if it represents a positive integer (not 0)

    Returns:
        bool
    """

    assert isinstance(num_str, str)
    if num_str.isdigit():
        return int(num_str) != 0
    return False


"""
http://python-3-patterns-idioms-test.readthedocs.io/en/latest/PythonDecorators.html
http://jfine-python-classes.readthedocs.io/en/latest/decorators.html

Syntax of a decorator on a class:
    @decorator
    class A:
        ...
    a = A()

is equal to
    class A:
        ...
    a = decorator(A)
"""

def addrepr(cls):
    """
    Decorator meant to be used on classes to set a __repr__ method
    that contains all variables of the classes
    """
    def __repr__(self):
        # `type(self)` is used instead of `cls` because `cls` only refers to the most parent object if inherited
        # while `type(self)` guarantees to get the class name of the current class
        class_name = type(self).__name__

        variables = []
        for variable, value in vars(self).items():
            variables.append(f"{variable}={value!r}")
        variables_str = ", ".join(variables)

        return f"{class_name}[{variables_str}]"

    # sets the __repr__ method as the defined __repr__ because methods can be defined outside classes
    # take that 1st year university test questions
    cls.__repr__ = __repr__

    # returns itself because of decorator(class) syntax
    return cls



class Singleton:
    """
    Singleton class based off of:
        https://colab.research.google.com/drive/1eajT5Rl9tA-7RmSHMME54B81U5aSKSni#scrollTo=nfQZINGxuUdK

    Sets its own attributes based off of:
        https://stackoverflow.com/questions/2466191/set-attributes-from-dictionary-in-python
    """

    def __new__(cls, *args, **kwargs):
        attr_name = f"_{cls.__name__}"
        if not hasattr(cls, attr_name):
            try:
                # generally for namedtuple, which works even if no args/kwargs are given
                attribute = super().__new__(cls, *args, **kwargs)
            except TypeError as e:
                if e.args[0] == "object() takes no parameters":
                    # for a regular object that has an __init__
                    attribute = super().__new__(cls)
                else:
                    exc_add_msg(e, f'with class {cls.__qualname__}')
                    raise

            setattr(cls, attr_name, attribute)
        return getattr(cls, attr_name)

"""
Simply provides the encode/decode function to turn a literal string into a regular string and back
"""

def decode_str(string):
    r"""
    Removes the quotations around a string, replaces double \\ with \, and replaces
    any specific character representation starting with \ with its true character
    (eg. \n turns to a newline)
    """
    if not len(string) >= 2:
        raise SyntaxError(f"Expected the string {string!r} to be longer than two characters so it can begin and end with a quotation")
    if not string.startswith('"'):
        raise SyntaxError(f"Expected the string {string!r} to begin with a quotation")
    if not string.endswith('"'):
        raise SyntaxError(f"Expected the string {string!r} to end with a quotation")

    return codecs.decode(string[1:-1], "unicode_escape")

def encode_str(string):
    r"""
    Surrounds the string with (double) quotes and replaces any characters with backslashes
    to their character representations
    """
    return '"' + codecs.encode(string, "unicode_escape").decode("utf-8") + '"'


if __name__ == "__main__":
    pass


class JsonStruct:
    """
    Stores all custom variables under an internal _dict attribute

    These attributes can be accessed through indexing like a dictionary or calling them as attributes.
    """

    def __init__(self, json_data, globals=None):
        # dict comprehension to wrap all values of the dictionary
        self._data = {key: _wrap(value, globals=globals) for key, value in json_data.items()}

    def __getattr__(self, item):
        # prevents recursion
        if item == "_data":
            return self.__dict__[item]

        return self._data[item]

    def __setattr__(self, key, value):
        if key == "_data":
            if "_data" not in self.__dict__:
                data = {}
                self.__dict__[key] = data
            self.__dict__[key] = value
        else:
            self.__dict__["_data"][key] = value

    def __getitem__(self, key):
        return self._data[key]

    def __setitem__(self, key, value):
        self._data[key] = value

    def __len__(self):
        return len(self._data)

    def __iter__(self):
        return iter(self._data)

    def __contains__(self, item):
        return item in self._data

    def __repr__(self):
        class_name = type(self).__name__

        variables = []
        for variable, value in items(self):
            variables.append(f"{variable}={value!r}")
        variables_str = ", ".join(variables)

        return f"{class_name}[{variables_str}]"


# All of the following methods are not methods of the JsonStruct class
# to prevent any item collisions
def _wrap(data, globals=None):
    """
    Recursive function to visit all inside a list and dictionary
    """
    if isinstance(data, list):
        # visits all items in the list
        return [_wrap(value, globals=globals) for value in data]

    if isinstance(data, dict):
        return JsonStruct(data, globals=globals)

    if isinstance(data, str) and data.startswith("$(") and data.endswith(")"):
        # pylint: disable=eval-used
        return eval(data[2:-1], globals)

    return data


def to_json(json_struct):
    json_dict = {}
    for key, value in items(json_struct):
        json_dict[key] = _wrap_json(value)

    return json_dict

def _wrap_json(data):
    if isinstance(data, (list)):
        return [_wrap_json(value) for value in data]

    if isinstance(data, JsonStruct):
        return to_json(data)

    return data


def items(json_struct):
    """
    Gets all items of the json_struct
    """
    return json_struct._data.items()

def keys(json_struct):
    """
    Gets all the variable names of the json_struct
    """
    return json_struct._data.keys()

def values(json_struct):
    """
    Gets all values of all variables of the json struct
    """
    return json_struct._data.values()

def pop(json_struct, item):
    """
    Removes the item
    """
    return json_struct._data.pop(item)





import os
import re
import json
import errno
import codecs

_SEMANTIC_VERSION = "2.0.0"

"""
Simple assert utils to make sure that an object matches some specified type
or the items in an iterable match some specified type

The main difference between using this function and using assert isinstance(...)
is that it provides a more in-depth error message

Running unit testing: `python3 -m unittest discover -s unittests`
"""

def assert_type(checked_object, *valid_types, additional_message=None, optional=False):
    """
    Checks whether an object is an instance of any of the valid types

    Args:
        checked_object (any)
        valid_types (any)
        additional_message (str or None)
        optional (bool): Whether the object can be a None object or not
    """
    assert isinstance(additional_message, str) or additional_message is None
    assert isinstance(optional, bool)

    if not (isinstance(checked_object, valid_types) or (optional and checked_object is None)):
        if len(valid_types) == 1:
            checked_types_str = f"{valid_types[0]}"
        else:
            checked_types_str = f"one of {valid_types}"

        if optional:
            checked_types_str += " or None"

        full_message = f"Expected type of {checked_object!r} to be {checked_types_str} but got {type(checked_object)}"
        #full_message = f"Expected type of {type(checked_object)} to be {checked_types_str} but got {type(checked_object)}"
        if additional_message is not None:
            full_message += f" {additional_message}"
        raise AssertionError(full_message)

def assert_iterable_types(checked_iterable, *valid_types, duplicate_key=None):
    """
    Checks whether all objects in a iterable are instances of one of the valid types

    Args:
        checked_iterable (iterable)
        valid_types (any)
        duplicate_key (None or callable): A function to give the value to check for duplicates
            Note that if you want to detect duplicates with itself, just do `duplicate_key=lambda x: x`
            If the option is None, no duplicate checking will be done

    """
    for index, item in enumerate(checked_iterable):
        assert_type(item, *valid_types, additional_message=f"in index {index} of iterable {checked_iterable}")

    # checks for duplicates
    if duplicate_key is not None:
        assert callable(duplicate_key), "The duplicate key must be a function"

        # uses a set because only the containment of an item matters
        found_objects = set()

        # iterates through each checked object to see if its within the found objects
        for checked_object in checked_iterable:
            result_object = duplicate_key(checked_object)
            # assert result_object not in found_objects, f"Found a duplicate of {result_object!r} in iterable {checked_iterable}"
            assert result_object not in found_objects, f"Found a duplicate of {result_object!r} in {checked_object!r}"
            found_objects.add(result_object)

def assert_list_types(checked_list, *valid_types, **kwargs):
    assert_type(checked_list, list)
    assert_iterable_types(checked_list, *valid_types, **kwargs)

def assert_tuple_types(checked_tuple, *valid_types, **kwargs):
    assert_type(checked_tuple, tuple)
    assert_iterable_types(checked_tuple, *valid_types, **kwargs)

"""
Utils to change the message of an exception
"""

def exc_add_msg(e: Exception, message: str, sep=" "):
    """
    Args:
        e (Exception): The exception to add a message to
        message (str): The message to be added to the exception
    """

    args = list(e.args)
    assert args, "You can only add a message if a message exists"
    args[-1] += sep + message
    e.args = tuple(args)


def exc_set_msg(e: Exception, message: str):
    """
    Args:
        e (Exception): The exception to set a message to
        message (str): The message to be set to the exception
    """
    e.args = (message,)


def make_dirs(file_path, is_dir_path=False):
    """
    Makes the directories if the directories to the file path does not exist

    Args:
        file_path (str): the path-like object to the file
        is_dir_path (bool): whether the file path is actually a directory path or not
            This will make the last basename directory instead of skipping it.

    Answer comes from:
        https://stackoverflow.com/a/12517490
    """
    dir_path = os.path.realpath((file_path if is_dir_path else os.path.dirname(file_path)))

    if not os.path.exists(dir_path):
        try:
            os.makedirs(dir_path)
        except OSError as e: # Guard against race condition
            # whereas errno is an error number, so this is just comparing a specific integer
            if e.errno != errno.EEXIST:
                raise


_alpha = re.compile("[A-Za-z_]")
_json_number = re.compile(r"-?(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?")
_nbt_float = re.compile(r"-?(0|[1-9]\d*)(\.\d+)([eE][+-]?\d+)?")

def is_json_number(string):
    """
    json_number ::= ("-")? && INT && ("." && INT)? && (["e", "E"] && ["+", "-"] && INT)?
    Follwing the picture for a general json number:
        http://www.json.org/number.gif
    """
    return bool(re.fullmatch(_json_number, string))

def is_number(string):
    """
    Checks whether the string has a proper signed number format for minecraft

    Args:
        string

    Returns:
        bool
    """

    try:
        float(string)
    except ValueError:
        return False

    # checks whether there is an alphabetical value is inside the number
    if re.search(_alpha, string) is not None:
        return False
    return True

def is_signed_int(num_str):
    """
    Args:
        num_str (str): The string that is checked to see if it represents a number

    Returns:
        bool
    """
    # if the num_str is a digit, that means that there are no special characters within the num_str
    # therefore making it a nonneg int
    # to check if it is a signed integer, the string is checked for one "-" and then the rest being the format of a nonneg int

    assert isinstance(num_str, str)
    return num_str.isdigit() or (num_str.startswith("-") and num_str[1:].isdigit())

def is_nonneg_int(num_str):
    """
    Args:
        num_str (str): The string that is checked to see if it represents a nonneg integer

    Returns:
        bool
    """

    assert isinstance(num_str, str)
    return num_str.isdigit()

def is_pos_int(num_str):
    """
    Args:
        num_str (str): The string that is checked to see if it represents a positive integer (not 0)

    Returns:
        bool
    """

    assert isinstance(num_str, str)
    if num_str.isdigit():
        return int(num_str) != 0
    return False


"""
http://python-3-patterns-idioms-test.readthedocs.io/en/latest/PythonDecorators.html
http://jfine-python-classes.readthedocs.io/en/latest/decorators.html

Syntax of a decorator on a class:
    @decorator
    class A:
        ...
    a = A()

is equal to
    class A:
        ...
    a = decorator(A)
"""

def addrepr(cls):
    """
    Decorator meant to be used on classes to set a __repr__ method
    that contains all variables of the classes
    """
    def __repr__(self):
        # `type(self)` is used instead of `cls` because `cls` only refers to the most parent object if inherited
        # while `type(self)` guarantees to get the class name of the current class
        class_name = type(self).__name__

        variables = []
        for variable, value in vars(self).items():
            variables.append(f"{variable}={value!r}")
        variables_str = ", ".join(variables)

        return f"{class_name}[{variables_str}]"

    # sets the __repr__ method as the defined __repr__ because methods can be defined outside classes
    # take that 1st year university test questions
    cls.__repr__ = __repr__

    # returns itself because of decorator(class) syntax
    return cls



class Singleton:
    """
    Singleton class based off of:
        https://colab.research.google.com/drive/1eajT5Rl9tA-7RmSHMME54B81U5aSKSni#scrollTo=nfQZINGxuUdK

    Sets its own attributes based off of:
        https://stackoverflow.com/questions/2466191/set-attributes-from-dictionary-in-python
    """

    def __new__(cls, *args, **kwargs):
        attr_name = f"_{cls.__name__}"
        if not hasattr(cls, attr_name):
            try:
                # generally for namedtuple, which works even if no args/kwargs are given
                attribute = super().__new__(cls, *args, **kwargs)
            except TypeError as e:
                if e.args[0] == "object() takes no parameters":
                    # for a regular object that has an __init__
                    attribute = super().__new__(cls)
                else:
                    exc_add_msg(e, f'with class {cls.__qualname__}')
                    raise

            setattr(cls, attr_name, attribute)
        return getattr(cls, attr_name)

"""
Simply provides the encode/decode function to turn a literal string into a regular string and back
"""

def decode_str(string):
    r"""
    Removes the quotations around a string, replaces double \\ with \, and replaces
    any specific character representation starting with \ with its true character
    (eg. \n turns to a newline)
    """
    if not len(string) >= 2:
        raise SyntaxError(f"Expected the string {string!r} to be longer than two characters so it can begin and end with a quotation")
    if not string.startswith('"'):
        raise SyntaxError(f"Expected the string {string!r} to begin with a quotation")
    if not string.endswith('"'):
        raise SyntaxError(f"Expected the string {string!r} to end with a quotation")

    return codecs.decode(string[1:-1], "unicode_escape")

def encode_str(string):
    r"""
    Surrounds the string with (double) quotes and replaces any characters with backslashes
    to their character representations
    """
    return '"' + codecs.encode(string, "unicode_escape").decode("utf-8") + '"'


if __name__ == "__main__":
    pass


class JsonStruct:
    """
    Stores all custom variables under an internal _dict attribute

    These attributes can be accessed through indexing like a dictionary or calling them as attributes.
    """

    def __init__(self, json_data, globals=None):
        # dict comprehension to wrap all values of the dictionary
        self._data = {key: _wrap(value, globals=globals) for key, value in json_data.items()}

    def __getattr__(self, item):
        # prevents recursion
        if item == "_data":
            return self.__dict__[item]

        return self._data[item]

    def __setattr__(self, key, value):
        if key == "_data":
            if "_data" not in self.__dict__:
                data = {}
                self.__dict__[key] = data
            self.__dict__[key] = value
        else:
            self.__dict__["_data"][key] = value

    def __getitem__(self, key):
        return self._data[key]

    def __setitem__(self, key, value):
        self._data[key] = value

    def __len__(self):
        return len(self._data)

    def __iter__(self):
        return iter(self._data)

    def __contains__(self, item):
        return item in self._data

    def __repr__(self):
        class_name = type(self).__name__

        variables = []
        for variable, value in items(self):
            variables.append(f"{variable}={value!r}")
        variables_str = ", ".join(variables)

        return f"{class_name}[{variables_str}]"


# All of the following methods are not methods of the JsonStruct class
# to prevent any item collisions
def _wrap(data, globals=None):
    """
    Recursive function to visit all inside a list and dictionary
    """
    if isinstance(data, list):
        # visits all items in the list
        return [_wrap(value, globals=globals) for value in data]

    if isinstance(data, dict):
        return JsonStruct(data, globals=globals)

    if isinstance(data, str) and data.startswith("$(") and data.endswith(")"):
        # pylint: disable=eval-used
        return eval(data[2:-1], globals)

    return data


def to_json(json_struct):
    json_dict = {}
    for key, value in items(json_struct):
        json_dict[key] = _wrap_json(value)

    return json_dict

def _wrap_json(data):
    if isinstance(data, (list)):
        return [_wrap_json(value) for value in data]

    if isinstance(data, JsonStruct):
        return to_json(data)

    return data


def items(json_struct):
    """
    Gets all items of the json_struct
    """
    return json_struct._data.items()

def keys(json_struct):
    """
    Gets all the variable names of the json_struct
    """
    return json_struct._data.keys()

def values(json_struct):
    """
    Gets all values of all variables of the json struct
    """
    return json_struct._data.values()

def pop(json_struct, item):
    """
    Removes the item
    """
    return json_struct._data.pop(item)





Simple assert utils to make sure that an object matches some specified type or the items in an iterable match some specified type  The main difference between using this function and using assert isinstance(...) is that it provides a more in-depth error message  Running unit testing: `python3 -m unittest discover -s unittests` Checks whether an object is an instance of any of the valid types      Args:         checked_object (any)         valid_types (any)         additional_message (str or None)         optional (bool): Whether the object can be a None object or not #full_message = f"Expected type of {type(checked_object)} to be {checked_types_str} but got {type(checked_object)}" Checks whether all objects in a iterable are instances of one of the valid types      Args:         checked_iterable (iterable)         valid_types (any)         duplicate_key (None or callable): A function to give the value to check for duplicates             Note that if you want to detect duplicates with itself, just do `duplicate_key=lambda x: x`             If the option is None, no duplicate checking will be done # checks for duplicates # uses a set because only the containment of an item matters # iterates through each checked object to see if its within the found objects # assert result_object not in found_objects, f"Found a duplicate of {result_object!r} in iterable {checked_iterable}" Utils to change the message of an exception Args:         e (Exception): The exception to add a message to         message (str): The message to be added to the exception Args:         e (Exception): The exception to set a message to         message (str): The message to be set to the exception Makes the directories if the directories to the file path does not exist      Args:         file_path (str): the path-like object to the file         is_dir_path (bool): whether the file path is actually a directory path or not             This will make the last basename directory instead of skipping it.      Answer comes from:         https://stackoverflow.com/a/12517490 # Guard against race condition # whereas errno is an error number, so this is just comparing a specific integer json_number ::= ("-")? && INT && ("." && INT)? && (["e", "E"] && ["+", "-"] && INT)?     Follwing the picture for a general json number:         http://www.json.org/number.gif Checks whether the string has a proper signed number format for minecraft      Args:         string      Returns:         bool # checks whether there is an alphabetical value is inside the number Args:         num_str (str): The string that is checked to see if it represents a number      Returns:         bool # if the num_str is a digit, that means that there are no special characters within the num_str # therefore making it a nonneg int # to check if it is a signed integer, the string is checked for one "-" and then the rest being the format of a nonneg int Args:         num_str (str): The string that is checked to see if it represents a nonneg integer      Returns:         bool Args:         num_str (str): The string that is checked to see if it represents a positive integer (not 0)      Returns:         bool http://python-3-patterns-idioms-test.readthedocs.io/en/latest/PythonDecorators.html http://jfine-python-classes.readthedocs.io/en/latest/decorators.html  Syntax of a decorator on a class:     @decorator     class A:         ...     a = A()  is equal to     class A:         ...     a = decorator(A) Decorator meant to be used on classes to set a __repr__ method     that contains all variables of the classes # `type(self)` is used instead of `cls` because `cls` only refers to the most parent object if inherited # while `type(self)` guarantees to get the class name of the current class # sets the __repr__ method as the defined __repr__ because methods can be defined outside classes # take that 1st year university test questions # returns itself because of decorator(class) syntax Singleton class based off of:         https://colab.research.google.com/drive/1eajT5Rl9tA-7RmSHMME54B81U5aSKSni#scrollTo=nfQZINGxuUdK      Sets its own attributes based off of:         https://stackoverflow.com/questions/2466191/set-attributes-from-dictionary-in-python # generally for namedtuple, which works even if no args/kwargs are given # for a regular object that has an __init__ Simply provides the encode/decode function to turn a literal string into a regular string and back Removes the quotations around a string, replaces double \\ with \, and replaces     any specific character representation starting with \ with its true character     (eg. \n turns to a newline) Surrounds the string with (double) quotes and replaces any characters with backslashes     to their character representations Stores all custom variables under an internal _dict attribute      These attributes can be accessed through indexing like a dictionary or calling them as attributes. # dict comprehension to wrap all values of the dictionary # prevents recursion # All of the following methods are not methods of the JsonStruct class # to prevent any item collisions Recursive function to visit all inside a list and dictionary # visits all items in the list # pylint: disable=eval-used Gets all items of the json_struct Gets all the variable names of the json_struct Gets all values of all variables of the json struct Removes the item