From d350775eb30db920863abb5332ae947e04aaeb23 Mon Sep 17 00:00:00 2001 From: Amir Hossein Samiee Date: Mon, 11 May 2026 01:42:54 +0330 Subject: [PATCH] feat: add v2rayN.Bridge CLI for external tool integration Add a lightweight command-line interface project (v2rayN.Bridge) that exposes v2rayN's ServiceLib configuration parsing and generation capabilities to external scripts and tools. Features: - Parse share links to JSON (`to-json` command) - Batch-parse subscription content (`parse-sub` command) - Convert server profiles back to share URIs (`to-uri` command) - Self-contained single-file binary deployment Includes: - Program.cs with CLI command handling - Project file targeting .NET 10.0 with ServiceLib reference - Comprehensive README with build instructions and Python integration example - Solution file updates adding the new project and x64/x86 platform configurations --- v2rayN/v2rayN.Bridge/Program.cs | 104 ++++++++++++++++ v2rayN/v2rayN.Bridge/README.md | 139 ++++++++++++++++++++++ v2rayN/v2rayN.Bridge/v2rayN.Bridge.csproj | 12 ++ v2rayN/v2rayN.sln | 78 +++++++++++- 4 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 v2rayN/v2rayN.Bridge/Program.cs create mode 100644 v2rayN/v2rayN.Bridge/README.md create mode 100644 v2rayN/v2rayN.Bridge/v2rayN.Bridge.csproj diff --git a/v2rayN/v2rayN.Bridge/Program.cs b/v2rayN/v2rayN.Bridge/Program.cs new file mode 100644 index 00000000..36ce9d32 --- /dev/null +++ b/v2rayN/v2rayN.Bridge/Program.cs @@ -0,0 +1,104 @@ +using System.Text.Json; +using ServiceLib.Handler; +using ServiceLib.Handler.Fmt; +using ServiceLib.Models; + +if (args.Length < 2) +{ + Console.WriteLine("Usage: v2rayN.Bridge "); + Console.WriteLine("Commands: to-uri, parse-sub, to-json"); + return; +} + +string command = args[0]; +string argument = args[1]; + +switch (command) +{ + case "to-json": + ToJson(argument); + break; + case "parse-sub": + ParseSub(argument); + break; + case "to-uri": + ToUri(argument); + break; + default: + Console.WriteLine("Unknown command"); + break; +} + +static void ToJson(string shareLink) +{ + string msg; + var item = FmtHandler.ResolveConfig(shareLink, out msg); + + if (item != null) + { + var json = JsonSerializer.Serialize( + item, + new JsonSerializerOptions { WriteIndented = true } + ); + Console.WriteLine(json); + } + else + { + Console.WriteLine($"ERROR: {msg}"); + } +} + +static void ParseSub(string configText) +{ + // For parsing subscription content or config text + // Split by newlines and parse each line as a potential link + string msg; + var lines = configText.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries); + var items = new List(); + + foreach (var line in lines) + { + var trimmed = line.Trim(); + if (!string.IsNullOrEmpty(trimmed)) + { + var item = FmtHandler.ResolveConfig(trimmed, out msg); + if (item != null) + { + items.Add(item); + } + } + } + + var json = JsonSerializer.Serialize( + items, + new JsonSerializerOptions + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + } + ); + Console.WriteLine(json); +} + +static void ToUri(string jsonItem) +{ + try + { + var options = new JsonSerializerOptions(); + var item = JsonSerializer.Deserialize(jsonItem, options); + + if (item != null) + { + var uri = FmtHandler.GetShareUri(item); + Console.WriteLine(uri ?? "Failed to generate URI"); + } + else + { + Console.WriteLine("ERROR: Invalid ProfileItem JSON"); + } + } + catch (Exception ex) + { + Console.WriteLine($"ERROR: {ex.Message}"); + } +} diff --git a/v2rayN/v2rayN.Bridge/README.md b/v2rayN/v2rayN.Bridge/README.md new file mode 100644 index 00000000..6740ec62 --- /dev/null +++ b/v2rayN/v2rayN.Bridge/README.md @@ -0,0 +1,139 @@ +# v2rayN.Bridge + +A lightweight CLI that exposes [v2rayN](https://github.com/2dust/v2rayN)'s battle-tested +configuration parsing, generation, and (hopefully, in the future) other features, to external scripts, tools, and languages. + +## Why? + +v2rayN handles an enormous variety of proxy protocols, share links, and subscription +formats. Being wildly used by many users, either directly via the original client or indirectly via its numerous forks, +the popularity makes it sort of the "standard" for dealing with this context, be it for casual use or development. The +capability to use v2rayN's native, well-known, and widely-maintainend features directly gives you a seamless experience +for an extensive range of interests. +**v2rayN.Bridge aims to wrap the exact same `ServiceLib` code that v2rayN uses +internally and makes it available through a simple stdout interface.** + +## Vision + +`v2rayN.Bridge` is the first step toward **an API‑like interface for v2rayN**. +Eventually it should be able to: + +- Load and manipulate the local configuration database +- Trigger speed tests, ping checks, and subscription updates +- Manage routing rules, DNS settings, and core config generation +- Serve as the backend for headless deployments, web dashboards, or + cross‑platform GUI alternatives + +Each new command is a `case` statement added to `Program.cs`. +If you can call a `ServiceLib` method from C#, you can expose it here. + +## Current Features + +- Parse any v2rayN share link (VMess, VLESS, Trojan, Shadowsocks, Hysteria2, TUIC, …) +- Batch‑parse subscription content +- Convert a server profile back into a share URI +- Designed for piping: JSON in, JSON out +- Self‑contained single‑file binary – no .NET runtime required on the target machine + +## Build + +```bash +# From the repository root (the parent directory of this README file) +dotnet publish v2rayN.Bridge -c Release -r --self-contained true -p:PublishSingleFile=true +``` + +Replace `` with `win-x64`, `linux-x64`, `osx-x64`, or `osx-arm64` accordingly. + +## Usage + +### CLI commands + +``` +v2rayN.Bridge +``` + +| Command | Argument | Output | +| ----------- | ------------------------------- | ----------------------------------- | +| `to-json` | A share link (e.g. `vmess://…`) | JSON object (`ProfileItem`) | +| `parse-sub` | Subscription text (all URLs) | JSON array of `ProfileItem` objects | +| `to-uri` | JSON of a `ProfileItem` | The share link as a string | + +### Example: Python integration + +```python +# create test.py next to this README file +from pathlib import Path +import subprocess +import json + + +class Bridge: + def __init__(self, path_to_exec): + self.exec = path_to_exec + + def run(self, *cmdargs) -> str: + proc = subprocess.run([self.exec, *cmdargs], capture_output=True, text=True) + if proc.returncode: + raise RuntimeError(proc.stderr) + return proc.stdout + + def load_uri(self, uri: str): + json_str = self.run("to-json", uri) + return json.loads(json_str) + + def dump_uri(self, config: dict): + return self.run("to-uri", json.dumps(config)) + + def extract_configs(self, sub_content): + return json.loads(self.run("parse-sub", sub_content)) + + +sub_content = """ +this is an example of some text content, probably +a config subscription's response, potentially +including config URIs supported by v2rayN; +such as: + +ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTp1MTdUM0J2cFlhYWl1VzJj@api.namasha.co:443 +vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIiIsDQogICJhZGQiOiAiIiwNCiAgInBvcnQiOiAiMCIsDQogICJpZCI6ICIiLA0KICAiYWlkIjogIjAiLA0KICAic2N5IjogIiIsDQogICJuZXQiOiAidGNwIiwNCiAgInRscyI6ICIiLA0KICAiYWxwbiI6ICIiLA0KICAiaW5zZWN1cmUiOiAiMCINCn0= + +and also pieces of plain text as well (obviously!) +""" + +# individual URIs +uris = [ + "vless://7f8f9f5d-d75e-4dd4-b921-c63b56d50865@185.143.234.25:2052?encryption=none&security=none&type=ws&host=tr-st3.ge9.ir&path=%2Fpath#%C9%A2%E1%B4%87%CA%80%E1%B4%8D%E1%B4%80%C9%B4%20%C2%B9%20%7C%20%F0%9F%87%A9%F0%9F%87%AA", + "trojan://J6aoK74aaYaReDimz0zvQw@dateandusage.a:8443?type=tcp&headerType=none", +] + +config = {"log": {"loglevel": "debug"}, "dns": {"hosts": {"dns.google": ["8.8.8.8", "8.8.4.4", "2001:4860:4860::8888", "2001:4860:4860::8844"], "cloudflare-dns.com": ["104.16.249.249", "104.16.248.249", "2606:4700::6810:f8f9", "2606:4700::6810:f9f9"]}, "servers": [{"address": "119.29.29.29", "domains": ["geosite:private", "geosite:cn"], "skipFallback": True, "tag": "direct-dns-2"}, "https://cloudflare-dns.com/dns-query"], "tag": "dns-module"}, "inbounds": [{"tag": "socks", "port": 10808, "listen": "127.0.0.1", "protocol": "mixed", "sniffing": {"enabled": True, "destOverride": ["http", "tls", "fakedns+others", "fakedns", "quic"], "routeOnly": False}, "settings": {"auth": "noauth", "udp": True, "allowTransparent": False}}], "outbounds": [{"tag": "proxy", "protocol": "vless", "settings": {"vnext": [{"address": "185.143.233.200", "port": 2082, "users": [{"id": "1691eb05-2fce-4ee1-b32b-c9b4e1647992", "email": "t@t.tt", "security": "auto", "encryption": "none"} ]} ] }, "streamSettings": {"network": "ws", "wsSettings": {"path": "/", "host": "nima.hayalco.ir", "headers": {}}}, "mux": {"enabled": True, "concurrency": 8}}], "routing": {"domainStrategy": "AsIs", "rules": [{"type": "field", "inboundTag": ["api"], "outboundTag": "api"}]}, "metrics": {"tag": "api"}, "policy": {"system": {"statsOutboundUplink": True, "statsOutboundDownlink": True}}, "stats": {}} + + +# after build, walk through the following path and modify in +# cases of difference; based on your OS, dotnet version, etc. +exec = Path(__file__).parent.joinpath("bin", "Release", "net10.0", "win-x64", "v2rayN.Bridge.exe") +assert exec.exists() +bridge = Bridge(exec) + +if __name__ == "__main__": + extracted = bridge.extract_configs(sub_content) + print("\nextracted configs from sub:", extracted) + + for uri in uris: + loaded = bridge.load_uri(uri) + print("\nloaded uri:", loaded) + + dumped = bridge.dump_uri(config) + print("\ndumped uri:", dumped) +``` + +## Contributing + +1. Fork v2rayN, and add your command to `v2rayN.Bridge/Program.cs`. +2. Ensure JSON output matches the `ServiceLib` model properties (PascalCase). +3. Test with your favourite scripting language. +4. Open a PR and submit. + +## License + +Same as v2rayN – [GPL-3.0](https://github.com/2dust/v2rayN/blob/master/LICENSE). diff --git a/v2rayN/v2rayN.Bridge/v2rayN.Bridge.csproj b/v2rayN/v2rayN.Bridge/v2rayN.Bridge.csproj new file mode 100644 index 00000000..9615a2ba --- /dev/null +++ b/v2rayN/v2rayN.Bridge/v2rayN.Bridge.csproj @@ -0,0 +1,12 @@ + + + + + + + Exe + net10.0 + enable + enable + + diff --git a/v2rayN/v2rayN.sln b/v2rayN/v2rayN.sln index 944ec2ac..3eab30d4 100644 --- a/v2rayN/v2rayN.sln +++ b/v2rayN/v2rayN.sln @@ -1,7 +1,7 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.5.11709.299 stable +VisualStudioVersion = 18.5.11709.299 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN", "v2rayN\v2rayN.csproj", "{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}" EndProject @@ -36,40 +36,114 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLib.Tests", "Service EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLib.UdpTest", "ServiceLib.UdpTest\ServiceLib.UdpTest.csproj", "{CE9D9298-0289-4718-2522-B236489F2912}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "v2rayN.Bridge", "v2rayN.Bridge\v2rayN.Bridge.csproj", "{008E6D04-F573-42FE-9299-6C3500F4DE7B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|x64.ActiveCfg = Debug|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|x64.Build.0 = Debug|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|x86.ActiveCfg = Debug|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|x86.Build.0 = Debug|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.Build.0 = Release|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|x64.ActiveCfg = Release|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|x64.Build.0 = Release|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|x86.ActiveCfg = Release|Any CPU + {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|x86.Build.0 = Release|Any CPU {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|x64.ActiveCfg = Debug|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|x64.Build.0 = Debug|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|x86.ActiveCfg = Debug|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|x86.Build.0 = Debug|Any CPU {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|Any CPU.ActiveCfg = Release|Any CPU {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|Any CPU.Build.0 = Release|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|x64.ActiveCfg = Release|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|x64.Build.0 = Release|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|x86.ActiveCfg = Release|Any CPU + {1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|x86.Build.0 = Release|Any CPU {5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|x64.ActiveCfg = Debug|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|x64.Build.0 = Debug|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|x86.ActiveCfg = Debug|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|x86.Build.0 = Debug|Any CPU {5D16541A-F971-4C17-9315-BB8955E3F984}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D16541A-F971-4C17-9315-BB8955E3F984}.Release|Any CPU.Build.0 = Release|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Release|x64.ActiveCfg = Release|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Release|x64.Build.0 = Release|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Release|x86.ActiveCfg = Release|Any CPU + {5D16541A-F971-4C17-9315-BB8955E3F984}.Release|x86.Build.0 = Release|Any CPU {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|x64.ActiveCfg = Debug|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|x64.Build.0 = Debug|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|x86.ActiveCfg = Debug|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|x86.Build.0 = Debug|Any CPU {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.ActiveCfg = Release|Any CPU {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.Build.0 = Release|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|x64.ActiveCfg = Release|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|x64.Build.0 = Release|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|x86.ActiveCfg = Release|Any CPU + {47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|x86.Build.0 = Release|Any CPU {CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|x64.ActiveCfg = Debug|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|x64.Build.0 = Debug|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|x86.ActiveCfg = Debug|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|x86.Build.0 = Debug|Any CPU {CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.Build.0 = Release|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Release|x64.ActiveCfg = Release|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Release|x64.Build.0 = Release|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Release|x86.ActiveCfg = Release|Any CPU + {CB3DE54F-3A26-AE02-1299-311132C32156}.Release|x86.Build.0 = Release|Any CPU {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|x64.ActiveCfg = Debug|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|x64.Build.0 = Debug|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|x86.ActiveCfg = Debug|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Debug|x86.Build.0 = Debug|Any CPU {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|Any CPU.Build.0 = Release|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|x64.ActiveCfg = Release|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|x64.Build.0 = Release|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|x86.ActiveCfg = Release|Any CPU + {E0B6C5C7-ED48-42EB-947A-877779E9F555}.Release|x86.Build.0 = Release|Any CPU {CE9D9298-0289-4718-2522-B236489F2912}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CE9D9298-0289-4718-2522-B236489F2912}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Debug|x64.ActiveCfg = Debug|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Debug|x64.Build.0 = Debug|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Debug|x86.ActiveCfg = Debug|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Debug|x86.Build.0 = Debug|Any CPU {CE9D9298-0289-4718-2522-B236489F2912}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE9D9298-0289-4718-2522-B236489F2912}.Release|Any CPU.Build.0 = Release|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Release|x64.ActiveCfg = Release|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Release|x64.Build.0 = Release|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Release|x86.ActiveCfg = Release|Any CPU + {CE9D9298-0289-4718-2522-B236489F2912}.Release|x86.Build.0 = Release|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Debug|x64.ActiveCfg = Debug|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Debug|x64.Build.0 = Debug|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Debug|x86.ActiveCfg = Debug|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Debug|x86.Build.0 = Debug|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Release|Any CPU.Build.0 = Release|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Release|x64.ActiveCfg = Release|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Release|x64.Build.0 = Release|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Release|x86.ActiveCfg = Release|Any CPU + {008E6D04-F573-42FE-9299-6C3500F4DE7B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE