diff options
| -rw-r--r-- | Evaluate/.gitignore | 10 | ||||
| -rw-r--r-- | Evaluate/.swp | bin | 0 -> 12288 bytes | |||
| -rw-r--r-- | Evaluate/README.md | 18 | ||||
| -rw-r--r-- | Evaluate/evaluate.py | 54 | ||||
| -rw-r--r-- | Evaluate/setup.ps1 | 18 | ||||
| -rw-r--r-- | Whisper/MF/AudioBuffer.h | 1 | ||||
| -rw-r--r-- | Whisper/Whisper/ContextImpl.cpp | 2 | ||||
| -rw-r--r-- | Whisper/WhisperCLI/WhisperCLI.cpp | 196 | ||||
| -rw-r--r-- | Whisper/WhisperCLI/WhisperCLI.vcxproj | 143 | ||||
| -rw-r--r-- | Whisper/WhisperCLI/WhisperCLI.vcxproj.filters | 22 | ||||
| -rw-r--r-- | WhisperCpp.sln | 65 |
11 files changed, 525 insertions, 4 deletions
diff --git a/Evaluate/.gitignore b/Evaluate/.gitignore new file mode 100644 index 0000000..c6d2776 --- /dev/null +++ b/Evaluate/.gitignore @@ -0,0 +1,10 @@ +# models +*.bin +# audio +*.mp3 +*.wav +# reference transcripts +*.txt +# binaries +*.exe +*.dll diff --git a/Evaluate/.swp b/Evaluate/.swp Binary files differnew file mode 100644 index 0000000..c1bc460 --- /dev/null +++ b/Evaluate/.swp diff --git a/Evaluate/README.md b/Evaluate/README.md new file mode 100644 index 0000000..91038f6 --- /dev/null +++ b/Evaluate/README.md @@ -0,0 +1,18 @@ +## Evaluation tool + +This directory holds code to evaluate the accuracy of transcriptions. + +Example usage (in Powershell): +``` +python3 -m pip install -r requirements.txt +python3 evaluate.py reference_transcript.txt +./setup.ps1 +./WhisperCLI.exe \ + --audio_path *.mp3 \ + --model_path *.bin +``` + +* setup.ps1: Downloads whisper checkpoints and audio from librivox. Copies + WhisperCLI.exe to CWD. +* evaluate.py: Computes Levenshtein distance between generated transcription + and "correct" transcription. diff --git a/Evaluate/evaluate.py b/Evaluate/evaluate.py new file mode 100644 index 0000000..5e8c85d --- /dev/null +++ b/Evaluate/evaluate.py @@ -0,0 +1,54 @@ +import argparse +import editdistance +import jiwer +import re +import subprocess +import sys +import time + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("reference_path", type=str, help="Path to reference transcript") + parser.add_argument("audio_path", type=str, help="Path to audio file to transcribe") + parser.add_argument("model_path", type=str, help="Path to Whisper model to use") + parser.add_argument("decode_method", type=str, help="Decoding method. Either 'greedy' or 'beam'") + args = parser.parse_args() + + cmd = "./WhisperCLI.exe" + cmd_args = [ + "--audio_path", args.audio_path, + "--model_path", args.model_path, + "--decode_method", args.decode_method, + ] + + t0 = time.time() + result = subprocess.run([cmd] + cmd_args, stdout=subprocess.PIPE) + t1 = time.time() + + if result.returncode != 0: + print(f"Failed to transcribe: cmd returned {result.returncode}", + file=sys.stderr) + + test_transcript = result.stdout.decode("utf-8") + with open(args.reference_path, "r") as f: + ref_transcript = f.read() + + dist = editdistance.eval(ref_transcript, test_transcript) + wer_transform = jiwer.Compose([ + jiwer.ToLowerCase(), + jiwer.RemoveWhiteSpace(replace_by_space=True), + jiwer.RemoveMultipleSpaces(), + jiwer.RemovePunctuation(), + jiwer.ReduceToListOfListOfWords(word_delimiter=" "), + ]) + wer = jiwer.wer( + ref_transcript, + test_transcript, + truth_transform=wer_transform, + hypothesis_transform=wer_transform) + + print(f"Duration: {t1 - t0}") + print(f"Levenshtein distance: {dist}") + print(f"Word error rate: {wer}") + print(f"Transcript: {test_transcript}") + diff --git a/Evaluate/setup.ps1 b/Evaluate/setup.ps1 new file mode 100644 index 0000000..95e2487 --- /dev/null +++ b/Evaluate/setup.ps1 @@ -0,0 +1,18 @@ + +cp ../x64/Debug/WhisperCLI.exe . +cp ../x64/Debug/Whisper.dll . + +$MODEL_URL = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin" +$MODEL_FILE = $(Split-Path -Path $MODEL_URL -Leaf) +if (-Not (Test-Path $MODEL_FILE)) { + echo "Fetch model" + Invoke-WebRequest $MODEL_URL -OutFile $MODEL_FILE +} + +#$AUDIO_URL = "https://www.archive.org/download/usconstitution_1610_librivox/constitution_01_unitedstates_64kb.mp3" +$AUDIO_URL = "https://www.archive.org/download/usconstitution_1610_librivox/constitution_02_unitedstates_128kb.mp3" +$AUDIO_FILE = $(Split-Path -Path $AUDIO_URL -Leaf) +if (-Not (Test-Path $AUDIO_FILE)) { + echo "Fetch audio" + Invoke-WebRequest $AUDIO_URL -OutFile $AUDIO_FILE +} diff --git a/Whisper/MF/AudioBuffer.h b/Whisper/MF/AudioBuffer.h index 63c4a8c..11b5ead 100644 --- a/Whisper/MF/AudioBuffer.h +++ b/Whisper/MF/AudioBuffer.h @@ -47,7 +47,6 @@ namespace Whisper void dropFirst(size_t len) { - assert(len <= mono.size()); if (len >= mono.size()) { mono.clear(); return; diff --git a/Whisper/Whisper/ContextImpl.cpp b/Whisper/Whisper/ContextImpl.cpp index 4e384ca..22347cf 100644 --- a/Whisper/Whisper/ContextImpl.cpp +++ b/Whisper/Whisper/ContextImpl.cpp @@ -837,12 +837,10 @@ HRESULT COMLIGHTCALL ContextImpl::runFullImpl( const sFullParams& params, const // in ascending order, we're always copying from old or // identical data. for (int nth_beam = 0; nth_beam < ctx_.size(); nth_beam++) { -#if 0 // Trivial optimization: only copy if beams differ. if (nth_beam == best_beams_and_tokens[nth_beam].first) { continue; } -#endif ctx_[nth_beam] = ctx_[best_beams_and_tokens[nth_beam].first]; } diff --git a/Whisper/WhisperCLI/WhisperCLI.cpp b/Whisper/WhisperCLI/WhisperCLI.cpp new file mode 100644 index 0000000..af0a59f --- /dev/null +++ b/Whisper/WhisperCLI/WhisperCLI.cpp @@ -0,0 +1,196 @@ +#define WIN32_LEAN_AND_MEAN + +#include <Unknwn.h> +#include <windows.h> + +#include "Whisper/API/whisperWindows.h" + +#include <iostream> +#include <locale> +#include <set> +#include <string> +#include <string_view> + +using std::cout; +using std::cerr; +using std::endl; +using namespace Whisper; + +struct Config { + std::wstring audio_path = L"input.wav"; + std::wstring model_path = L"model.bin"; + eSamplingStrategy decode_method = eSamplingStrategy::BeamSearch; +}; + +bool hasArg(int argc, int shift, char* arg) { + if (shift + 1 >= argc) { + cerr << "Error: " << arg << " is missing argument" << endl; + return false; + } + return true; +} + +std::wstring cstrToWstr(char* c_str) { + int length = MultiByteToWideChar(CP_UTF8, 0, c_str, -1, NULL, 0); + std::wstring result(length, 0); + MultiByteToWideChar(CP_UTF8, 0, c_str, -1, result.data(), result.size()); + return result; +} + + +bool parseArgs(int argc, char* argv[], Config& c) { + int shift = 1; + while (shift < argc) { + if (std::string_view(argv[shift]) == "--audio_path") { + if (!hasArg(argc, shift, argv[shift])) { + return false; + } + c.audio_path = cstrToWstr(argv[shift + 1]); + shift += 2; + continue; + } + if (std::string_view(argv[shift]) == "--model_path") { + if (!hasArg(argc, shift, argv[shift])) { + return false; + } + c.model_path = cstrToWstr(argv[shift + 1]); + shift += 2; + continue; + } + if (std::string_view(argv[shift]) == "--decode_method") { + if (!hasArg(argc, shift, argv[shift])) { + return false; + } + std::string_view decode_method(argv[shift + 1]); + if (decode_method == "greedy") { + cerr << "Using greedy decode " << endl; + c.decode_method = eSamplingStrategy::Greedy; + } + else if (decode_method == "beam") { + cerr << "Using beam decode " << endl; + c.decode_method = eSamplingStrategy::BeamSearch; + } + else { + cerr << "Unsupported decode method: " << decode_method << endl; + return false; + } + shift += 2; + continue; + } + cerr << "Unrecognized argument: \"" << argv[shift] << '"' << endl; + return false; + } + return true; +} + +int main(int argc, char* argv[]) +{ + Config c; + if (!parseArgs(argc, argv, c)) { + cerr << "Failed to parse args"; + return 1; + } + + iMediaFoundation* f = nullptr; + HRESULT err = initMediaFoundation(&f); + if (FAILED(err)) { + cerr << "Failed to init media foundation: " << err << endl; + return 1; + } + + Whisper::iAudioBuffer* buffer = nullptr; + err = f->loadAudioFile(c.audio_path.c_str(), /*stereo=*/false, &buffer); + if (FAILED(err)) { + cerr << "Failed to load audio file 'input.wav': " << err << endl; + return 1; + } + + Whisper::iModel* model = nullptr; + err = Whisper::loadModel(c.model_path.c_str(), eModelImplementation::GPU, /*flags=*/0, /*callbacks=*/nullptr, &model); + if (FAILED(err)) { + cerr << "Failed to open model 'model.bin': " << err << endl; + return 1; + } + + Whisper::iContext* context = nullptr; + err = model->createContext(&context); + if (FAILED(err)) { + cerr << "Failed to create context: " << err << endl; + return 1; + } + + Whisper::sFullParams wparams{}; + context->fullDefaultParams(c.decode_method, &wparams); + if (c.decode_method == eSamplingStrategy::BeamSearch) { + wparams.beam_search.beam_width = 5; + wparams.beam_search.n_best = 5; + } + wparams.language = Whisper::makeLanguageKey("en"); + wparams.n_max_text_ctx = 100; + + err = context->runFull(wparams, buffer); + if (FAILED(err)) { + cerr << "Failed to transcribe: " << err << endl; + return 1; + } + + Whisper::iTranscribeResult* result = nullptr; + err = context->getResults(eResultFlags::Tokens, &result); + if (FAILED(err)) { + cerr << "Failed to get transcription results: " << err << endl; + return 1; + } + + std::set<int> special_tokens; + { + Whisper::SpecialTokens st; + err = model->getSpecialTokens(st); + if (FAILED(err)) { + cerr << "Failed to get special tokens: " << err << endl; + } + special_tokens.insert(st.Not); + special_tokens.insert(st.PreviousWord); + special_tokens.insert(st.SentenceStart); + special_tokens.insert(st.TaskTranscribe); + special_tokens.insert(st.TaskTranslate); + special_tokens.insert(st.TranscriptionBegin); + special_tokens.insert(st.TranscriptionEnd); + special_tokens.insert(st.TranscriptionStart); + } + + sTranscribeLength length; + err = result->getSize(length); + if (FAILED(err)) { + cerr << "Failed to get transcription length: " << err << endl; + } + auto* segments = result->getSegments(); + auto* tokens = result->getTokens(); + bool is_metadata = false; + for (int i = 0; i < length.countSegments; i++) { + auto& segment = segments[i]; + for (int j = 0; j < segment.countTokens; j++) { + const sToken& tok = tokens[segment.firstToken + j]; + if (special_tokens.contains(tok.id)) { + continue; + } + std::string_view tok_str(tok.text); + if (tok_str.starts_with("[") || + tok_str.starts_with(" [")) { + if (tok_str.ends_with("]")) { + continue; + } + is_metadata = true; + continue; + } + if (is_metadata && + tok_str.ends_with("]")) { + is_metadata = false; + continue; + } + cout << tok.text; + } + } + cout << endl; + + return 0; +}
\ No newline at end of file diff --git a/Whisper/WhisperCLI/WhisperCLI.vcxproj b/Whisper/WhisperCLI/WhisperCLI.vcxproj new file mode 100644 index 0000000..8295eee --- /dev/null +++ b/Whisper/WhisperCLI/WhisperCLI.vcxproj @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>16.0</VCProjectVersion> + <Keyword>Win32Proj</Keyword> + <ProjectGuid>{b561d29f-be1d-4a4f-acfc-4d075cbc9108}</ProjectGuid> + <RootNamespace>WhisperCLI</RootNamespace> + <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v143</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v143</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v143</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v143</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir);</IncludePath> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <LanguageStandard>stdcpp20</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies);$(OutDir)Whisper.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="WhisperCLI.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Whisper/WhisperCLI/WhisperCLI.vcxproj.filters b/Whisper/WhisperCLI/WhisperCLI.vcxproj.filters new file mode 100644 index 0000000..34bd24e --- /dev/null +++ b/Whisper/WhisperCLI/WhisperCLI.vcxproj.filters @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="WhisperCLI.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/WhisperCpp.sln b/WhisperCpp.sln index 84d9a2f..9f50842 100644 --- a/WhisperCpp.sln +++ b/WhisperCpp.sln @@ -43,60 +43,123 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Readme.md = Readme.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerfSummary", "Tools\PerfSummary\PerfSummary.csproj", "{8AC301F0-FEC9-4F26-83DD-DB32969CD510}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfSummary", "Tools\PerfSummary\PerfSummary.csproj", "{8AC301F0-FEC9-4F26-83DD-DB32969CD510}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WhisperCLI", "Whisper\WhisperCLI\WhisperCLI.vcxproj", "{B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}" + ProjectSection(ProjectDependencies) = postProject + {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71} = {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x64.ActiveCfg = Debug|x64 {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x64.Build.0 = Debug|x64 + {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x86.ActiveCfg = Debug|x64 + {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Debug|x86.Build.0 = Debug|x64 {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x64.ActiveCfg = Release|x64 {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x64.Build.0 = Release|x64 + {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x86.ActiveCfg = Release|x64 + {52F486E7-830C-45D8-BE47-E76B5AAB2772}.Release|x86.Build.0 = Release|x64 {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x64.ActiveCfg = Debug|x64 {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x64.Build.0 = Debug|x64 + {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x86.ActiveCfg = Debug|x64 + {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Debug|x86.Build.0 = Debug|x64 {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x64.ActiveCfg = Release|x64 {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x64.Build.0 = Release|x64 + {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x86.ActiveCfg = Release|x64 + {701DF8C8-E4A5-43EC-9C6B-747BBF4D8E71}.Release|x86.Build.0 = Release|x64 {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x64.ActiveCfg = Debug|x64 {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x64.Build.0 = Debug|x64 + {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x86.ActiveCfg = Debug|x64 + {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Debug|x86.Build.0 = Debug|x64 {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x64.ActiveCfg = Release|x64 {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x64.Build.0 = Release|x64 + {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x86.ActiveCfg = Release|x64 + {1C39D386-96D0-47A1-BBFA-68BBDB24439C}.Release|x86.Build.0 = Release|x64 {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x64.ActiveCfg = Debug|Any CPU {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x64.Build.0 = Debug|Any CPU + {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x86.ActiveCfg = Debug|Any CPU + {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Debug|x86.Build.0 = Debug|Any CPU {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x64.ActiveCfg = Release|Any CPU {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x64.Build.0 = Release|Any CPU + {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x86.ActiveCfg = Release|Any CPU + {F213558F-FEA2-4F66-A07F-69727E9EC81D}.Release|x86.Build.0 = Release|Any CPU {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x64.ActiveCfg = Debug|x64 {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x64.Build.0 = Debug|x64 + {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x86.ActiveCfg = Debug|x64 + {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Debug|x86.Build.0 = Debug|x64 {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Release|x64.ActiveCfg = Release|x64 + {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Release|x86.ActiveCfg = Release|x64 + {0533B86C-D0E8-4190-9717-7DBD9EC8C11F}.Release|x86.Build.0 = Release|x64 {596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x64.ActiveCfg = Debug|x64 {596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x64.Build.0 = Debug|x64 + {596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x86.ActiveCfg = Debug|x64 + {596F9770-9AEB-49D3-86CA-4200197DF12B}.Debug|x86.Build.0 = Debug|x64 {596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x64.ActiveCfg = Release|x64 {596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x64.Build.0 = Release|x64 + {596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x86.ActiveCfg = Release|x64 + {596F9770-9AEB-49D3-86CA-4200197DF12B}.Release|x86.Build.0 = Release|x64 {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x64.ActiveCfg = Debug|Any CPU {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x64.Build.0 = Debug|Any CPU + {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x86.ActiveCfg = Debug|Any CPU + {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Debug|x86.Build.0 = Debug|Any CPU {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x64.ActiveCfg = Release|Any CPU {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x64.Build.0 = Release|Any CPU + {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x86.ActiveCfg = Release|Any CPU + {4E85005E-D2C7-4B28-A5F2-8BC92DAF6BA2}.Release|x86.Build.0 = Release|Any CPU {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x64.ActiveCfg = Debug|x64 {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x64.Build.0 = Debug|x64 + {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x86.ActiveCfg = Debug|x64 + {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Debug|x86.Build.0 = Debug|x64 {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x64.ActiveCfg = Release|x64 {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x64.Build.0 = Release|x64 + {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x86.ActiveCfg = Release|x64 + {4CCA7042-EB15-4F7A-B77B-5CAFD2DF47B2}.Release|x86.Build.0 = Release|x64 {A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x64.ActiveCfg = Debug|x64 {A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x64.Build.0 = Debug|x64 + {A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x86.ActiveCfg = Debug|x64 + {A49305C0-7022-45A6-89B4-4BD33138C98A}.Debug|x86.Build.0 = Debug|x64 {A49305C0-7022-45A6-89B4-4BD33138C98A}.Release|x64.ActiveCfg = Release|x64 + {A49305C0-7022-45A6-89B4-4BD33138C98A}.Release|x86.ActiveCfg = Release|x64 + {A49305C0-7022-45A6-89B4-4BD33138C98A}.Release|x86.Build.0 = Release|x64 {8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x64.ActiveCfg = Debug|x64 {8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x64.Build.0 = Debug|x64 + {8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x86.ActiveCfg = Debug|x64 + {8478A77C-D851-4C63-9511-1770CC82D33E}.Debug|x86.Build.0 = Debug|x64 {8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x64.ActiveCfg = Release|x64 {8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x64.Build.0 = Release|x64 + {8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x86.ActiveCfg = Release|x64 + {8478A77C-D851-4C63-9511-1770CC82D33E}.Release|x86.Build.0 = Release|x64 {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x64.ActiveCfg = Debug|x64 {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x64.Build.0 = Debug|x64 + {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x86.ActiveCfg = Debug|x64 + {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Debug|x86.Build.0 = Debug|x64 {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x64.ActiveCfg = Release|x64 {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x64.Build.0 = Release|x64 + {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x86.ActiveCfg = Release|x64 + {CD9E49F0-75A3-4F91-AC71-336109EE39C6}.Release|x86.Build.0 = Release|x64 {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x64.ActiveCfg = Debug|Any CPU {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x64.Build.0 = Debug|Any CPU + {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x86.ActiveCfg = Debug|Any CPU + {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Debug|x86.Build.0 = Debug|Any CPU {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x64.ActiveCfg = Release|Any CPU {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x64.Build.0 = Release|Any CPU + {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x86.ActiveCfg = Release|Any CPU + {8AC301F0-FEC9-4F26-83DD-DB32969CD510}.Release|x86.Build.0 = Release|Any CPU + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x64.ActiveCfg = Debug|x64 + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x64.Build.0 = Debug|x64 + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x86.ActiveCfg = Debug|Win32 + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Debug|x86.Build.0 = Debug|Win32 + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x64.ActiveCfg = Release|x64 + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x64.Build.0 = Release|x64 + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x86.ActiveCfg = Release|Win32 + {B561D29F-BE1D-4A4F-ACFC-4D075CBC9108}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE |
