support anytls for clash
GitHub CI / Linux aarch64 Build (push) Failing after 22s
GitHub CI / Linux amd64 Build (push) Failing after 15s
GitHub CI / Linux armv7 Build (push) Failing after 18s
GitHub CI / Linux x86 Build (push) Failing after 18s
Publish Docker Image / Build linux/386 Image (push) Failing after 7m13s
Publish Docker Image / Build linux/amd64 Image (push) Failing after 22m43s
Publish Docker Image / Build linux/arm/v7 Image (push) Failing after 33m40s
Publish Docker Image / Build linux/arm64 Image (push) Failing after 25m25s
Publish Docker Image / Merge (push) Has been skipped
GitHub CI / macOS arm Build (push) Has been cancelled
GitHub CI / macOS x86 Build (push) Has been cancelled
GitHub CI / Windows amd64 Build (push) Has been cancelled
GitHub CI / Windows x86 Build (push) Has been cancelled

This commit is contained in:
asdlokj1qpi23 committed 2025-04-16 18:14:00 +08:00
1 parent 638137e1db
commit ebf6a08449
5 files changed
+144 -49

No files matched your search

+27 -10
View File
@@ -551,6 +551,28 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
singleproxy["congestion-controller"] = x.CongestionControl;
}
break;
case ProxyType::AnyTLS:
singleproxy["type"] = "anytls";
if (!x.Password.empty()) {
singleproxy["password"] = x.Password;
}
if (!x.Fingerprint.empty()) {
singleproxy["client-fingerprint"] = x.Fingerprint;
}
if (!udp.is_undef()) {
singleproxy["udp"] = udp.get();
}
if (!x.ServerName.empty()) {
singleproxy["sni"] = x.SNI;
}
if (!scv.is_undef())
singleproxy["skip-cert-verify"] = scv.get();
if (!x.AlpnList.empty()) {
for (auto &item: x.AlpnList) {
singleproxy["alpn"].push_back(item);
}
}
break;
case ProxyType::VLESS:
singleproxy["type"] = "vless";
singleproxy["uuid"] = x.UserId;
@@ -662,8 +684,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
yamlnode["Proxy"] = proxies;
for(const ProxyGroupConfig &x : extra_proxy_group)
{
for (const ProxyGroupConfig &x: extra_proxy_group) {
YAML::Node singlegroup;
string_array filtered_nodelist;
@@ -673,8 +694,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
else
singlegroup["type"] = x.TypeStr();
switch(x.Type)
{
switch (x.Type) {
case ProxyGroupType::Select:
case ProxyGroupType::Relay:
break;
@@ -705,8 +725,7 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
if (!x.UsingProvider.empty())
singlegroup["use"] = x.UsingProvider;
else
{
else {
if (filtered_nodelist.empty())
filtered_nodelist.emplace_back("DIRECT");
}
@@ -718,10 +737,8 @@ proxyToClash(std::vector<Proxy> &nodes, YAML::Node &yamlnode, const ProxyGroupCo
singlegroup.SetStyle(YAML::EmitterStyle::Flow);
bool replace_flag = false;
for(auto && original_group : original_groups)
{
if(original_group["name"].as<std::string>() == x.Name)
{
for (auto &&original_group: original_groups) {
if (original_group["name"].as<std::string>() == x.Name) {
original_group.reset(singlegroup);
replace_flag = true;
break;
+8 -3
View File
@@ -24,7 +24,8 @@ enum class ProxyType
VLESS,
Hysteria,
Hysteria2,
TUIC
TUIC,
AnyTLS
};
inline String getProxyTypeName(ProxyType type) {
@@ -55,6 +56,8 @@ inline String getProxyTypeName(ProxyType type) {
return "Hysteria2";
case ProxyType::TUIC:
return "Tuic";
case ProxyType::AnyTLS:
return "AnyTLS";
default:
return "Unknown";
}
@@ -83,7 +86,9 @@ struct Proxy {
String TransferProtocol;
String FakeType;
String AuthStr;
uint16_t IdleSessionCheckInterval=30;
uint16_t IdleSessionTimeout=30;
uint16_t MinIdleSession=0;
bool TLSSecure = false;
String Host;
@@ -151,5 +156,5 @@ struct Proxy {
#define HYSTERIA_DEFAULT_GROUP "HysteriaProvider"
#define HYSTERIA2_DEFAULT_GROUP "Hysteria2Provider"
#define TUIC_DEFAULT_GROUP "TuicProvider"
#define ANYTLS_DEFAULT_GROUP "AnyTLSProvider"
#endif // PROXY_H_INCLUDED
+102 -34
View File
@@ -18,16 +18,20 @@ using namespace rapidjson;
using namespace rapidjson_ext;
using namespace YAML;
string_array ss_ciphers = {"rc4-md5", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb",
string_array ss_ciphers = {
"rc4-md5", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb",
"aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb",
"camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf", "2022-blake3-aes-128-gcm",
"2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "2022-blake3-chacha12-poly1305",
"2022-blake3-chacha8-poly1305"};
string_array ssr_ciphers = {"none", "table", "rc4", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb",
"2022-blake3-chacha8-poly1305"
};
string_array ssr_ciphers = {
"none", "table", "rc4", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb",
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb",
"camellia-192-cfb", "camellia-256-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb",
"seed-cfb", "salsa20", "chacha20", "chacha20-ietf"};
"seed-cfb", "salsa20", "chacha20", "chacha20-ietf"
};
std::map<std::string, std::string> parsedMD5;
std::string modSSMD5 = "f7653207090ce3389115e9c88541afe0";
@@ -77,8 +81,10 @@ void vmessConstruct(Proxy &node, const std::string &group, const std::string &re
void ssrConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &protocol, const std::string &method,
const std::string &obfs, const std::string &password, const std::string &obfsparam,
const std::string &protoparam, tribool udp, tribool tfo, tribool scv,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool(),underlying_proxy);
const std::string &protoparam, tribool udp, tribool tfo, tribool scv,
const std::string &underlying_proxy) {
commonConstruct(node, ProxyType::ShadowsocksR, group, remarks, server, port, udp, tfo, scv, tribool(),
underlying_proxy);
node.Password = password;
node.EncryptMethod = method;
node.Protocol = protocol;
@@ -136,7 +142,8 @@ void trojanConstruct(Proxy &node, const std::string &group, const std::string &r
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &obfs,
const std::string &host, uint16_t version, tribool udp, tribool tfo, tribool scv,const std::string& underlying_proxy) {
const std::string &host, uint16_t version, tribool udp, tribool tfo, tribool scv,
const std::string &underlying_proxy) {
commonConstruct(node, ProxyType::Snell, group, remarks, server, port, udp, tfo, scv, tribool(), underlying_proxy);
node.Password = password;
node.OBFS = obfs;
@@ -148,8 +155,10 @@ void wireguardConstruct(Proxy &node, const std::string &group, const std::string
const std::string &port, const std::string &selfIp, const std::string &selfIpv6,
const std::string &privKey, const std::string &pubKey, const std::string &psk,
const string_array &dns, const std::string &mtu, const std::string &keepalive,
const std::string &testUrl, const std::string &clientId, const tribool &udp,const std::string& underlying_proxy) {
commonConstruct(node, ProxyType::WireGuard, group, remarks, server, port, udp, tribool(), tribool(), tribool(),underlying_proxy);
const std::string &testUrl, const std::string &clientId, const tribool &udp,
const std::string &underlying_proxy) {
commonConstruct(node, ProxyType::WireGuard, group, remarks, server, port, udp, tribool(), tribool(), tribool(),
underlying_proxy);
node.SelfIP = selfIp;
node.SelfIPv6 = selfIpv6;
node.PrivateKey = privKey;
@@ -184,6 +193,25 @@ void hysteriaConstruct(Proxy &node, const std::string &group, const std::string
node.ServerName = sni;
}
void anyTlSConstruct(Proxy &node, const std::string &group, const std::string &remarks,
const std::string &port, const std::string &password,
const std::string &host, const std::vector<String> &AlpnList,
const std::string &fingerprint,
const std::string &sni, tribool udp,
tribool tfo, tribool scv,
tribool tls13, const std::string &underlying_proxy, uint16_t idleSessionCheckInterval,
uint16_t idleSessionTimeout, uint16_t minIdleSession) {
commonConstruct(node, ProxyType::AnyTLS, group, remarks, host, port, udp, tfo, scv, tls13, underlying_proxy);
node.Host = trim(host);
node.Password = password;
node.AlpnList = AlpnList;
node.SNI = sni;
node.Fingerprint = fingerprint;
node.IdleSessionCheckInterval = idleSessionCheckInterval;
node.IdleSessionTimeout = idleSessionTimeout;
node.MinIdleSession = minIdleSession;
}
void vlessConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &add,
const std::string &port, const std::string &type, const std::string &id, const std::string &aid,
@@ -252,7 +280,8 @@ void tuicConstruct(Proxy &node, const std::string &group, const std::string &rem
const std::string &sni, const std::string &uuid, const std::string &udpRelayMode,
const std::string &token,
tribool udp, tribool tfo,
tribool scv, tribool reduceRtt, tribool disableSni, uint16_t request_timeout,const std::string& underlying_proxy) {
tribool scv, tribool reduceRtt, tribool disableSni, uint16_t request_timeout,
const std::string &underlying_proxy) {
commonConstruct(node, ProxyType::TUIC, group, remarks, add, port, udp, tfo, scv, tribool(), underlying_proxy);
node.Password = password;
node.Alpn = alpn;
@@ -326,7 +355,8 @@ void explodeVmess(std::string vmess, Proxy &node) {
add = trim(add);
vmessConstruct(node, V2RAY_DEFAULT_GROUP, ps, add, port, type, id, aid, net, "auto", path, host, "", tls, sni,std::vector<std::string>{});
vmessConstruct(node, V2RAY_DEFAULT_GROUP, ps, add, port, type, id, aid, net, "auto", path, host, "", tls, sni,
std::vector<std::string>{});
}
void explodeVmessConf(std::string content, std::vector<Proxy> &nodes) {
@@ -402,8 +432,7 @@ void explodeVmessConf(std::string content, std::vector<Proxy> &nodes) {
}
return;
}
}
catch (std::exception &e) {
} catch (std::exception &e) {
//writeLog(0, "VMessConf parser throws an error. Leaving...", LOG_LEVEL_WARNING);
//return;
//ignore
@@ -470,7 +499,8 @@ void explodeVmessConf(std::string content, std::vector<Proxy> &nodes) {
}
void explodeSS(std::string ss, Proxy &node) {
std::string ps, password, method, server, port, plugins, plugin, pluginopts, addition, group = SS_DEFAULT_GROUP, secret;
std::string ps, password, method, server, port, plugins, plugin, pluginopts, addition, group = SS_DEFAULT_GROUP,
secret;
//std::vector<std::string> args, secret;
ss = replaceAllDistinct(ss.substr(5), "/?", "?");
if (strFind(ss, "#")) {
@@ -683,7 +713,8 @@ void explodeSSR(std::string ssr, Proxy &node) {
void explodeSSRConf(std::string content, std::vector<Proxy> &nodes) {
Document json;
std::string remarks, group, server, port, method, password, protocol, protoparam, obfs, obfsparam, plugin, pluginopts;
std::string remarks, group, server, port, method, password, protocol, protoparam, obfs, obfsparam, plugin,
pluginopts;
auto index = nodes.size();
json.Parse(content.data());
@@ -926,7 +957,8 @@ void explodeHysteria2(std::string hysteria2, Proxy &node) {
void explodeQuan(const std::string &quan, Proxy &node) {
std::string strTemp, itemName, itemVal;
std::string group = V2RAY_DEFAULT_GROUP, ps, add, port, cipher, type = "none", id, aid = "0", net = "tcp", path, host, edge, tls;
std::string group = V2RAY_DEFAULT_GROUP, ps, add, port, cipher, type = "none", id, aid = "0", net = "tcp", path,
host, edge, tls;
string_array configs, vArray, headers;
strTemp = regReplace(quan, "(.*?) = (.*)", "$1,$2");
configs = split(strTemp, ",");
@@ -982,7 +1014,8 @@ void explodeQuan(const std::string &quan, Proxy &node) {
if (path.empty())
path = "/";
vmessConstruct(node, group, ps, add, port, type, id, aid, net, cipher, path, host, edge, tls, "",std::vector<std::string>{});
vmessConstruct(node, group, ps, add, port, type, id, aid, net, cipher, path, host, edge, tls, "",
std::vector<std::string>{});
}
}
@@ -1109,6 +1142,9 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
std::string obfsPassword; //hysteria2
std::string congestion_control, udp_relay_mode, token; // tuic
string_array dns_server;
std::vector<String> alpns;
String alpn2;
std::string fingerprint;
tribool udp, tfo, scv;
bool reduceRtt, disableSni; //tuic
std::vector<std::string> alpnList;
@@ -1141,12 +1177,15 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
break;
case "ws"_hash:
if (singleproxy["ws-opts"].IsDefined()) {
path = singleproxy["ws-opts"]["path"].IsDefined() ? safe_as<std::string>(
singleproxy["ws-opts"]["path"]) : "/";
path = singleproxy["ws-opts"]["path"].IsDefined()
? safe_as<std::string>(
singleproxy["ws-opts"]["path"])
: "/";
singleproxy["ws-opts"]["headers"]["Host"] >>= host;
singleproxy["ws-opts"]["headers"]["Edge"] >>= edge;
} else {
path = singleproxy["ws-path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-path"])
path = singleproxy["ws-path"].IsDefined()
? safe_as<std::string>(singleproxy["ws-path"])
: "/";
singleproxy["ws-headers"]["Host"] >>= host;
singleproxy["ws-headers"]["Edge"] >>= edge;
@@ -1318,7 +1357,9 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["uuid"] >>= id;
singleproxy["alterId"] >>= aid;
net = singleproxy["network"].IsDefined() ? safe_as<std::string>(singleproxy["network"]) : "tcp";
sni = singleproxy["sni"].IsDefined() ? safe_as<std::string>(singleproxy["sni"]) : safe_as<std::string>(
sni = singleproxy["sni"].IsDefined()
? safe_as<std::string>(singleproxy["sni"])
: safe_as<std::string>(
singleproxy["servername"]);
switch (hash_(net)) {
case "http"_hash:
@@ -1328,12 +1369,15 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
break;
case "ws"_hash:
if (singleproxy["ws-opts"].IsDefined()) {
path = singleproxy["ws-opts"]["path"].IsDefined() ? safe_as<std::string>(
singleproxy["ws-opts"]["path"]) : "/";
path = singleproxy["ws-opts"]["path"].IsDefined()
? safe_as<std::string>(
singleproxy["ws-opts"]["path"])
: "/";
singleproxy["ws-opts"]["headers"]["Host"] >>= host;
singleproxy["ws-opts"]["headers"]["Edge"] >>= edge;
} else {
path = singleproxy["ws-path"].IsDefined() ? safe_as<std::string>(singleproxy["ws-path"])
path = singleproxy["ws-path"].IsDefined()
? safe_as<std::string>(singleproxy["ws-path"])
: "/";
singleproxy["ws-headers"]["Host"] >>= host;
singleproxy["ws-headers"]["Edge"] >>= edge;
@@ -1349,11 +1393,14 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
singleproxy["grpc-opts"]["grpc-service-name"] >>= path;
edge.clear();
break;
default:
continue;
}
tls = safe_as<std::string>(singleproxy["tls"]) == "true" ? "tls" : "";
if (singleproxy["reality-opts"].IsDefined()) {
host = singleproxy["sni"].IsDefined() ? safe_as<std::string>(singleproxy["sni"])
host = singleproxy["sni"].IsDefined()
? safe_as<std::string>(singleproxy["sni"])
: safe_as<std::string>(singleproxy["servername"]);
printf("host:%s", host.c_str());
singleproxy["reality-opts"]["public-key"] >>= pbk;
@@ -1428,6 +1475,24 @@ void explodeClash(Node yamlnode, std::vector<Proxy> &nodes) {
tribool(), scv, reduceRtt, disableSni, request_timeout);
break;
case "anytls"_hash:
group = ANYTLS_DEFAULT_GROUP;
singleproxy["password"] >>= password;
singleproxy["sni"] >>= sni;
if (!singleproxy["alpn"].IsNull()&& singleproxy["alpn"].size() >= 1) {
singleproxy["alpn"][0] >>= alpn;
alpns.push_back(alpn);
if (singleproxy["alpn"].size() >= 2 && !singleproxy["alpn"][1].IsNull()) {
singleproxy["alpn"][1] >>= alpn2;
alpns.push_back(alpn2);
}
}
singleproxy["client-fingerprint"] >>= fingerprint;
anyTlSConstruct(node, ANYTLS_DEFAULT_GROUP, ps, port, password, server, alpns, fingerprint, sni,
udp,
tribool(), scv, tribool(),"",30,30,0);
break;
default:
continue;
}
@@ -1449,7 +1514,8 @@ void explodeStdVMess(std::string vmess, Proxy &node) {
remarks = urlDecode(vmess.substr(pos + 1));
vmess.erase(pos);
}
const std::string stdvmess_matcher = R"(^([a-z]+)(?:\+([a-z]+))?:([\da-f]{4}(?:[\da-f]{4}-){4}[\da-f]{12})-(\d+)@(.+):(\d+)(?:\/?\?(.*))?$)";
const std::string stdvmess_matcher =
R"(^([a-z]+)(?:\+([a-z]+))?:([\da-f]{4}(?:[\da-f]{4}-){4}[\da-f]{12})-(\d+)@(.+):(\d+)(?:\/?\?(.*))?$)";
if (regGetMatch(vmess, stdvmess_matcher, 8, 0, &net, &tls, &id, &aid, &add, &port, &addition))
return;
@@ -1479,7 +1545,8 @@ void explodeStdVMess(std::string vmess, Proxy &node) {
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, "auto", path, host, "", tls, "",alpnList);
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, "auto", path, host, "", tls, "",
alpnList);
}
@@ -1583,7 +1650,8 @@ void explodeStdVless(std::string vless, Proxy &node) {
remarks = urlDecode(vless.substr(pos + 1));
vless.erase(pos);
}
const std::string stdvless_matcher = R"(^([\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12})@\[?([\d\-a-zA-Z:.]+)\]?:(\d+)(?:\/?\?(.*))?$)";
const std::string stdvless_matcher =
R"(^([\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12})@\[?([\d\-a-zA-Z:.]+)\]?:(\d+)(?:\/?\?(.*))?$)";
if (regGetMatch(vless, stdvless_matcher, 5, 0, &id, &add, &port, &addition))
return;
@@ -1669,7 +1737,8 @@ void explodeShadowrocket(std::string rocket, Proxy &node) {
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "",alpnList);
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "",
alpnList);
}
void explodeKitsunebi(std::string kit, Proxy &node) {
@@ -1708,7 +1777,8 @@ void explodeKitsunebi(std::string kit, Proxy &node) {
if (!alpn.empty()) {
alpnList.push_back(alpn);
}
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "",alpnList);
vmessConstruct(node, V2RAY_DEFAULT_GROUP, remarks, add, port, type, id, aid, net, cipher, path, host, "", tls, "",
alpnList);
}
// peer = (public-key = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=, allowed-ips = "0.0.0.0/0, ::/0", endpoint = engage.cloudflareclient.com:2408, client-id = 139/184/125),(public-key = bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=, endpoint = engage.cloudflareclient.com:2408)
@@ -2996,8 +3066,7 @@ void explodeSub(std::string sub, std::vector<Proxy> &nodes) {
processed = true;
}
}
}
catch (std::exception &e) {
} catch (std::exception &e) {
//writeLog(0, e.what(), LOG_LEVEL_DEBUG);
//ignore
throw;
@@ -3022,8 +3091,7 @@ void explodeSub(std::string sub, std::vector<Proxy> &nodes) {
}
}
}
}
catch (std::exception &e) {
} catch (std::exception &e) {
writeLog(LOG_TYPE_ERROR, e.what(), LOG_LEVEL_ERROR);
//writeLog(0, e.what(), LOG_LEVEL_DEBUG);
//ignore
+6 -1
View File
@@ -76,7 +76,12 @@ void trojanConstruct(Proxy &node, const std::string &group, const std::string &r
const std::vector<std::string> &alpnList,
bool tlssecure, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool(),const std::string& underlying_proxy="");
void anyTlSConstruct(Proxy &node, const std::string &group, const std::string &remarks,
const std::string &port, const std::string &password,
const std::string &host, const std::vector<String> &AlpnList,
const std::string &fingerprint,
const std::string &sni, tribool udp = tribool(), tribool tfo = tribool(), tribool scv = tribool(),
tribool tls13 = tribool(),const std::string& underlying_proxy="",uint16_t idleSessionCheckInterval=30,uint16_t idleSessionTimeout=30,uint16_t minIdleSession=0);
void snellConstruct(Proxy &node, const std::string &group, const std::string &remarks, const std::string &server,
const std::string &port, const std::string &password, const std::string &obfs,
const std::string &host, uint16_t version = 0, tribool udp = tribool(), tribool tfo = tribool(),
+1 -1
View File
@@ -1,6 +1,6 @@
#ifndef VERSION_H_INCLUDED
#define VERSION_H_INCLUDED
#define VERSION "v0.9.8"
#define VERSION "v0.9.9"
#endif // VERSION_H_INCLUDED