aboutsummaryrefslogtreecommitdiff
path: root/libs/installer_fomod_plus/share/xml
diff options
context:
space:
mode:
Diffstat (limited to 'libs/installer_fomod_plus/share/xml')
-rw-r--r--libs/installer_fomod_plus/share/xml/FomodInfoFile.cpp44
-rw-r--r--libs/installer_fomod_plus/share/xml/FomodInfoFile.h25
-rw-r--r--libs/installer_fomod_plus/share/xml/ModuleConfiguration.cpp352
-rw-r--r--libs/installer_fomod_plus/share/xml/ModuleConfiguration.h305
-rw-r--r--libs/installer_fomod_plus/share/xml/XmlHelper.h17
-rw-r--r--libs/installer_fomod_plus/share/xml/XmlParseException.h10
6 files changed, 0 insertions, 753 deletions
diff --git a/libs/installer_fomod_plus/share/xml/FomodInfoFile.cpp b/libs/installer_fomod_plus/share/xml/FomodInfoFile.cpp
deleted file mode 100644
index d4fed69..0000000
--- a/libs/installer_fomod_plus/share/xml/FomodInfoFile.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#include "FomodInfoFile.h"
-#include "XmlParseException.h"
-#include <format>
-#include <pugixml.hpp>
-
-#include "stringutil.h"
-
-#include <QFile>
-#include <QString>
-
-bool FomodInfoFile::deserialize(const QString& filePath)
-{
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- throw XmlParseException(std::format("Failed to open file: {}", filePath.toStdString()));
- }
- const QByteArray content = file.readAll();
- file.close();
-
- pugi::xml_document doc;
- if (const pugi::xml_parse_result result = doc.load_buffer(content.constData(), content.size()); !result) {
- throw XmlParseException(std::format("XML parsed with errors: {}", result.description()));
- }
-
- const pugi::xml_node fomodNode = doc.child("fomod");
- if (!fomodNode) {
- throw XmlParseException("No <config> node found");
- }
-
- name = fomodNode.child("Name").text().as_string();
- author = fomodNode.child("Author").text().as_string();
- version = fomodNode.child("Version").text().as_string();
- website = fomodNode.child("Website").text().as_string();
- description = fomodNode.child("Description").text().as_string();
-
- trim({ name, author, version, website, description });
-
- for (pugi::xml_node groupNode : fomodNode.child("Groups").children("element")) {
- groups.emplace_back(groupNode.text().as_string());
- }
-
- return true;
-
-} \ No newline at end of file
diff --git a/libs/installer_fomod_plus/share/xml/FomodInfoFile.h b/libs/installer_fomod_plus/share/xml/FomodInfoFile.h
deleted file mode 100644
index d2c2a23..0000000
--- a/libs/installer_fomod_plus/share/xml/FomodInfoFile.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include <qstring.h>
-#include <string>
-#include <vector>
-
-class FomodInfoFile {
-public:
- bool deserialize(const QString &filePath);
-
- [[nodiscard]] const std::string& getName() const { return name; }
- [[nodiscard]] const std::string& getAuthor() const { return author; }
- [[nodiscard]] const std::string& getVersion() const { return version; }
- [[nodiscard]] const std::string& getWebsite() const { return website; }
- [[nodiscard]] const std::string& getDescription() const { return description; }
- [[nodiscard]] const std::vector<std::string>& getGroups() const { return groups; }
-
-private:
- std::string name;
- std::string author;
- std::string version;
- std::string website;
- std::string description;
- std::vector<std::string> groups;
-}; \ No newline at end of file
diff --git a/libs/installer_fomod_plus/share/xml/ModuleConfiguration.cpp b/libs/installer_fomod_plus/share/xml/ModuleConfiguration.cpp
deleted file mode 100644
index 64d6b0b..0000000
--- a/libs/installer_fomod_plus/share/xml/ModuleConfiguration.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-#include "ModuleConfiguration.h"
-
-#include <format>
-
-#include "XmlHelper.h"
-#include "XmlParseException.h"
-#include "stringutil.h"
-
-#include <QFile>
-#include <QString>
-
-using namespace StringConstants::FomodFiles;
-
-static GroupTypeEnum groupTypeFromString(const std::string& groupType)
-{
- if (groupType == "SelectAny")
- return SelectAny;
- if (groupType == "SelectAll")
- return SelectAll;
- if (groupType == "SelectExactlyOne")
- return SelectExactlyOne;
- if (groupType == "SelectAtMostOne")
- return SelectAtMostOne;
- if (groupType == "SelectAtLeastOne")
- return SelectAtLeastOne;
- return SelectAny; // is this a sane default? probably
-}
-
-PluginTypeEnum pluginTypeFromString(const std::string& typeStr)
-{
- if (typeStr == TYPE_REQUIRED)
- return PluginTypeEnum::Required;
- if (typeStr == TYPE_OPTIONAL)
- return PluginTypeEnum::Optional;
- if (typeStr == TYPE_RECOMMENDED)
- return PluginTypeEnum::Recommended;
- if (typeStr == TYPE_NOT_USABLE)
- return PluginTypeEnum::NotUsable;
- if (typeStr == TYPE_COULD_BE_USABLE)
- return PluginTypeEnum::CouldBeUsable;
- return PluginTypeEnum::Optional;
-}
-
-template <typename T>
-bool deserializeList(pugi::xml_node& node, const char* childName, std::vector<T>& list)
-{
- for (pugi::xml_node childNode : node.children(childName)) {
- T item;
- item.deserialize(childNode);
- list.push_back(item);
- }
- return true;
-}
-
-/*
- * NOTE: We call 'trim()' on all error-prone fields that rely on user-input. I'm assuming these FOMODs are created with
- * the FOMOD creation tool, so I won't trim things like flags that the tool sets for the user.
- */
-
-bool FileDependency::deserialize(pugi::xml_node& node)
-{
- file = node.attribute("file").as_string();
- trim(file);
- // ReSharper disable once CppTooWideScopeInitStatement
- // Do not use 'auto' for these. it will break equality checks
- const std::string stateStr = node.attribute("state").as_string();
-
- if (stateStr == "Missing")
- state = FileDependencyTypeEnum::Missing;
- else if (stateStr == "Inactive")
- state = FileDependencyTypeEnum::Inactive;
- else if (stateStr == "Active")
- state = FileDependencyTypeEnum::Active;
- return true;
-}
-
-bool FlagDependency::deserialize(pugi::xml_node& node)
-{
- flag = node.attribute("flag").as_string();
- value = node.attribute("value").as_string();
- trim({ flag, value });
- return true;
-}
-
-bool GameDependency::deserialize(pugi::xml_node& node)
-{
- version = node.attribute("version").as_string();
- trim(version);
- return true;
-}
-
-bool CompositeDependency::deserialize(pugi::xml_node& node)
-{
-
- // this could EITHER have a dependencies child or the dependencies are here.
- // turns out they could have both.
- pugi::xml_node possibleNode = node;
-
- // If the dependencies are all right inside, just use the root node as the dependency base.
- // This looks hacky but accommodates both _nested_ dependencies for plugins, and extremely simple ones for step visibility.
- if (node.child("dependencies") && !node.child("fileDependency") && !node.child("flagDependency") &&!node.child("gameDependency")) {
- possibleNode = node.child("dependencies");
- }
-
- deserializeList(possibleNode, "fileDependency", fileDependencies);
- deserializeList(possibleNode, "flagDependency", flagDependencies);
- deserializeList(possibleNode, "gameDependency", gameDependencies);
- deserializeList(possibleNode, "dependencies", nestedDependencies);
-
- operatorType = OperatorTypeEnum::AND; // safest default.
-
- if (const std::string operatorStr = possibleNode.attribute("operator").as_string(); operatorStr == "Or") {
- operatorType = OperatorTypeEnum::OR;
- }
-
- return true;
-}
-
-bool DependencyPattern::deserialize(pugi::xml_node& node)
-{
- if (!node)
- return false;
- pugi::xml_node dependenciesNode = node.child("dependencies");
- dependencies.deserialize(dependenciesNode);
-
- const pugi::xml_node typeNode = node.child("type");
- type = pluginTypeFromString(typeNode.attribute("name").as_string());
- return true;
-}
-
-bool DependencyPatternList::deserialize(pugi::xml_node& node)
-{
- return deserializeList(node, "pattern", patterns);
-}
-
-bool DependencyPluginType::deserialize(pugi::xml_node& node)
-{
- pugi::xml_node patternsNode = node.child("patterns");
- const pugi::xml_node defaultTypeNode = node.child("defaultType");
- defaultType = pluginTypeFromString(defaultTypeNode.attribute("name").as_string());
- patterns.deserialize(patternsNode);
- return true;
-}
-
-bool TypeDescriptor::deserialize(pugi::xml_node& node)
-{
- pugi::xml_node dependencyTypeNode = node.child("dependencyType");
- dependencyType.deserialize(dependencyTypeNode);
- const pugi::xml_node typeNode = node.child("type");
- type = pluginTypeFromString(typeNode.attribute("name").as_string());
- return true;
-}
-
-bool Image::deserialize(pugi::xml_node& node)
-{
- path = node.attribute("path").as_string();
- return true;
-}
-
-bool HeaderImage::deserialize(pugi::xml_node& node)
-{
- path = node.attribute("path").as_string();
- showImage = node.attribute("showImage").as_bool();
- showFade = node.attribute("showFade").as_bool();
- height = node.attribute("height").as_int();
- return true;
-}
-
-bool FileList::deserialize(pugi::xml_node& node)
-{
- for (pugi::xml_node childNode : node.children()) {
- if (std::string(childNode.name()) == "folder"
- || std::string(childNode.name()) == "file") {
- File file;
- file.deserialize(childNode);
- files.emplace_back(file);
- }
- }
- return true;
-}
-
-bool ConditionalFileInstallPattern::deserialize(pugi::xml_node& node)
-{
- pugi::xml_node dependenciesNode = node.child("dependencies");
- pugi::xml_node filesNode = node.child("files");
-
- dependencies.deserialize(dependenciesNode);
- files.deserialize(filesNode);
-
- return true;
-}
-
-// <flag name="2">On</flag>
-bool ConditionFlag::deserialize(pugi::xml_node& node)
-{
- name = node.attribute("name").as_string();
- value = node.child_value(); //
- return true;
-}
-
-bool ConditionFlagList::deserialize(pugi::xml_node& node)
-{
- return deserializeList(node, "flag", flags);
-}
-
-bool File::deserialize(pugi::xml_node& node)
-{
- source = node.attribute("source").as_string();
- // destination = node.attribute("destination").as_string();
- priority = node.attribute("priority").as_int();
- isFolder = strcmp(node.name(), "folder") == 0;
- if (auto attr = node.attribute("destination"); attr) {
- destination = attr.as_string();
- } else {
- destination = std::nullopt;
- }
- return true;
-}
-
-
-bool Plugin::deserialize(pugi::xml_node& node)
-{
- pugi::xml_node imageNode = node.child("image");
- pugi::xml_node typeDescriptorNode = node.child("typeDescriptor");
- pugi::xml_node conditionFlagsNode = node.child("conditionFlags");
- pugi::xml_node filesNode = node.child("files");
-
- // Description is optional in the schema; guard against null C strings from pugixml.
- if (const pugi::xml_node descNode = node.child("description")) {
- if (const char* rawDesc = descNode.text().as_string()) {
- description = rawDesc;
- }
- }
- description = trim(description); // Find a better way to do this eventually.
- image.deserialize(imageNode);
- typeDescriptor.deserialize(typeDescriptorNode);
- name = node.attribute("name").as_string();
- name = trim(name);
- conditionFlags.deserialize(conditionFlagsNode);
- files.deserialize(filesNode);
- return true;
-}
-
-bool PluginList::deserialize(pugi::xml_node& node)
-{
- deserializeList(node, "plugin", plugins);
- order = XmlHelper::getOrderType(node.attribute("order").as_string(), OrderTypeEnum::Ascending);
-
- // Sort the plugins based on the specified order
- std::ranges::sort(plugins, [this](const Plugin& a, const Plugin& b) {
- if (order == OrderTypeEnum::Ascending) {
- return a.name < b.name;
- }
- if (order == OrderTypeEnum::Descending) {
- return a.name > b.name;
- }
- return false; // Default case, no sorting
- });
-
- return true;
-}
-
-bool Group::deserialize(pugi::xml_node& node)
-{
- pugi::xml_node pluginsNode = node.child("plugins");
- plugins.deserialize(pluginsNode);
- name = node.attribute("name").as_string();
- type = groupTypeFromString(node.attribute("type").as_string());
- return true;
-}
-
-bool GroupList::deserialize(pugi::xml_node& node)
-{
- deserializeList(node, "group", groups);
- order = XmlHelper::getOrderType(node.attribute("order").as_string());
-
- // Sort the groups based on the specified order
- std::ranges::sort(groups, [this](const Group& a, const Group& b) {
- if (order == OrderTypeEnum::Ascending) {
- return a.name < b.name;
- }
- if (order == OrderTypeEnum::Descending) {
- return a.name > b.name;
- }
- return false; // Default case, no sorting
- });
- return true;
-}
-
-bool InstallStep::deserialize(pugi::xml_node& node)
-{
- pugi::xml_node visibleNode = node.child("visible");
- pugi::xml_node optionalFileGroupsNode = node.child("optionalFileGroups");
- visible.deserialize(visibleNode);
- optionalFileGroups.deserialize(optionalFileGroupsNode);
- name = node.attribute("name").as_string();
- return true;
-}
-
-bool ConditionalFileInstall::deserialize(pugi::xml_node& node)
-{
- pugi::xml_node patternsNode = node.child("patterns");
- deserializeList(patternsNode, "pattern", patterns);
- return true;
-}
-
-bool StepList::deserialize(pugi::xml_node& node)
-{
- deserializeList(node, "installStep", installSteps);
- order = XmlHelper::getOrderType(node.attribute("order").as_string());
- return true;
-}
-
-bool ModuleConfiguration::deserialize(const QString& filePath)
-{
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- throw XmlParseException(std::format("Failed to open file: {}", filePath.toStdString()));
- }
- const QByteArray content = file.readAll();
- file.close();
-
- pugi::xml_document doc;
- if (const pugi::xml_parse_result result = doc.load_buffer(content.constData(), content.size()); !result) {
- throw XmlParseException(std::format("XML parsed with errors: {}", result.description()));
- }
-
- const pugi::xml_node configNode = doc.child("config");
- if (!configNode) {
- throw XmlParseException("No <config> node found");
- }
-
- moduleName = configNode.child("moduleName").text().as_string();
-
- moduleImage = HeaderImage();
- pugi::xml_node moduleImageNode = configNode.child("moduleImage");
- moduleImage.deserialize(moduleImageNode);
-
- pugi::xml_node moduleDependenciesNode = configNode.child("moduleDependencies");
- moduleDependencies.deserialize(moduleDependenciesNode);
-
- pugi::xml_node requiredInstallFilesNode = configNode.child("requiredInstallFiles");
- requiredInstallFiles.deserialize(requiredInstallFilesNode);
-
- pugi::xml_node installStepsNode = configNode.child("installSteps");
- installSteps.deserialize(installStepsNode);
-
- pugi::xml_node conditionalFileInstallsNode = configNode.child("conditionalFileInstalls");
- conditionalFileInstalls.deserialize(conditionalFileInstallsNode);
-
- return true;
-}
diff --git a/libs/installer_fomod_plus/share/xml/ModuleConfiguration.h b/libs/installer_fomod_plus/share/xml/ModuleConfiguration.h
deleted file mode 100644
index a0a017b..0000000
--- a/libs/installer_fomod_plus/share/xml/ModuleConfiguration.h
+++ /dev/null
@@ -1,305 +0,0 @@
-#pragma once
-
-#include <iostream>
-#include <optional>
-#include <pugixml.hpp>
-#include <qstring.h>
-#include <string>
-#include <vector>
-
-class XmlDeserializable {
-public:
- virtual ~XmlDeserializable() = default;
-
- virtual bool deserialize(pugi::xml_node& node) = 0;
-
-protected:
- XmlDeserializable() = default;
-};
-
-enum GroupTypeEnum {
- SelectAny,
- SelectAll,
- SelectExactlyOne,
- SelectAtMostOne,
- SelectAtLeastOne
-};
-
-enum class OperatorTypeEnum {
- AND,
- OR
-};
-
-enum class OrderTypeEnum {
- Explicit,
- Ascending,
- Descending
-};
-
-enum class FileDependencyTypeEnum {
- Missing,
- Inactive,
- Active,
- UNKNOWN_STATE
-};
-
-template <typename T>
-class OrderedContents {
-public:
- OrderTypeEnum order;
-
- OrderedContents() : order(OrderTypeEnum::Ascending) {}
- explicit OrderedContents(const OrderTypeEnum orderType): order(orderType) {}
-
- template <typename Accessor>
- bool compare(const T& a, const T& b, Accessor accessor) const
- {
- switch (order) {
- case OrderTypeEnum::Ascending:
- return accessor(a) < accessor(b);
- case OrderTypeEnum::Descending:
- return accessor(a) > accessor(b);
- case OrderTypeEnum::Explicit:
- default:
- return false; // No sorting for explicit order
- }
- }
-};
-
-enum class PluginTypeEnum {
- Recommended,
- Required,
- Optional,
- NotUsable,
- CouldBeUsable,
- UNKNOWN
-};
-
-
-inline std::ostream& operator<<(std::ostream& os, const PluginTypeEnum& type)
-{
- switch (type) {
- case PluginTypeEnum::Recommended:
- os << "Recommended";
- break;
- case PluginTypeEnum::Required:
- os << "Required";
- break;
- case PluginTypeEnum::Optional:
- os << "Optional";
- break;
- case PluginTypeEnum::NotUsable:
- os << "NotUsable";
- break;
- case PluginTypeEnum::CouldBeUsable:
- os << "CouldBeUsable";
- break;
- default: ;
- }
- return os;
-}
-
-class PluginType final : public XmlDeserializable {
-public:
- PluginTypeEnum name = PluginTypeEnum::Optional; // sane default
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class FileDependency final : public XmlDeserializable {
-public:
- std::string file;
- FileDependencyTypeEnum state = FileDependencyTypeEnum::UNKNOWN_STATE;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class FlagDependency final : public XmlDeserializable {
-public:
- std::string flag;
- std::string value;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class GameDependency final : public XmlDeserializable {
-public:
- std::string version;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class CompositeDependency final : public XmlDeserializable {
-public:
- std::vector<FileDependency> fileDependencies;
- std::vector<FlagDependency> flagDependencies;
- std::vector<GameDependency> gameDependencies;
- std::vector<CompositeDependency> nestedDependencies;
- OperatorTypeEnum operatorType = OperatorTypeEnum::AND; // safest default.
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class DependencyPattern final : public XmlDeserializable {
-public:
- CompositeDependency dependencies;
- PluginTypeEnum type;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-
-class DependencyPatternList final : public XmlDeserializable {
-public:
- std::vector<DependencyPattern> patterns;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class DependencyPluginType final : public XmlDeserializable {
-public:
- std::optional<PluginTypeEnum> defaultType;
- DependencyPatternList patterns;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class TypeDescriptor final : public XmlDeserializable {
-public:
- DependencyPluginType dependencyType;
- PluginTypeEnum type;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class Image final : public XmlDeserializable {
-public:
- std::string path;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class HeaderImage final : public XmlDeserializable {
-public:
- std::string path;
- bool showImage;
- bool showFade;
- int height;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class File final : public XmlDeserializable {
-public:
- std::string source;
- std::optional<std::string> destination;
- int priority{ 0 };
- bool isFolder;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-
-class FileList final : public XmlDeserializable {
-public:
- std::vector<File> files;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class ConditionalFileInstallPattern final : public XmlDeserializable {
-public:
- CompositeDependency dependencies;
- FileList files;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-// <flag name="2">On</flag>
-class ConditionFlag final : public XmlDeserializable {
-public:
- std::string name;
- std::string value;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class ConditionFlagList final : public XmlDeserializable {
-public:
- std::vector<ConditionFlag> flags;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class Plugin final : public XmlDeserializable {
-public:
- std::string description;
- Image image;
- TypeDescriptor typeDescriptor;
- std::string name;
- ConditionFlagList conditionFlags;
- FileList files;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class PluginList final : public XmlDeserializable, public OrderedContents<Plugin> {
-public:
- std::vector<Plugin> plugins;
- OrderTypeEnum order;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class Group final : public XmlDeserializable {
-public:
- PluginList plugins;
- std::string name;
- GroupTypeEnum type;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class GroupList final : public XmlDeserializable, public OrderedContents<Group> {
-public:
- std::vector<Group> groups;
- OrderTypeEnum order;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class InstallStep final : public XmlDeserializable {
-public:
- CompositeDependency visible;
- GroupList optionalFileGroups;
- std::string name;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class ConditionalFileInstall final : public XmlDeserializable {
-public:
- std::vector<ConditionalFileInstallPattern> patterns;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class StepList final : public XmlDeserializable, public OrderedContents<InstallStep> {
-public:
- std::vector<InstallStep> installSteps;
- OrderTypeEnum order;
-
- bool deserialize(pugi::xml_node& node) override;
-};
-
-class ModuleConfiguration {
-public:
- std::string moduleName;
- HeaderImage moduleImage;
- CompositeDependency moduleDependencies;
- FileList requiredInstallFiles;
- StepList installSteps;
- ConditionalFileInstall conditionalFileInstalls;
-
- bool deserialize(const QString& filePath);
-}; \ No newline at end of file
diff --git a/libs/installer_fomod_plus/share/xml/XmlHelper.h b/libs/installer_fomod_plus/share/xml/XmlHelper.h
deleted file mode 100644
index 6934a86..0000000
--- a/libs/installer_fomod_plus/share/xml/XmlHelper.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-
-#include "ModuleConfiguration.h"
-
-class XmlHelper {
-public:
- static OrderTypeEnum getOrderType(const std::string& orderType, OrderTypeEnum defaultOrder = OrderTypeEnum::Explicit)
- {
- if (orderType == "Explicit")
- return OrderTypeEnum::Explicit;
- if (orderType == "Ascending")
- return OrderTypeEnum::Ascending;
- if (orderType == "Descending")
- return OrderTypeEnum::Descending;
- return defaultOrder; // Ascending for plugins, Explicit for groups
- }
-}; \ No newline at end of file
diff --git a/libs/installer_fomod_plus/share/xml/XmlParseException.h b/libs/installer_fomod_plus/share/xml/XmlParseException.h
deleted file mode 100644
index 6406f3b..0000000
--- a/libs/installer_fomod_plus/share/xml/XmlParseException.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#include <stdexcept>
-#include <string>
-
-class XmlParseException final : public std::runtime_error {
-public:
- explicit XmlParseException(const std::string& message)
- : std::runtime_error(message) {}
-};